From 4276ebb67dd23ca386bbfb7f0192d411be3e7603 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 25 Jun 2018 11:33:20 -0700 Subject: [PATCH 001/587] re-brand to amplify --- packages/amplify-category-api/commands/api.js | 6 + .../extensions/api-extension.js | 6 + packages/amplify-category-api/package.json | 15 + .../amplify-category-api/templates/api.ejs | 382 ++++++++++++++++++ 4 files changed, 409 insertions(+) create mode 100755 packages/amplify-category-api/commands/api.js create mode 100755 packages/amplify-category-api/extensions/api-extension.js create mode 100755 packages/amplify-category-api/package.json create mode 100755 packages/amplify-category-api/templates/api.ejs diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js new file mode 100755 index 0000000000..a991e6513b --- /dev/null +++ b/packages/amplify-category-api/commands/api.js @@ -0,0 +1,6 @@ +module.exports = { + name: 'api', + run: async ({ print, api }) => { + print.info(await api()) + }, +} \ No newline at end of file diff --git a/packages/amplify-category-api/extensions/api-extension.js b/packages/amplify-category-api/extensions/api-extension.js new file mode 100755 index 0000000000..5c8c3d5c83 --- /dev/null +++ b/packages/amplify-category-api/extensions/api-extension.js @@ -0,0 +1,6 @@ +module.exports = toolbox => { + toolbox.api = async () => { + let params = toolbox.parameters + console.log(params) + } +} \ No newline at end of file diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json new file mode 100755 index 0000000000..b533934033 --- /dev/null +++ b/packages/amplify-category-api/package.json @@ -0,0 +1,15 @@ +{ + "name": "amplify-category-api", + "version": "0.1.0", + "main": "index.js", + "license": "apache-2.0", + "defaults": { + "apiName": "amplify-api", + "apiType": [ + "regional", + "edge" + ], + "apiStageName": "prod", + "apiCors": "*" + } +} diff --git a/packages/amplify-category-api/templates/api.ejs b/packages/amplify-category-api/templates/api.ejs new file mode 100755 index 0000000000..1206116e91 --- /dev/null +++ b/packages/amplify-category-api/templates/api.ejs @@ -0,0 +1,382 @@ +AWSTemplateFormatVersion: '2010-09-09' +Transform: AWS::Serverless-2016-10-31 +Description: "AWS Amplify API" +Parameters: + LambdaFunctionName: + Type: String + Default: "EmberServerlessFunction" + Description: "AWS Amplify created function" + AppClientName: + Type: String + Default: "EmberServerlessWebClient" + Description: "Cognito user pools app client name" +Resources: + ApiGatewayApi: + Type: AWS::Serverless::Api + DependsOn: CognitoUserPool + Properties: + StageName: Prod + DefinitionBody: + swagger: "2.0" + info: + version: "2017-02-24T04:09:00Z" + title: "EmberServerlessAPI" + basePath: "/Prod" + schemes: + - "https" + paths: + "/docs": + get: + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "user" + in: "header" + required: false + type: "string" + - name: "id" + in: "query" + required: false + type: "string" + responses: + "200": + description: "200 response" + schema: + $ref: "#/definitions/Empty" + headers: + Access-Control-Allow-Origin: + type: "string" + security: + - EmberServerless: [] + x-amazon-apigateway-integration: + responses: + default: + statusCode: "200" + responseParameters: + method.response.header.Access-Control-Allow-Origin: "'*'" + requestTemplates: + application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ + ## This template will pass through all parameters including path, querystring,\ + \ header, stage variables, and context through to the integration endpoint\ + \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ + \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ + \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ + \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ + \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ + #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ + \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ + \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ + \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ + ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ + \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ + ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ + ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ + \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ + \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ + \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ + \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ + \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ + source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ + ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ + \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ + ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ + \ : \"$context.resourcePath\"\n }\n}\n" + uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] + passthroughBehavior: "when_no_templates" + httpMethod: "POST" + contentHandling: "CONVERT_TO_TEXT" + type: "aws" + post: + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "user" + in: "header" + required: false + type: "string" + responses: + "200": + description: "200 response" + schema: + $ref: "#/definitions/Empty" + headers: + Access-Control-Allow-Origin: + type: "string" + security: + - EmberServerless: [] + x-amazon-apigateway-integration: + responses: + default: + statusCode: "200" + responseParameters: + method.response.header.Access-Control-Allow-Origin: "'*'" + requestTemplates: + application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ + ## This template will pass through all parameters including path, querystring,\ + \ header, stage variables, and context through to the integration endpoint\ + \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ + \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ + \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ + \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ + \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ + #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ + \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ + \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ + \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ + ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ + \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ + ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ + ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ + \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ + \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ + \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ + \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ + \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ + source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ + ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ + \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ + ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ + \ : \"$context.resourcePath\"\n }\n}\n" + uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] + passthroughBehavior: "when_no_templates" + httpMethod: "POST" + contentHandling: "CONVERT_TO_TEXT" + type: "aws" + delete: + consumes: + - "application/json" + produces: + - "application/json" + parameters: + - name: "user" + in: "header" + required: false + type: "string" + responses: + "200": + description: "200 response" + schema: + $ref: "#/definitions/Empty" + headers: + Access-Control-Allow-Origin: + type: "string" + security: + - EmberServerless: [] + x-amazon-apigateway-integration: + responses: + default: + statusCode: "200" + responseParameters: + method.response.header.Access-Control-Allow-Origin: "'*'" + requestTemplates: + application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ + ## This template will pass through all parameters including path, querystring,\ + \ header, stage variables, and context through to the integration endpoint\ + \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ + \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ + \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ + \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ + \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ + #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ + \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ + \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ + \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ + ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ + \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ + ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ + ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ + \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ + \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ + \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ + \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ + \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ + source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ + ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ + \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ + ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ + \ : \"$context.resourcePath\"\n }\n}\n" + uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] + passthroughBehavior: "when_no_templates" + httpMethod: "POST" + contentHandling: "CONVERT_TO_TEXT" + type: "aws" + 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: "'GET,OPTIONS,POST,PUT,DELETE'" + method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,user'" + method.response.header.Access-Control-Allow-Origin: "'*'" + requestTemplates: + application/json: "{\"statusCode\": 200}" + passthroughBehavior: "when_no_match" + type: "mock" + securityDefinitions: + EmberServerless: + type: "apiKey" + name: "user" + in: "header" + x-amazon-apigateway-authtype: "cognito_user_pools" + x-amazon-apigateway-authorizer: + providerARNs: + - !GetAtt CognitoUserPool.Arn + type: "cognito_user_pools" + definitions: + Empty: + type: "object" + title: "Empty Schema" + LambdaFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Ref LambdaFunctionName + Handler: index.handler + Runtime: nodejs4.3 + Policies: AmazonDynamoDBFullAccess + Environment: + Variables: + TABLE_NAME: !Ref Table + Events: + GetDocs: + Type: Api + Properties: + RestApiId: !Ref ApiGatewayApi + Path: /docs + Method: GET + NewDoc: + Type: Api + Properties: + RestApiId: !Ref ApiGatewayApi + Path: /docs + Method: POST + DeleteDoc: + Type: Api + Properties: + RestApiId: !Ref ApiGatewayApi + Path: /docs + Method: DELETE + CognitoUserPool: + Type: AWS::Cognito::UserPool + Properties: + UserPoolName: EmberServerless + AutoVerifiedAttributes: + - "email" + CognitoUserPoolClient: + Type: AWS::Cognito::UserPoolClient + DependsOn: CognitoUserPool + Properties: + ClientName: !Ref AppClientName + UserPoolId: !Ref CognitoUserPool + GenerateSecret: false + CognitoIdentityPool: + Type: AWS::Cognito::IdentityPool + Properties: + AllowUnauthenticatedIdentities: true + CognitoIdentityProviders: + - ClientId: !Ref CognitoUserPoolClient + ProviderName: !GetAtt CognitoUserPool.ProviderName + CognitoIdentityPoolRoles: + Type: AWS::Cognito::IdentityPoolRoleAttachment + DependsOn: CognitoIdentityPool + Properties: + IdentityPoolId: !Ref CognitoIdentityPool + Roles: + authenticated: !GetAtt AuthenticatedRole.Arn + unauthenticated: !GetAtt UnauthenticatedRole.Arn + UnauthenticatedRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Federated: cognito-identity.amazonaws.com + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool + ForAnyValue:StringLike: + cognito-identity.amazonaws.com:amr: unauthenticated + Policies: + - + PolicyName: EmberServerlessUnauthenticatedApi + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - mobileanalytics:PutEvents + - cognito-sync:* + Resource: + - "*" + AuthenticatedRole: + Type: AWS::IAM::Role + Properties: + AssumeRolePolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: + Federated: cognito-identity.amazonaws.com + Action: sts:AssumeRoleWithWebIdentity + Condition: + StringEquals: + cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool + ForAnyValue:StringLike: + cognito-identity.amazonaws.com:amr: authenticated + Policies: + - + PolicyName: EmberServerlessAuthenticatedApi + PolicyDocument: + Version: '2012-10-17' + Statement: + - Effect: Allow + Action: + - execute-api:Invoke + Resource: !Join [ "", [ "arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref ApiGatewayApi, "/*" ] ] + Table: + Type: AWS::Serverless::SimpleTable +Outputs: + CognitoIdentityPoolId: + Description: Cognito Identity Pool ID + Value: !Ref CognitoIdentityPool + CognitoUserPoolsId: + Description: Cognito User Pools ID + Value: !Ref CognitoUserPool + CognitoUserPoolsClientId: + Description: Cognito User Pools App Client ID + Value: !Ref CognitoUserPoolClient + Api: + Description: API Gateway ID + Value: !Ref ApiGatewayApi + ApiUrl: + Description: URL of your API endpoint + Value: !Join + - '' + - - https:// + - !Ref ApiGatewayApi + - '.execute-api.' + - !Ref 'AWS::Region' + - '.amazonaws.com/Prod' From dfda1602a5329fc682ea20ecec500c765f9d6eba Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 1 Jul 2018 22:33:41 -0700 Subject: [PATCH 002/587] AppSync Feature Part 1 --- packages/amplify-category-api/.eslintrc.json | 14 + packages/amplify-category-api/.gitignore | 7 + packages/amplify-category-api/commands/api.js | 10 +- .../amplify-category-api/commands/api/add.js | 33 + .../amplify-category-api/commands/api/push.js | 16 + .../commands/api/remove.js | 16 + .../amplify-category-api/package-lock.json | 2506 +++++++++++++++++ packages/amplify-category-api/package.json | 24 +- ...ync-cloudformation-template-custom.yml.ejs | 82 + ...nc-cloudformation-template-default.yml.ejs | 540 ++++ .../default-values/appSync-defaults.js | 21 + .../index.js | 60 + .../appSync-walkthrough.js | 160 ++ .../provider-utils/supported-services.json | 81 + 14 files changed, 3557 insertions(+), 13 deletions(-) create mode 100644 packages/amplify-category-api/.eslintrc.json create mode 100644 packages/amplify-category-api/.gitignore create mode 100644 packages/amplify-category-api/commands/api/add.js create mode 100644 packages/amplify-category-api/commands/api/push.js create mode 100644 packages/amplify-category-api/commands/api/remove.js create mode 100644 packages/amplify-category-api/package-lock.json create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js create mode 100644 packages/amplify-category-api/provider-utils/supported-services.json diff --git a/packages/amplify-category-api/.eslintrc.json b/packages/amplify-category-api/.eslintrc.json new file mode 100644 index 0000000000..621522d8fb --- /dev/null +++ b/packages/amplify-category-api/.eslintrc.json @@ -0,0 +1,14 @@ +{ + "extends": "airbnb-base", + "rules": { + "no-param-reassign": "off", + "no-return-await" : "off", + "no-continue": "off", + "no-await-in-loop": "off", + "no-use-before-define": "off", + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off", + "consistent-return": "off" + } +} \ No newline at end of file diff --git a/packages/amplify-category-api/.gitignore b/packages/amplify-category-api/.gitignore new file mode 100644 index 0000000000..81fae83675 --- /dev/null +++ b/packages/amplify-category-api/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +node_modules +npm-debug.log +coverage +.nyc_output +yarn.lock +package.lock diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index a991e6513b..239c510df8 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -1,6 +1,8 @@ +const featureName = 'api'; + module.exports = { - name: 'api', - run: async ({ print, api }) => { - print.info(await api()) + name: featureName, + run: async (context) => { + context.print.info("Here's a list of all the Amplify API commands!"); }, -} \ No newline at end of file +}; diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js new file mode 100644 index 0000000000..b948bacde8 --- /dev/null +++ b/packages/amplify-category-api/commands/api/add.js @@ -0,0 +1,33 @@ +const fs = require('fs'); + +const subcommand = 'add'; +const category = 'api'; +const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); + +let options; + +module.exports = { + name: subcommand, + run: async (context) => { + const { amplify } = context; + + return amplify.serviceSelectionPrompt(context, category, servicesMetadata) + .then((result) => { + options = { + service: result.service, + providerPlugin: result.providerName, + }; + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.error('Provider not confgiured for this category'); + return; + } + return providerController.addResource(context, category, result.service, options); + }) + .then(() => context.print.success('Successfully added resource')) + .catch((err) => { + context.print.info(err.stack); + context.print.error('There was an error adding the API resource'); + }); + }, +}; diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js new file mode 100644 index 0000000000..a30bd83351 --- /dev/null +++ b/packages/amplify-category-api/commands/api/push.js @@ -0,0 +1,16 @@ +const subcommand = 'push'; +const category = 'api'; + +module.exports = { + name: subcommand, + run: async (context) => { + const { amplify, parameters } = context; + const resourceName = parameters.first; + + return amplify.pushResources(context, category, resourceName) + .catch((err) => { + context.print.info(err.stack); + context.print.error('There was an error pushing the API resource'); + }); + }, +}; diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js new file mode 100644 index 0000000000..c763cd008a --- /dev/null +++ b/packages/amplify-category-api/commands/api/remove.js @@ -0,0 +1,16 @@ +const subcommand = 'remove'; +const category = 'api'; + +module.exports = { + name: subcommand, + run: async (context) => { + const { amplify, parameters } = context; + const resourceName = parameters.first; + + return amplify.removeResource(context, category, resourceName) + .catch((err) => { + context.print.info(err.stack); + context.print.error('There was an error removing the API resource'); + }); + }, +}; diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json new file mode 100644 index 0000000000..d6e05c143b --- /dev/null +++ b/packages/amplify-category-api/package-lock.json @@ -0,0 +1,2506 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + }, + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" + }, + "amplify-category-storage": { + "version": "file:../amplify-category-storage", + "requires": { + "eslint": "4.19.1", + "inquirer": "3.3.0", + "uuid": "2.0.3" + }, + "dependencies": { + "acorn": { + "version": "5.6.2", + "bundled": true + }, + "acorn-jsx": { + "version": "3.0.1", + "bundled": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "bundled": true + } + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "bundled": true + }, + "ansi-escapes": { + "version": "3.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "argparse": { + "version": "1.0.10", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-union": { + "version": "1.0.2", + "bundled": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "bundled": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "caller-path": { + "version": "0.1.0", + "bundled": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "bundled": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "chardet": { + "version": "0.4.2", + "bundled": true + }, + "circular-json": { + "version": "0.3.3", + "bundled": true + }, + "cli-cursor": { + "version": "2.1.0", + "bundled": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "del": { + "version": "2.2.2", + "bundled": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.1.0", + "bundled": true, + "requires": { + "esutils": "2.0.2" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "eslint": { + "version": "4.19.1", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.5.0", + "ignore": "3.3.8", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "bundled": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "bundled": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.12.0", + "bundled": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "bundled": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "bundled": true + }, + "eslint-scope": { + "version": "3.7.1", + "bundled": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "bundled": true + }, + "espree": { + "version": "3.5.4", + "bundled": true, + "requires": { + "acorn": "5.6.2", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "bundled": true + }, + "esquery": { + "version": "1.0.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "external-editor": { + "version": "2.2.0", + "bundled": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "figures": { + "version": "2.0.0", + "bundled": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "bundled": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "bundled": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "bundled": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.5.0", + "bundled": true + }, + "globby": { + "version": "5.0.0", + "bundled": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.8", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "inquirer": { + "version": "3.3.0", + "bundled": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-path-cwd": { + "version": "1.0.0", + "bundled": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "bundled": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "bundled": true + }, + "is-resolvable": { + "version": "1.1.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true + }, + "js-yaml": { + "version": "3.12.0", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "bundled": true + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "natural-compare": { + "version": "1.4.0", + "bundled": true + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "bundled": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "bundled": true + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "progress": { + "version": "2.0.0", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "regexpp": { + "version": "1.1.0", + "bundled": true + }, + "require-uncached": { + "version": "1.0.3", + "bundled": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.7.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "bundled": true + }, + "restore-cursor": { + "version": "2.0.0", + "bundled": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "bundled": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "bundled": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "bundled": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slice-ansi": { + "version": "1.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "table": { + "version": "4.0.2", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "tmp": { + "version": "0.0.33", + "bundled": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "2.0.3", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write": { + "version": "0.2.1", + "bundled": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.2" + } + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "requires": { + "esutils": "2.0.2" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", + "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==" + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "hosted-git-info": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", + "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==" + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" + }, + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.2" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } +} diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b533934033..5bc500835f 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,15 +1,21 @@ { "name": "amplify-category-api", "version": "0.1.0", + "description": "amplify-cli api plugin", "main": "index.js", - "license": "apache-2.0", - "defaults": { - "apiName": "amplify-api", - "apiType": [ - "regional", - "edge" - ], - "apiStageName": "prod", - "apiCors": "*" + "dependencies": { + "eslint": "^4.19.1", + "inquirer": "^3.2.1", + "uuid": "^2.0.3" + }, + "scripts": { + "lint": "eslint .", + "lint-fix": "eslint . --fix" + }, + "license": "Apache-2.0", + "devDependencies": { + "amplify-category-storage": "file:../amplify-category-storage", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-plugin-import": "^2.12.0" } } diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs new file mode 100644 index 0000000000..62652a2fc2 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -0,0 +1,82 @@ +--- +<%if (props.dependsOn) { %> +Parameters: +<% 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] %> +<% } %> +<% } %> +<% } %> + +Resources: + GraphQLApi: + Type: "AWS::AppSync::GraphQLApi" + Properties: + Name: <%= props.apiName %> + AuthenticationType: AWS_IAM + + ServiceRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: <%= props.serviceRoleName %> + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: '' + Effect: Allow + Principal: + Service: appsync.amazonaws.com + Action: 'sts:AssumeRole' + <%if (props.dataSources && props.dataSources.dynamoDb) { %> + + ServicePolicyDynamo: + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: <%= props.servicePolicyName %> + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'dynamodb:Query' + - 'dynamodb:BatchWriteItem' + - 'dynamodb:GetItem' + - 'dynamodb:DeleteItem' + - 'dynamodb:PutItem' + - 'dynamodb:Scan' + - 'dynamodb:UpdateItem' + Resource: + <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> + - !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Arn + <% } %> + Roles: + - !Ref ServiceRole + <% } %> + + <%if (props.dataSources && props.dataSources.dynamoDb) { %> + <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> + <%= props.dataSources.dynamoDb[i].resourceName %>DataSource: + Type: "AWS::AppSync::DataSource" + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + Name: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name + ServiceRoleArn: !GetAtt ServiceRole.Arn + Type: AMAZON_DYNAMODB + DynamoDBConfig: + AwsRegion: <%= props.region %> + TableName: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name + <% } %> + <% } %> + +Outputs: + GraphQLApiARN: + Description: The App ID of the GraphQL endpoint. + Value: !Ref GraphQLApi + GraphQLApiId: + Description: The App ID of the GraphQL endpoint. + Value: !GetAtt GraphQLApi.ApiId + GraphQLApiEndpoint: + Description: The URL for the GraphQL endpoint. + Value: !GetAtt GraphQLApi.GraphQLUrl \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs new file mode 100644 index 0000000000..c7450291b7 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs @@ -0,0 +1,540 @@ +--- +Description: AWSAppSync DynamoDB Example +Resources: + GraphQLApi: + Type: "AWS::AppSync::GraphQLApi" + Properties: + Name: <%= props.apiName %> + AuthenticationType: AWS_IAM + + ServiceRole: + Type: 'AWS::IAM::Role' + Properties: + RoleName: <%= props.serviceRoleName %> + AssumeRolePolicyDocument: + Version: 2012-10-17 + Statement: + - Sid: '' + Effect: Allow + Principal: + Service: appsync.amazonaws.com + Action: 'sts:AssumeRole' + + DynamoDbTable: + Type: 'AWS::DynamoDB::Table' + Properties: + AttributeDefinitions: + - AttributeName: id + AttributeType: S + KeySchema: + - AttributeName: id + KeyType: HASH + ProvisionedThroughput: + ReadCapacityUnits: '5' + WriteCapacityUnits: '5' + TableName: <%= props.defaultTableName %> + + ServicePolicy: + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: <%= props.servicePolicyName %> + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'dynamodb:Query' + - 'dynamodb:BatchWriteItem' + - 'dynamodb:GetItem' + - 'dynamodb:DeleteItem' + - 'dynamodb:PutItem' + - 'dynamodb:Scan' + - 'dynamodb:UpdateItem' + Resource: + - !GetAtt DynamoDbTable.Arn + Roles: + - !Ref ServiceRole + + PostDynamoDBTableDataSource: + Type: "AWS::AppSync::DataSource" + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + Name: PostDynamoDBTable + Description: The Post DynamoDB table in <%= props.region %> + Type: AMAZON_DYNAMODB + ServiceRoleArn: !GetAtt ServiceRole.Arn + DynamoDBConfig: + AwsRegion: <%= props.region %> + TableName: !Ref DynamoDbTable + + QueryGetPostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Query + FieldName: getPost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "GetItem", + "key" : { + "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) + } + } + ResponseMappingTemplate: "$utils.toJson($ctx.result)" + + QueryAllPostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Query + FieldName: allPost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "Scan", + #if( $ctx.args.count ) + "limit": $ctx.args.count, + #end + #if( ${ctx.args.nextToken} ) + "nextToken": "${ctx.args.nextToken}" + #end + } + ResponseMappingTemplate: | + { + "posts": $utils.toJson($ctx.result.items), + #if( ${ctx.result.nextToken} ) + "nextToken": "${ctx.result.nextToken}", + #end + }ctx + QueryAllPostsByAuthorResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Query + FieldName: allPostsByAuthor + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "Query", + "index" : "author-index", + "query" : { + "expression": "author = :author", + "expressionValues" : { + ":author" : $util.dynamodb.toDynamoDBJson($ctx.args.author) + } + }, + #if( $ctx.args.count ) + "limit": $ctx.args.count, + #end + #if( ${ctx.args.nextToken} ) + "nextToken": "${ctx.args.nextToken}", + #end + } + ResponseMappingTemplate: | + { + "posts": $utils.toJson($ctx.result.items), + #if( ${ctx.result.nextToken} ) + "nextToken": "${ctx.result.nextToken}", + #end + } + QueryAllPostsByTagResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Query + FieldName: allPostsByTag + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "Scan", + "filter": { + "expression": "contains (tags, :tag)", + "expressionValues": { + ":tag": $util.dynamodb.toStringJson($ctx.args.tag) + } + }, + #if( $ctx.args.count ) + "limit": $ctx.args.count, + #end + #if( ${ctx.args.nextToken} ) + "nextToken": "${ctx.args.nextToken}" + #end + } + ResponseMappingTemplate: | + { + "posts": $utils.toJson($ctx.result.items), + #if( ${ctx.result.nextToken} ) + "nextToken": "${ctx.result.nextToken}", + #end + } + MutationaddPostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: addPost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + #set( $d = $util.dynamodb ) + #set( $values = $d.toMapValues($ctx.args)) + $!{values.put("ups", $d.toNumber(1))} + $!{values.put("downs", $d.toNumber(0))} + $!{values.put("version", $d.toNumber(1))} + $!{values.put("created", $d.toDynamoDB($util.time.nowISO8601()))} + $!{values.put("lastUpdated", $values.get("created"))} + { + "version" : "2017-02-28", + "operation" : "PutItem", + "key" : { + "id" : $d.toStringJson($utils.autoId()) + }, + "attributeValues" : $util.toJson($values), + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationAddCommentResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: addComment + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $util.dynamodb.toStringJson($ctx.args.id) + }, + "update" : { + "expression" : "SET comments = list_append(if_not_exists(comments, :emptyList), :newComment), lastUpdated = :lastUpdated ADD version :plusOne", + "expressionValues" : { + ":emptyList": $util.dynamodb.toListJson([]), + ":newComment" : $util.dynamodb.toListJson([$util.map.copyAndRetainAllKeys($ctx.args, ["author","comment"])]), + ":plusOne" : $util.dynamodb.toNumberJson(1), + ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()) + } + }, + "condition" : { + "expression" : "attribute_exists(id)" + }, + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationAddTagResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: addTag + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $util.dynamodb.toStringJson($ctx.args.id) + }, + "update" : { + "expression" : "ADD tags :tags, version :plusOne SET lastUpdated = :lastUpdated", + "expressionValues" : { + ":tags" : $util.dynamodb.toStringSetJson([$ctx.args.tag]), + ":plusOne" : $util.dynamodb.toNumberJson(1), + ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), + } + }, + "condition" : { + "expression" : "attribute_exists(id)" + }, + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationRemoveTagResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: removeTag + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $util.dynamodb.toStringJson($ctx.args.id) + }, + "update" : { + "expression" : "DELETE tags :tags ADD version :plusOne SET lastUpdated = :lastUpdated", + "expressionValues" : { + ":tags" : $util.dynamodb.toStringSetJson([$ctx.args.tag]), + ":plusOne" : $util.dynamodb.toNumberJson(1), + ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), + } + }, + "condition" : { + "expression" : "attribute_exists(id)" + }, + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationDeletePostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: deletePost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "DeleteItem", + "key": { + "id": $util.dynamodb.toStringJson($ctx.args.id) + }, + #if( $ctx.args.containsKey("expectedVersion") ) + "condition" : { + "expression" : "attribute_not_exists(id) OR version = :expectedVersion", + "expressionValues" : { + ":expectedVersion" : $util.dynamodb.toNumberJson($ctx.args.expectedVersion) + } + }, + #end + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationUpvotePostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: upvotePost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $util.dynamodb.toStringJson($ctx.args.id) + }, + "update" : { + "expression" : "ADD ups :plusOne, version :plusOne SET lastUpdated = :lastUpdated", + "expressionValues" : { + ":plusOne" : $util.dynamodb.toNumberJson(1), + ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()) + } + }, + "condition" : { + "expression" : "attribute_exists(id)" + }, + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationDownvotePostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: downvotePost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $util.dynamodb.toStringJson($ctx.args.id) + }, + "update" : { + "expression" : "ADD downs :plusOne, version :plusOne SET lastUpdated = :lastUpdated", + "expressionValues" : { + ":plusOne" : $util.dynamodb.toNumberJson(1), + ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), + } + }, + "condition" : { + "expression" : "attribute_exists(id)" + }, + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + MutationUpdatePostResolver: + Type: "AWS::AppSync::Resolver" + DependsOn: Schema + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + TypeName: Mutation + FieldName: updatePost + DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name + RequestMappingTemplate: | + #set( $ddb = $util.dynamodb ) + { + "version" : "2017-02-28", + "operation" : "UpdateItem", + "key" : { + "id" : $ddb.toDynamoDBJson($ctx.args.id) + }, + ## Set up some space to keep track of things we're updating ** + #set( $expNames = {} ) + #set( $expValues = {} ) + #set( $expSet = {} ) + #set( $expAdd = {} ) + #set( $expRemove = [] ) + ## Increment "version" by 1 ** + $!{expAdd.put("version", ":one")} + $!{expValues.put(":one", $ddb.toDynamoDB(1))} + ## Set the "lastUpdated" timestamp ** + $!{expSet.put("lastUpdated", ":lastUpdated")} + $!{expValues.put(":lastUpdated", $ddb.toDynamoDB($util.time.nowISO8601()))} + ## Iterate through each argument, skipping "id" and "expectedVersion" ** + #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args, ["id","expectedVersion"]).entrySet() ) + #if( $util.isNull($entry.value) ) + ## If the argument is set to "null", then remove that attribute from the item in DynamoDB ** + #set( $discard = ${expRemove.add("#${entry.key}")} ) + $!{expNames.put("#${entry.key}", "${entry.key}")} + #else + ## Otherwise set (or update) the attribute on the item in DynamoDB ** + $!{expSet.put("#${entry.key}", ":${entry.key}")} + $!{expNames.put("#${entry.key}", "${entry.key}")} + $!{expValues.put(":${entry.key}", $ddb.toDynamoDB($entry.value))} + #end + #end + ## Start building the update expression, starting with attributes we're going to SET ** + #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 + ## Continue building the update expression, adding attributes we're going to ADD ** + #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 + ## Continue building the update expression, adding attributes we're going to REMOVE ** + #if( !${expRemove.isEmpty()} ) + #set( $expression = "${expression} REMOVE" ) + #foreach( $entry in $expRemove ) + #set( $expression = "${expression} ${entry}" ) + #if ( $foreach.hasNext ) + #set( $expression = "${expression}," ) + #end + #end + #end + ## Finally, write the update expression into the document, along with any expressionNames and expressionValues ** + "update" : { + "expression" : "${expression}", + #if( !${expNames.isEmpty()} ) + "expressionNames" : $utils.toJson($expNames), + #end + #if( !${expValues.isEmpty()} ) + "expressionValues" : $utils.toJson($expValues), + #end + }, + "condition" : { + "expression" : "attribute_exists(id) and version = :expectedVersion", + "expressionValues" : { + ":expectedVersion" : $ddb.toDynamoDBJson($context.arguments.expectedVersion) + } + } + } + ResponseMappingTemplate: "$util.toJson($ctx.result)" + + Schema: + Type: "AWS::AppSync::GraphQLSchema" + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + Definition: | + type Comment { + author: String! + comment: String! + } + type Mutation { + addComment(id: ID!, author: String!, comment: String!): Post + addTag(id: ID!, tag: String!): Post + removeTag(id: ID!, tag: String!): Post + deletePost(id: ID!, expectedVersion: Int): Post + upvotePost(id: ID!): Post + downvotePost(id: ID!): Post + updatePost( + id: ID!, + author: String, + title: String, + content: String, + url: String, + expectedVersion: Int! + ): Post + addPost( + author: String!, + title: String!, + content: String!, + url: String! + ): Post! + } + type PaginatedPosts { + posts: [Post!]! + nextToken: String + } + type Post { + id: ID! + author: String + title: String + content: String + url: String + ups: Int! + downs: Int! + version: Int! + tags: [String!] + comments: [Comment!] + created: String + lastUpdated: String + } + type Query { + allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts! + allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts! + allPost(count: Int, nextToken: String): PaginatedPosts! + getPost(id: ID!): Post + } + schema { + query: Query + mutation: Mutation + } +Outputs: + GraphQLApiARN: + Description: The App ID of the GraphQL endpoint. + Value: !Ref GraphQLApi + GraphQLApiId: + Description: The App ID of the GraphQL endpoint. + Value: !GetAtt GraphQLApi.ApiId + GraphQLApiEndpoint: + Description: The URL for the GraphQL endpoint. + Value: !GetAtt GraphQLApi.GraphQLUrl + PostDynamoDBTableDataSourceARN: + Description: The ARN for the Post DynamoDB table DataSource. + Value: !Ref PostDynamoDBTableDataSource + PostDynamoDBTableDataSourceName: + Description: The ARN for the Post DynamoDB table DataSource. + Value: !GetAtt PostDynamoDBTableDataSource.Name \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js new file mode 100644 index 0000000000..3d53bceaae --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js @@ -0,0 +1,21 @@ +const uuid = require('uuid'); + +const getAllDefaults = (project) => { + const name = project.projectConfig.projectName.toLowerCase(); + const region = project.amplifyMeta.providers['amplify-provider-awscloudformation'].Region; + const [shortId] = uuid().split('-'); + const defaults = { + resourceName: `appsync${shortId}`, + apiName: `${name}${shortId}`, + serviceRoleName: `serviceRole${shortId}`, + servicePolicyName: `servicePolicy${shortId}`, + region, + defaultTableName: `Posts${shortId}` + }; + console.log(defaults); + return defaults; +}; + +module.exports = { + getAllDefaults, +}; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js new file mode 100644 index 0000000000..634ba5d5b0 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -0,0 +1,60 @@ +const fs = require('fs'); + +let serviceMetadata; + +function serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) { + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { serviceWalkthrough } = require(serviceWalkthroughSrc); + + return serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); +} + + +function copyCfnTemplate(context, category, options, cfnFilename) { + const { amplify } = context; + const targetDir = amplify.pathManager.getBackendDirPath(); + const pluginDir = __dirname; + + const copyJobs = [ + { + dir: pluginDir, + template: `cloudformation-templates/${cfnFilename}`, + target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.yml`, + }, + ]; + + // copy over the files + return context.amplify.copyBatch(context, copyJobs, options); +} + +function addResource(context, category, service, options) { + let answers; + serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + let { cfnFilename } = serviceMetadata; + const {defaultValuesFilename, serviceWalkthroughFilename} = serviceMetadata; + + return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) + .then((result) => { + let dependsOn; + + if(result.answers) { + answers = result.answers; + options.dependsOn = result.dependsOn; + } else { + answers = result; + } + if(answers.customCfnFile) { + cfnFilename = answers.customCfnFile; + } + + copyCfnTemplate(context, category, answers, cfnFilename); + context.amplify.updateamplifyMetaAfterResourceAdd( + category, + answers.resourceName, + options + ); + return answers.resourceName + }); +} + +module.exports = { addResource }; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js new file mode 100644 index 0000000000..ce9efa9980 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -0,0 +1,160 @@ +const inquirer = require('inquirer'); + +function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { + const { amplify } = context; + const { inputs } = serviceMetadata; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = require(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + + const questions = []; + for (let i = 0; i < 3; i += 1) { + let question = { + name: inputs[i].key, + message: inputs[i].question, + validate: amplify.inputValidation(inputs[i]), + default: () => { + const defaultValue = allDefaultValues[inputs[i].key]; + return defaultValue; + }, + }; + + if (inputs[i].type && inputs[i].type === 'list') { + question = Object.assign({ + type: 'list', + choices: inputs[i].options, + }, question); + } else if (inputs[i].type && inputs[i].type === 'multiselect') { + question = Object.assign({ + type: 'checkbox', + choices: inputs[i].options, + }, question); + } else { + question = Object.assign({ + type: 'input', + }, question); + } + questions.push(question); + } + + return inquirer.prompt(questions) + .then((answers) => { + if(answers.templateSelection === "default") { + Object.assign(allDefaultValues, answers); + return allDefaultValues; + } else { + return askCustomQuestions(context, inputs) + .then((result) => { + Object.assign(allDefaultValues, result.answers); + allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; + return {answers: allDefaultValues, dependsOn: result.dependsOn}; + }); + } + }); +} + +async function askCustomQuestions(context, inputs) { + let answers = {}; + let dependsOn = []; + + if(await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { + const dataSourceAnswers = await askDataSourceQuestions(context, inputs); + let dataSources = dataSourceAnswers.dataSources; + dependsOn = dataSourceAnswers.dependsOn; + Object.assign(answers, {dataSources}); + Object.assign(answers, {dependsOn}); + } + return {answers, dependsOn}; + +} +async function askDataSourceQuestions(context, inputs) { + const dataSourceTypeQuestion = { + type: inputs[3].type, + name: inputs[3].key, + message: inputs[3].question, + choices: inputs[3].options, + }; + let dataSources = {}; + let dependsOn = []; + let continueDataSourcesQuestion = true; + + // Ask data source related questions + + while (continueDataSourcesQuestion) { + const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); + switch(dataSourceAnswer[inputs[3].key]) { + case 'DynamoDb': { + let resourceName = await askDynamoDBQuestions(context, inputs); + if(!dataSources.dynamoDb) { + dataSources.dynamoDb = [{category: 'storage', resourceName}]; + } else { + dataSources.dynamoDb.push({category: 'storage', resourceName}); + } + dependsOn.push({ + category: 'storage', + resourceName, + attributes: ['Name', 'Arn']}); + } + break; + default: context.print.error('Feature not yet implemented'); + } + continueDataSourcesQuestion = await context.prompt.confirm('Do you want to add another data source?'); + } + + return {dataSources, dependsOn}; + +} + +async function askDynamoDBQuestions(context, inputs) { + + const dynamoDbTypeQuestion = { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + choices: inputs[4].options, + }; + const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); + while(true) { + switch(dynamoDbTypeAnswer[inputs[4].key]) { + case 'currentProject': { + const storageResources = context.amplify.getProjectDetails().amplifyMeta['storage']; + const dynamoDbProjectResources = []; + Object.keys(storageResources).forEach((resourceName) => { + if(storageResources[resourceName].service === "DynamoDB") { + dynamoDbProjectResources.push(resourceName); + } + }); + if(dynamoDbProjectResources.length === 0) { + context.print.error("There are no DynamoDb resources configured in your project currently"); + break; + } + const dynamoResourceQuestion = { + type: inputs[5].type, + name: inputs[5].key, + message: inputs[5].question, + choices: dynamoDbProjectResources, + }; + + const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); + + return dynamoResourceAnswer[inputs[5].key]; + + } + break; + case 'newResource': { + const { add } = require('amplify-category-storage'); + return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') + .then((resourceName) => { + context.print.success("Succesfully added DynamoDb table localy"); + return resourceName; + }); + } + break; + default: context.print.error('Invalid option selected'); + } + } + +} + + +module.exports = { serviceWalkthrough }; \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json new file mode 100644 index 0000000000..cfcce64ad4 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -0,0 +1,81 @@ +{ + "AppSync": { + "inputs": [ + { + "key": "resourceName", + "type": "input", + "question": "Please provide a friendly name for your resource that will be used to label 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": "Please provide API name:", + "validation": { + "operator": "regex", + "value": "^[a-zA-Z0-9._-]+$", + "onErrorMsg": "You can use the following characters: a-z A-Z 0-9 . - _" + }, + "required": true + }, + { + + "key": "templateSelection", + "type": "list", + "question": "Choose from one of the options below", + "options": [ + { "name": "Use sample AppSync-DynamoDB example cloudformation template", + "value": "default" + }, + { + "name": "Use custom AppSync cloudformation template", + "value": "custom" + } + ], + "required": true + }, + { + + "key": "dataSourceType", + "type": "list", + "question": "Choose a data source you would like to add to your GraphQL API", + "options": [ + "DynamoDb", + "Lambda", + "Elasticsearch" + ] + }, + { + + "key": "dynamoDbType", + "type": "list", + "question": "Choose a DynamoDB data source option", + "options": [ + { "name": "Use DynamoDB table configured in the current Amplify project", + "value": "currentProject" + }, + { + "name": "Create a new DynamoDB table", + "value": "newResource" + } + ] + }, + { + + "key": "dynamoDbResources", + "type": "list", + "question": "Choose from one of the already configured DynamoDB tables" + } + ], + "defaultValuesFilename": "appSync-defaults.js", + "serviceWalkthroughFilename": "appSync-walkthrough.js", + "cfnFilename": "appSync-cloudformation-template-default.yml.ejs", + "provider": "amplify-provider-awscloudformation" + } +} \ No newline at end of file From 7fc2fd8505c7c1a38ee728acd72bc63fd52c5e75 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 1 Jul 2018 22:53:29 -0700 Subject: [PATCH 003/587] Fix eslint issues --- packages/amplify-category-api/.eslintrc.json | 1 + .../extensions/api-extension.js | 10 +-- packages/amplify-category-api/package.json | 2 +- .../default-values/appSync-defaults.js | 2 +- .../index.js | 18 ++-- .../appSync-walkthrough.js | 83 +++++++++---------- 6 files changed, 54 insertions(+), 62 deletions(-) diff --git a/packages/amplify-category-api/.eslintrc.json b/packages/amplify-category-api/.eslintrc.json index 621522d8fb..ef16d9dd3f 100644 --- a/packages/amplify-category-api/.eslintrc.json +++ b/packages/amplify-category-api/.eslintrc.json @@ -3,6 +3,7 @@ "rules": { "no-param-reassign": "off", "no-return-await" : "off", + "no-constant-condition": "off", "no-continue": "off", "no-await-in-loop": "off", "no-use-before-define": "off", diff --git a/packages/amplify-category-api/extensions/api-extension.js b/packages/amplify-category-api/extensions/api-extension.js index 5c8c3d5c83..ea56f1a245 100755 --- a/packages/amplify-category-api/extensions/api-extension.js +++ b/packages/amplify-category-api/extensions/api-extension.js @@ -1,6 +1,6 @@ -module.exports = toolbox => { +module.exports = (toolbox) => { toolbox.api = async () => { - let params = toolbox.parameters - console.log(params) - } -} \ No newline at end of file + const params = toolbox.parameters; + console.log(params); + }; +}; diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5bc500835f..ef54be28e9 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -4,6 +4,7 @@ "description": "amplify-cli api plugin", "main": "index.js", "dependencies": { + "amplify-category-storage": "file:../amplify-category-storage", "eslint": "^4.19.1", "inquirer": "^3.2.1", "uuid": "^2.0.3" @@ -14,7 +15,6 @@ }, "license": "Apache-2.0", "devDependencies": { - "amplify-category-storage": "file:../amplify-category-storage", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" } diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js index 3d53bceaae..d1377a1888 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js @@ -10,7 +10,7 @@ const getAllDefaults = (project) => { serviceRoleName: `serviceRole${shortId}`, servicePolicyName: `servicePolicy${shortId}`, region, - defaultTableName: `Posts${shortId}` + defaultTableName: `Posts${shortId}`, }; console.log(defaults); return defaults; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index 634ba5d5b0..74769d2a61 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -31,29 +31,27 @@ function addResource(context, category, service, options) { let answers; serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; let { cfnFilename } = serviceMetadata; - const {defaultValuesFilename, serviceWalkthroughFilename} = serviceMetadata; + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) .then((result) => { - let dependsOn; - - if(result.answers) { - answers = result.answers; + if (result.answers) { + ({ answers } = result.answers); options.dependsOn = result.dependsOn; } else { answers = result; } - if(answers.customCfnFile) { + if (answers.customCfnFile) { cfnFilename = answers.customCfnFile; } copyCfnTemplate(context, category, answers, cfnFilename); context.amplify.updateamplifyMetaAfterResourceAdd( - category, - answers.resourceName, - options + category, + answers.resourceName, + options, ); - return answers.resourceName + return answers.resourceName; }); } diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index ce9efa9980..f6c9f80e31 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -39,33 +39,31 @@ function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { return inquirer.prompt(questions) .then((answers) => { - if(answers.templateSelection === "default") { - Object.assign(allDefaultValues, answers); - return allDefaultValues; - } else { - return askCustomQuestions(context, inputs) - .then((result) => { - Object.assign(allDefaultValues, result.answers); - allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; - return {answers: allDefaultValues, dependsOn: result.dependsOn}; - }); - } + if (answers.templateSelection === 'default') { + Object.assign(allDefaultValues, answers); + return allDefaultValues; + } + return askCustomQuestions(context, inputs) + .then((result) => { + Object.assign(allDefaultValues, result.answers); + allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; + return { answers: allDefaultValues, dependsOn: result.dependsOn }; + }); }); } async function askCustomQuestions(context, inputs) { - let answers = {}; + const answers = {}; let dependsOn = []; - if(await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { + if (await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { const dataSourceAnswers = await askDataSourceQuestions(context, inputs); - let dataSources = dataSourceAnswers.dataSources; - dependsOn = dataSourceAnswers.dependsOn; - Object.assign(answers, {dataSources}); - Object.assign(answers, {dependsOn}); + const { dataSources } = dataSourceAnswers; + ({ dependsOn } = dataSourceAnswers.dependsOn); + Object.assign(answers, { dataSources }); + Object.assign(answers, { dependsOn }); } - return {answers, dependsOn}; - + return { answers, dependsOn }; } async function askDataSourceQuestions(context, inputs) { const dataSourceTypeQuestion = { @@ -74,39 +72,38 @@ async function askDataSourceQuestions(context, inputs) { message: inputs[3].question, choices: inputs[3].options, }; - let dataSources = {}; - let dependsOn = []; + const dataSources = {}; + const dependsOn = []; let continueDataSourcesQuestion = true; // Ask data source related questions while (continueDataSourcesQuestion) { const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); - switch(dataSourceAnswer[inputs[3].key]) { + switch (dataSourceAnswer[inputs[3].key]) { case 'DynamoDb': { - let resourceName = await askDynamoDBQuestions(context, inputs); - if(!dataSources.dynamoDb) { - dataSources.dynamoDb = [{category: 'storage', resourceName}]; + const resourceName = await askDynamoDBQuestions(context, inputs); + if (!dataSources.dynamoDb) { + dataSources.dynamoDb = [{ category: 'storage', resourceName }]; } else { - dataSources.dynamoDb.push({category: 'storage', resourceName}); + dataSources.dynamoDb.push({ category: 'storage', resourceName }); } dependsOn.push({ - category: 'storage', + category: 'storage', resourceName, - attributes: ['Name', 'Arn']}); + attributes: ['Name', 'Arn'], + }); } - break; + break; default: context.print.error('Feature not yet implemented'); } continueDataSourcesQuestion = await context.prompt.confirm('Do you want to add another data source?'); } - return {dataSources, dependsOn}; - + return { dataSources, dependsOn }; } async function askDynamoDBQuestions(context, inputs) { - const dynamoDbTypeQuestion = { type: inputs[4].type, name: inputs[4].key, @@ -114,18 +111,18 @@ async function askDynamoDBQuestions(context, inputs) { choices: inputs[4].options, }; const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); - while(true) { - switch(dynamoDbTypeAnswer[inputs[4].key]) { + while (true) { + switch (dynamoDbTypeAnswer[inputs[4].key]) { case 'currentProject': { - const storageResources = context.amplify.getProjectDetails().amplifyMeta['storage']; - const dynamoDbProjectResources = []; + const storageResources = context.amplify.getProjectDetails().amplifyMeta.storage; + const dynamoDbProjectResources = []; Object.keys(storageResources).forEach((resourceName) => { - if(storageResources[resourceName].service === "DynamoDB") { + if (storageResources[resourceName].service === 'DynamoDB') { dynamoDbProjectResources.push(resourceName); } }); - if(dynamoDbProjectResources.length === 0) { - context.print.error("There are no DynamoDb resources configured in your project currently"); + if (dynamoDbProjectResources.length === 0) { + context.print.error('There are no DynamoDb resources configured in your project currently'); break; } const dynamoResourceQuestion = { @@ -138,23 +135,19 @@ async function askDynamoDBQuestions(context, inputs) { const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); return dynamoResourceAnswer[inputs[5].key]; - } - break; case 'newResource': { const { add } = require('amplify-category-storage'); return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') .then((resourceName) => { - context.print.success("Succesfully added DynamoDb table localy"); + context.print.success('Succesfully added DynamoDb table localy'); return resourceName; }); } - break; default: context.print.error('Invalid option selected'); } } - } -module.exports = { serviceWalkthrough }; \ No newline at end of file +module.exports = { serviceWalkthrough }; From 61d404cbd651120bf753a4d22210ff9f14af0045 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 1 Jul 2018 23:03:05 -0700 Subject: [PATCH 004/587] Remove console statement --- .../default-values/appSync-defaults.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js index d1377a1888..9d2677d02b 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js @@ -12,7 +12,7 @@ const getAllDefaults = (project) => { region, defaultTableName: `Posts${shortId}`, }; - console.log(defaults); + return defaults; }; From 4b4bc1386aa017168a4f5f82f1dc55c4ac94213d Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 2 Jul 2018 16:00:44 -0700 Subject: [PATCH 005/587] Add auth to AppSync --- .../amplify-category-api/commands/api/add.js | 2 +- .../extensions/api-extension.js | 6 - .../amplify-category-api/package-lock.json | 73 +++++- packages/amplify-category-api/package.json | 1 + ...ync-cloudformation-template-custom.yml.ejs | 44 +++- .../default-values/appSync-defaults.js | 2 +- .../index.js | 2 +- .../appSync-walkthrough.js | 233 ++++++++++++++---- .../provider-utils/supported-services.json | 129 ++++++++-- 9 files changed, 397 insertions(+), 95 deletions(-) delete mode 100755 packages/amplify-category-api/extensions/api-extension.js diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index b948bacde8..31d86c8eef 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -19,7 +19,7 @@ module.exports = { }; const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { - context.print.error('Provider not confgiured for this category'); + context.print.error('Provider not configured for this category'); return; } return providerController.addResource(context, category, result.service, options); diff --git a/packages/amplify-category-api/extensions/api-extension.js b/packages/amplify-category-api/extensions/api-extension.js deleted file mode 100755 index ea56f1a245..0000000000 --- a/packages/amplify-category-api/extensions/api-extension.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = (toolbox) => { - toolbox.api = async () => { - const params = toolbox.parameters; - console.log(params); - }; -}; diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json index d6e05c143b..7405c3d9de 100644 --- a/packages/amplify-category-api/package-lock.json +++ b/packages/amplify-category-api/package-lock.json @@ -1,6 +1,8 @@ { - "requires": true, + "name": "amplify-category-api", + "version": "0.1.0", "lockfileVersion": 1, + "requires": true, "dependencies": { "acorn": { "version": "5.7.1", @@ -1298,7 +1300,8 @@ "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true }, "caller-path": { "version": "0.1.0", @@ -1401,7 +1404,8 @@ "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -1457,6 +1461,7 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, "requires": { "is-arrayish": "0.2.1" } @@ -1515,6 +1520,7 @@ "version": "12.1.0", "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, "requires": { "eslint-restricted-globals": "0.1.1" } @@ -1523,6 +1529,7 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", + "dev": true, "requires": { "debug": "2.6.9", "resolve": "1.8.1" @@ -1532,6 +1539,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -1542,6 +1550,7 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, "requires": { "debug": "2.6.9", "pkg-dir": "1.0.0" @@ -1551,6 +1560,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -1561,6 +1571,7 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "dev": true, "requires": { "contains-path": "0.1.0", "debug": "2.6.9", @@ -1578,6 +1589,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "requires": { "ms": "2.0.0" } @@ -1586,6 +1598,7 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, "requires": { "esutils": "2.0.2", "isarray": "1.0.0" @@ -1596,7 +1609,8 @@ "eslint-restricted-globals": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true }, "eslint-scope": { "version": "3.7.1", @@ -1698,6 +1712,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, "requires": { "path-exists": "2.1.0", "pinkie-promise": "2.0.1" @@ -1722,7 +1737,8 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "functional-red-black-tree": { "version": "1.0.1", @@ -1769,6 +1785,7 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, "requires": { "function-bind": "1.1.1" } @@ -1789,7 +1806,8 @@ "hosted-git-info": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==" + "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==", + "dev": true }, "iconv-lite": { "version": "0.4.23", @@ -1847,12 +1865,14 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true }, "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, "requires": { "builtin-modules": "1.1.1" } @@ -1940,6 +1960,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, "requires": { "graceful-fs": "4.1.11", "parse-json": "2.2.0", @@ -1951,6 +1972,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, "requires": { "p-locate": "2.0.0", "path-exists": "3.0.0" @@ -1959,7 +1981,8 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true } } }, @@ -2003,6 +2026,11 @@ "minimist": "0.0.8" } }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, "ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -2022,6 +2050,7 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, "requires": { "hosted-git-info": "2.6.1", "is-builtin-module": "1.0.0", @@ -2072,6 +2101,7 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, "requires": { "p-try": "1.0.0" } @@ -2080,6 +2110,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, "requires": { "p-limit": "1.3.0" } @@ -2087,12 +2118,14 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, "requires": { "error-ex": "1.3.2" } @@ -2101,6 +2134,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, "requires": { "pinkie-promise": "2.0.1" } @@ -2118,12 +2152,14 @@ "path-parse": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, "requires": { "pify": "2.3.0" } @@ -2150,6 +2186,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, "requires": { "find-up": "1.1.2" } @@ -2183,6 +2220,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, "requires": { "load-json-file": "2.0.0", "normalize-package-data": "2.4.0", @@ -2193,6 +2231,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, "requires": { "find-up": "2.1.0", "read-pkg": "2.0.0" @@ -2202,6 +2241,7 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, "requires": { "locate-path": "2.0.0" } @@ -2240,6 +2280,7 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", + "dev": true, "requires": { "path-parse": "1.0.5" } @@ -2332,6 +2373,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "dev": true, "requires": { "spdx-expression-parse": "3.0.0", "spdx-license-ids": "3.0.0" @@ -2340,12 +2382,14 @@ "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", + "dev": true }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, "requires": { "spdx-exceptions": "2.1.0", "spdx-license-ids": "3.0.0" @@ -2354,7 +2398,8 @@ "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", + "dev": true }, "sprintf-js": { "version": "1.0.3", @@ -2396,7 +2441,8 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true }, "strip-json-comments": { "version": "2.0.1", @@ -2466,6 +2512,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "dev": true, "requires": { "spdx-correct": "3.0.0", "spdx-expression-parse": "3.0.0" diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ef54be28e9..7a79313df7 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -7,6 +7,7 @@ "amplify-category-storage": "file:../amplify-category-storage", "eslint": "^4.19.1", "inquirer": "^3.2.1", + "moment": "^2.22.2", "uuid": "^2.0.3" }, "scripts": { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index 62652a2fc2..b2fe03de5d 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -15,7 +15,44 @@ Resources: Type: "AWS::AppSync::GraphQLApi" Properties: Name: <%= props.apiName %> + <%if (props.securitySetting.type == 'iam') { %> AuthenticationType: AWS_IAM + <% } %> + <%if (props.securitySetting.type == 'apiKey') { %> + AuthenticationType: API_KEY + <% } %> + <%if (props.securitySetting.type == 'cognito') { %> + AuthenticationType: AMAZON_COGNITO_USER_POOLS + UserPoolConfig: + AwsRegion: <%= props.region %> + UserPoolId: <%= props.securitySetting.options.cognitoUserPoolId %> + DefaultAction: <%= props.securitySetting.options.cognitoAction %> + <%if (props.securitySetting.options.appClientRegex) { %> + AppIdClientRegex: <%= props.securitySetting.options.appClientRegex %> + <% } %> + <% } %> + <%if (props.securitySetting.type == 'openId') { %> + AuthenticationType: OPENID_CONNECT + OpenIDConnectConfig: + Issuer: <%= props.securitySetting.options.openIdUrl %> + <%if (props.securitySetting.options.clientId) { %> + ClientId: <%= props.securitySetting.options.clientId %> + <% } %> + <%if (props.securitySetting.options.issueTTL) { %> + IatTTL: <%= props.securitySetting.options.issueTTL %> + <% } %> + <%if (props.securitySetting.options.authTTL) { %> + AuthTTL: <%= props.securitySetting.options.authTTL %> + <% } %> + <% } %> + + <%if (props.securitySetting.type == 'apiKey') { %> + AppSyncApiKey: + Type: "AWS::AppSync::ApiKey" + Properties: + Expires: <%= props.securitySetting.options.apiKeyExpiryDays %> + ApiId: !GetAtt GraphQLApi.ApiId + <% } %> ServiceRole: Type: 'AWS::IAM::Role' @@ -30,7 +67,6 @@ Resources: Service: appsync.amazonaws.com Action: 'sts:AssumeRole' <%if (props.dataSources && props.dataSources.dynamoDb) { %> - ServicePolicyDynamo: Type: 'AWS::IAM::Policy' Properties: @@ -79,4 +115,8 @@ Outputs: Value: !GetAtt GraphQLApi.ApiId GraphQLApiEndpoint: Description: The URL for the GraphQL endpoint. - Value: !GetAtt GraphQLApi.GraphQLUrl \ No newline at end of file + Value: !GetAtt GraphQLApi.GraphQLUrl + <%if (props.securitySetting.type == 'apiKey') { %> + ApiKey: + Value: !GetAtt AppSyncApiKey.ApiKey + <% } %> diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js index 9d2677d02b..a0ed9b48fe 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js @@ -12,7 +12,7 @@ const getAllDefaults = (project) => { region, defaultTableName: `Posts${shortId}`, }; - + return defaults; }; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index 74769d2a61..14e44ebc15 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -36,7 +36,7 @@ function addResource(context, category, service, options) { return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) .then((result) => { if (result.answers) { - ({ answers } = result.answers); + ({ answers } = result); options.dependsOn = result.dependsOn; } else { answers = result; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index f6c9f80e31..9c42e48994 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,54 +1,55 @@ const inquirer = require('inquirer'); +const moment = require('moment'); -function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { +async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { const { amplify } = context; const { inputs } = serviceMetadata; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - const questions = []; - for (let i = 0; i < 3; i += 1) { - let question = { - name: inputs[i].key, - message: inputs[i].question, - validate: amplify.inputValidation(inputs[i]), + + const resourceQuestions = [ + { + type: inputs[0].type, + name: inputs[0].key, + message: inputs[0].question, + validate: amplify.inputValidation(inputs[0]), default: () => { - const defaultValue = allDefaultValues[inputs[i].key]; + const defaultValue = getAllDefaults(amplify.getProjectDetails())[inputs[0].key]; return defaultValue; }, - }; - - if (inputs[i].type && inputs[i].type === 'list') { - question = Object.assign({ - type: 'list', - choices: inputs[i].options, - }, question); - } else if (inputs[i].type && inputs[i].type === 'multiselect') { - question = Object.assign({ - type: 'checkbox', - choices: inputs[i].options, - }, question); - } else { - question = Object.assign({ - type: 'input', - }, question); - } - questions.push(question); + }, + { + type: inputs[1].type, + name: inputs[1].key, + message: inputs[1].question, + validate: amplify.inputValidation(inputs[1]), + default: answers => answers.resourceName, + }, + { + type: inputs[2].type, + name: inputs[2].key, + message: inputs[2].question, + choices: inputs[2].options, + validate: amplify.inputValidation(inputs[2]), + }, + ]; + + // Ask resource and API name question + + const resourceAnswers = await inquirer.prompt(resourceQuestions); + Object.assign(allDefaultValues, resourceAnswers); + + if (resourceAnswers[inputs[2].key] === 'default') { + return allDefaultValues; } - return inquirer.prompt(questions) - .then((answers) => { - if (answers.templateSelection === 'default') { - Object.assign(allDefaultValues, answers); - return allDefaultValues; - } - return askCustomQuestions(context, inputs) - .then((result) => { - Object.assign(allDefaultValues, result.answers); - allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; - return { answers: allDefaultValues, dependsOn: result.dependsOn }; - }); + return askCustomQuestions(context, inputs) + .then((result) => { + Object.assign(allDefaultValues, result.answers); + allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; + return { answers: allDefaultValues, dependsOn: result.dependsOn }; }); } @@ -56,22 +57,142 @@ async function askCustomQuestions(context, inputs) { const answers = {}; let dependsOn = []; + const securitySetting = await askSecurityQuestions(context, inputs); + Object.assign(answers, { securitySetting }); + if (await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { const dataSourceAnswers = await askDataSourceQuestions(context, inputs); const { dataSources } = dataSourceAnswers; - ({ dependsOn } = dataSourceAnswers.dependsOn); + ({ dependsOn } = dataSourceAnswers); Object.assign(answers, { dataSources }); Object.assign(answers, { dependsOn }); } return { answers, dependsOn }; } -async function askDataSourceQuestions(context, inputs) { - const dataSourceTypeQuestion = { + +async function askSecurityQuestions(context, inputs) { + const securityTypeQuestion = { type: inputs[3].type, name: inputs[3].key, message: inputs[3].question, choices: inputs[3].options, }; + + const securitySetting = {}; + + const securityTypeAnswer = await inquirer.prompt([securityTypeQuestion]); + securitySetting.type = securityTypeAnswer[inputs[3].key]; + + switch (securityTypeAnswer[inputs[3].key]) { + case 'cognito': securitySetting.options = await askCognitoQuestions(context, inputs); + break; + case 'openId': securitySetting.options = await askOpenIdQuestions(context, inputs); + break; + case 'apiKey': securitySetting.options = await askApiKeyQuestions(context, inputs); + break; + case 'iam': break; + default: context.print.error('Invalid option'); + } + + return securitySetting; +} + +async function askCognitoQuestions(context, inputs) { + const { amplify } = context; + + + const userPoolIdQuestion = { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + validate: amplify.inputValidation(inputs[4]), + }; + + const defaultActionQuestion = { + type: inputs[5].type, + name: inputs[5].key, + message: inputs[5].question, + choices: inputs[5].options, + validate: amplify.inputValidation(inputs[5]), + }; + + const appIdClientRegexQuestion = { + type: inputs[6].type, + name: inputs[6].key, + message: inputs[6].question, + validate: amplify.inputValidation(inputs[6]), + }; + + return await inquirer.prompt([userPoolIdQuestion, + defaultActionQuestion, + appIdClientRegexQuestion]); +} + +async function askOpenIdQuestions(context, inputs) { + const { amplify } = context; + + const openIdDomainQuestion = { + type: inputs[7].type, + name: inputs[7].key, + message: inputs[7].question, + validate: amplify.inputValidation(inputs[7]), + }; + + const clientIdQuestion = { + type: inputs[8].type, + name: inputs[8].key, + message: inputs[8].question, + validate: amplify.inputValidation(inputs[8]), + }; + + const issueTTLQuestion = { + type: inputs[9].type, + name: inputs[9].key, + message: inputs[9].question, + validate: amplify.inputValidation(inputs[9]), + default: 0, + }; + + const authTTLQuestion = { + type: inputs[10].type, + name: inputs[10].key, + message: inputs[10].question, + validate: amplify.inputValidation(inputs[10]), + default: 0, + }; + + return await inquirer.prompt([openIdDomainQuestion, + clientIdQuestion, + issueTTLQuestion, + authTTLQuestion]); +} + +async function askApiKeyQuestions(context, inputs) { + const apiKeyExpiryQuestion = { + type: inputs[11].type, + name: inputs[11].key, + message: inputs[11].question, + validate: answer => new Promise((resolve, reject) => { + if (!answer || Number.isNaN(answer) || Number(answer) <= 0 || Number(answer) > 365) { + reject(new Error('The number of days should be set between 1 to 365')); + } + resolve(true); + }), + }; + + const apiKeyExpiryAnswer = await inquirer.prompt([apiKeyExpiryQuestion]); + apiKeyExpiryAnswer[inputs[11].key] = moment().add(Number(apiKeyExpiryAnswer[inputs[11].key]), 'days').unix(); + context.print.info(`Expiry date of the API key set to: ${moment.unix(apiKeyExpiryAnswer[inputs[11].key]).local().format('YYYY-MM-DD HH:mm:ss')}`); + return apiKeyExpiryAnswer; +} + +async function askDataSourceQuestions(context, inputs) { + const dataSourceTypeQuestion = { + type: inputs[12].type, + name: inputs[12].key, + message: inputs[12].question, + choices: inputs[12].options, + }; const dataSources = {}; const dependsOn = []; let continueDataSourcesQuestion = true; @@ -80,7 +201,7 @@ async function askDataSourceQuestions(context, inputs) { while (continueDataSourcesQuestion) { const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); - switch (dataSourceAnswer[inputs[3].key]) { + switch (dataSourceAnswer[inputs[12].key]) { case 'DynamoDb': { const resourceName = await askDynamoDBQuestions(context, inputs); if (!dataSources.dynamoDb) { @@ -105,14 +226,14 @@ async function askDataSourceQuestions(context, inputs) { async function askDynamoDBQuestions(context, inputs) { const dynamoDbTypeQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: inputs[4].options, + type: inputs[13].type, + name: inputs[13].key, + message: inputs[13].question, + choices: inputs[13].options, }; - const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); while (true) { - switch (dynamoDbTypeAnswer[inputs[4].key]) { + const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); + switch (dynamoDbTypeAnswer[inputs[13].key]) { case 'currentProject': { const storageResources = context.amplify.getProjectDetails().amplifyMeta.storage; const dynamoDbProjectResources = []; @@ -126,18 +247,24 @@ async function askDynamoDBQuestions(context, inputs) { break; } const dynamoResourceQuestion = { - type: inputs[5].type, - name: inputs[5].key, - message: inputs[5].question, + type: inputs[14].type, + name: inputs[14].key, + message: inputs[14].question, choices: dynamoDbProjectResources, }; const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); - return dynamoResourceAnswer[inputs[5].key]; + return dynamoResourceAnswer[inputs[14].key]; } case 'newResource': { - const { add } = require('amplify-category-storage'); + let add; + try { + ({ add } = require('amplify-category-storage')); + } catch (e) { + context.print.error('Storage plugin not installed in the CLI. Please install it to use this feature'); + break; + } return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') .then((resourceName) => { context.print.success('Succesfully added DynamoDb table localy'); diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index cfcce64ad4..78a70a868b 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -1,7 +1,6 @@ { "AppSync": { - "inputs": [ - { + "inputs": [{ "key": "resourceName", "type": "input", "question": "Please provide a friendly name for your resource that will be used to label this category in the project:", @@ -29,22 +28,116 @@ "key": "templateSelection", "type": "list", "question": "Choose from one of the options below", - "options": [ - { "name": "Use sample AppSync-DynamoDB example cloudformation template", - "value": "default" - }, - { - "name": "Use custom AppSync cloudformation template", - "value": "custom" + "options": [{ + "name": "Use sample AppSync-DynamoDB example cloudformation template", + "value": "default" + }, + { + "name": "Use custom AppSync cloudformation template", + "value": "custom" + } + ], + "required": true + }, + { + + "key": "authType", + "type": "list", + "question": "Choose an authorization type for the API", + "options": [{ + "name": "API key", + "value": "apiKey" + }, + { + "name": "AWS Identity and Access Management (IAM)", + "value": "iam" + }, + { + "name": "Amazon Cognito User Pool", + "value": "cognito" + }, + { + "name": "OpenID Connect", + "value": "openId" } + ], "required": true }, + { + + "key": "cognitoUserPoolId", + "type": "input", + "question": "Please provide a user pool ID:", + "validation": { + "operator": "regex", + "value": "^[a-zA-Z0-9._-]+$", + "onErrorMsg": "You can use the following characters: a-z A-Z 0-9 . - _" + }, + "required": true + }, + { + + "key": "cognitoAction", + "type": "list", + "question": "Select the default permission for requests to your API", + "options": [ + "ALLOW", + "DENY" + ] + }, + { + + "key": "appClientRegex", + "type": "input", + "question": "Type a regular expression to allow or block requests to this API (Optional)" + }, + { + + "key": "openIdUrl", + "type": "input", + "question": "Please provide the URL of your OpenID Connect provider used for discovery:", + "required": true + }, + { + + "key": "clientId", + "type": "input", + "question": "Please provide a client id from your OpenID Client Connect application to only allow tokens from that application(Optional):" + }, + { + + "key": "issueTTL", + "type": "input", + "question": "Please provide the number of milliseconds a token is valid for after being issued to a user. Set to 0 to disable(Optional):", + "validation": { + "operator": "regex", + "value": "^[0-9]+$", + "onErrorMsg": "Value entered can only be numeric" + } + }, + { + + "key": "authTTL", + "type": "input", + "question": "Please provide the number of milliseconds a token is valid for after being authenticated. Set to 0 to disable(Optional):", + "validation": { + "operator": "regex", + "value": "^[0-9]+$", + "onErrorMsg": "Value entered can only be numeric" + } + }, + { + + "key": "apiKeyExpiryDays", + "type": "input", + "question": "Please provide the days after which the api key would be invalid (with a minimum of 1 day and a maximum of 365 days):" + }, { "key": "dataSourceType", "type": "list", - "question": "Choose a data source you would like to add to your GraphQL API", + "question": "Choose a data source you would like to add to your AppSync API", "options": [ "DynamoDb", "Lambda", @@ -56,13 +149,13 @@ "key": "dynamoDbType", "type": "list", "question": "Choose a DynamoDB data source option", - "options": [ - { "name": "Use DynamoDB table configured in the current Amplify project", - "value": "currentProject" - }, - { - "name": "Create a new DynamoDB table", - "value": "newResource" + "options": [{ + "name": "Use DynamoDB table configured in the current Amplify project", + "value": "currentProject" + }, + { + "name": "Create a new DynamoDB table", + "value": "newResource" } ] }, @@ -70,7 +163,7 @@ "key": "dynamoDbResources", "type": "list", - "question": "Choose from one of the already configured DynamoDB tables" + "question": "Choose from one of the already configured DynamoDB tables" } ], "defaultValuesFilename": "appSync-defaults.js", From f09bb37db0581b2226e4b079361545ee3064a18f Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 2 Jul 2018 19:03:05 -0700 Subject: [PATCH 006/587] Expose utility functions from the provider available to the category plugins --- .../amplify-category-api/commands/api/add.js | 1 + .../appSync-walkthrough.js | 117 +++++++++++------- .../provider-utils/supported-services.json | 10 +- 3 files changed, 81 insertions(+), 47 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 31d86c8eef..c4317deafc 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -22,6 +22,7 @@ module.exports = { context.print.error('Provider not configured for this category'); return; } + return providerController.addResource(context, category, result.service, options); }) .then(() => context.print.success('Successfully added resource')) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 9c42e48994..356a8b767f 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -79,19 +79,24 @@ async function askSecurityQuestions(context, inputs) { }; const securitySetting = {}; + while (true) { + const securityTypeAnswer = await inquirer.prompt([securityTypeQuestion]); + securitySetting.type = securityTypeAnswer[inputs[3].key]; - const securityTypeAnswer = await inquirer.prompt([securityTypeQuestion]); - securitySetting.type = securityTypeAnswer[inputs[3].key]; - - switch (securityTypeAnswer[inputs[3].key]) { - case 'cognito': securitySetting.options = await askCognitoQuestions(context, inputs); - break; - case 'openId': securitySetting.options = await askOpenIdQuestions(context, inputs); - break; - case 'apiKey': securitySetting.options = await askApiKeyQuestions(context, inputs); + switch (securityTypeAnswer[inputs[3].key]) { + case 'cognito': securitySetting.options = await askCognitoQuestions(context, inputs); + break; + case 'openId': securitySetting.options = await askOpenIdQuestions(context, inputs); + break; + case 'apiKey': securitySetting.options = await askApiKeyQuestions(context, inputs); + break; + case 'iam': securitySetting.options = {}; + break; + default: context.print.error('Invalid option'); + } + if (securitySetting.options) { break; - case 'iam': break; - default: context.print.error('Invalid option'); + } } return securitySetting; @@ -100,29 +105,51 @@ async function askSecurityQuestions(context, inputs) { async function askCognitoQuestions(context, inputs) { const { amplify } = context; + const regions = await amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); - const userPoolIdQuestion = { + const regionQuestion = { type: inputs[4].type, name: inputs[4].key, message: inputs[4].question, - validate: amplify.inputValidation(inputs[4]), + choices: regions, }; - const defaultActionQuestion = { + const regionAnswer = await inquirer.prompt([regionQuestion]); + + const userPools = await amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getUserPools', { region: regionAnswer[inputs[4].key] }); + + const userPoolOptions = userPools.map(userPool => ({ + value: userPool.Id, + name: `${userPool.Id}(${userPool.Name})`, + })); + + if (userPoolOptions.length === 0) { + context.print.error('You do not have any user pools configured for the selected region'); + return; + } + + const userPoolIdQuestion = { type: inputs[5].type, name: inputs[5].key, message: inputs[5].question, - choices: inputs[5].options, - validate: amplify.inputValidation(inputs[5]), + choices: userPoolOptions, }; - const appIdClientRegexQuestion = { + const defaultActionQuestion = { type: inputs[6].type, name: inputs[6].key, message: inputs[6].question, + choices: inputs[6].options, validate: amplify.inputValidation(inputs[6]), }; + const appIdClientRegexQuestion = { + type: inputs[7].type, + name: inputs[7].key, + message: inputs[7].question, + validate: amplify.inputValidation(inputs[7]), + }; + return await inquirer.prompt([userPoolIdQuestion, defaultActionQuestion, appIdClientRegexQuestion]); @@ -132,28 +159,20 @@ async function askOpenIdQuestions(context, inputs) { const { amplify } = context; const openIdDomainQuestion = { - type: inputs[7].type, - name: inputs[7].key, - message: inputs[7].question, - validate: amplify.inputValidation(inputs[7]), - }; - - const clientIdQuestion = { type: inputs[8].type, name: inputs[8].key, message: inputs[8].question, validate: amplify.inputValidation(inputs[8]), }; - const issueTTLQuestion = { + const clientIdQuestion = { type: inputs[9].type, name: inputs[9].key, message: inputs[9].question, validate: amplify.inputValidation(inputs[9]), - default: 0, }; - const authTTLQuestion = { + const issueTTLQuestion = { type: inputs[10].type, name: inputs[10].key, message: inputs[10].question, @@ -161,6 +180,14 @@ async function askOpenIdQuestions(context, inputs) { default: 0, }; + const authTTLQuestion = { + type: inputs[11].type, + name: inputs[11].key, + message: inputs[11].question, + validate: amplify.inputValidation(inputs[11]), + default: 0, + }; + return await inquirer.prompt([openIdDomainQuestion, clientIdQuestion, issueTTLQuestion, @@ -169,11 +196,11 @@ async function askOpenIdQuestions(context, inputs) { async function askApiKeyQuestions(context, inputs) { const apiKeyExpiryQuestion = { - type: inputs[11].type, - name: inputs[11].key, - message: inputs[11].question, + type: inputs[12].type, + name: inputs[12].key, + message: inputs[12].question, validate: answer => new Promise((resolve, reject) => { - if (!answer || Number.isNaN(answer) || Number(answer) <= 0 || Number(answer) > 365) { + if (!answer || Number.isNaN(Number(answer)) || Number(answer) <= 0 || Number(answer) > 365) { reject(new Error('The number of days should be set between 1 to 365')); } resolve(true); @@ -188,10 +215,10 @@ async function askApiKeyQuestions(context, inputs) { async function askDataSourceQuestions(context, inputs) { const dataSourceTypeQuestion = { - type: inputs[12].type, - name: inputs[12].key, - message: inputs[12].question, - choices: inputs[12].options, + type: inputs[13].type, + name: inputs[13].key, + message: inputs[13].question, + choices: inputs[13].options, }; const dataSources = {}; const dependsOn = []; @@ -201,7 +228,7 @@ async function askDataSourceQuestions(context, inputs) { while (continueDataSourcesQuestion) { const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); - switch (dataSourceAnswer[inputs[12].key]) { + switch (dataSourceAnswer[inputs[13].key]) { case 'DynamoDb': { const resourceName = await askDynamoDBQuestions(context, inputs); if (!dataSources.dynamoDb) { @@ -226,14 +253,14 @@ async function askDataSourceQuestions(context, inputs) { async function askDynamoDBQuestions(context, inputs) { const dynamoDbTypeQuestion = { - type: inputs[13].type, - name: inputs[13].key, - message: inputs[13].question, - choices: inputs[13].options, + type: inputs[14].type, + name: inputs[14].key, + message: inputs[14].question, + choices: inputs[14].options, }; while (true) { const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); - switch (dynamoDbTypeAnswer[inputs[13].key]) { + switch (dynamoDbTypeAnswer[inputs[14].key]) { case 'currentProject': { const storageResources = context.amplify.getProjectDetails().amplifyMeta.storage; const dynamoDbProjectResources = []; @@ -247,15 +274,15 @@ async function askDynamoDBQuestions(context, inputs) { break; } const dynamoResourceQuestion = { - type: inputs[14].type, - name: inputs[14].key, - message: inputs[14].question, + type: inputs[15].type, + name: inputs[15].key, + message: inputs[15].question, choices: dynamoDbProjectResources, }; const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); - return dynamoResourceAnswer[inputs[14].key]; + return dynamoResourceAnswer[inputs[15].key]; } case 'newResource': { let add; diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 78a70a868b..05d800b546 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -64,11 +64,17 @@ ], "required": true }, + { + + "key": "cognitoUserPoolRegion", + "type": "list", + "question": "Please provide a user pool ID:" + }, { "key": "cognitoUserPoolId", - "type": "input", - "question": "Please provide a user pool ID:", + "type": "list", + "question": "Please select a user pool ID:", "validation": { "operator": "regex", "value": "^[a-zA-Z0-9._-]+$", From eb2b11a2192d41f8bf78c4a997eefc87709340d4 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 2 Jul 2018 20:21:57 -0700 Subject: [PATCH 007/587] Added region for cognito user pool --- .../appSync-cloudformation-template-custom.yml.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index b2fe03de5d..84b92f29ec 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -24,7 +24,7 @@ Resources: <%if (props.securitySetting.type == 'cognito') { %> AuthenticationType: AMAZON_COGNITO_USER_POOLS UserPoolConfig: - AwsRegion: <%= props.region %> + AwsRegion: <%= props.securitySetting.options.region %> UserPoolId: <%= props.securitySetting.options.cognitoUserPoolId %> DefaultAction: <%= props.securitySetting.options.cognitoAction %> <%if (props.securitySetting.options.appClientRegex) { %> From e57005dd4aace1ac6939d24b2ab461f6e0d79173 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 3 Jul 2018 10:40:45 -0700 Subject: [PATCH 008/587] Fix some PR comments --- .../service-walkthroughs/appSync-walkthrough.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 356a8b767f..ffb4b544a5 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -79,7 +79,7 @@ async function askSecurityQuestions(context, inputs) { }; const securitySetting = {}; - while (true) { + while (!securitySetting.options) { const securityTypeAnswer = await inquirer.prompt([securityTypeQuestion]); securitySetting.type = securityTypeAnswer[inputs[3].key]; @@ -94,9 +94,6 @@ async function askSecurityQuestions(context, inputs) { break; default: context.print.error('Invalid option'); } - if (securitySetting.options) { - break; - } } return securitySetting; @@ -120,7 +117,7 @@ async function askCognitoQuestions(context, inputs) { const userPoolOptions = userPools.map(userPool => ({ value: userPool.Id, - name: `${userPool.Id}(${userPool.Name})`, + name: `${userPool.Id} (${userPool.Name})`, })); if (userPoolOptions.length === 0) { From 24ab444ef479ed5a3a493ea2e1fdc85cc6dcc1a3 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 3 Jul 2018 13:55:31 -0700 Subject: [PATCH 009/587] Minor validations and fixes --- .../appSync-cloudformation-template-custom.yml.ejs | 2 +- .../service-walkthroughs/appSync-walkthrough.js | 10 +++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index 84b92f29ec..eee9595a21 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -24,7 +24,7 @@ Resources: <%if (props.securitySetting.type == 'cognito') { %> AuthenticationType: AMAZON_COGNITO_USER_POOLS UserPoolConfig: - AwsRegion: <%= props.securitySetting.options.region %> + AwsRegion: <%= props.securitySetting.options.cognitoUserPoolRegion %> UserPoolId: <%= props.securitySetting.options.cognitoUserPoolId %> DefaultAction: <%= props.securitySetting.options.cognitoAction %> <%if (props.securitySetting.options.appClientRegex) { %> diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index ffb4b544a5..5815b49f0a 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -147,9 +147,12 @@ async function askCognitoQuestions(context, inputs) { validate: amplify.inputValidation(inputs[7]), }; - return await inquirer.prompt([userPoolIdQuestion, + const cognitoAnswers = await inquirer.prompt([userPoolIdQuestion, defaultActionQuestion, appIdClientRegexQuestion]); + Object.assign(cognitoAnswers, regionAnswer); + + return cognitoAnswers; } async function askOpenIdQuestions(context, inputs) { @@ -205,8 +208,9 @@ async function askApiKeyQuestions(context, inputs) { }; const apiKeyExpiryAnswer = await inquirer.prompt([apiKeyExpiryQuestion]); - apiKeyExpiryAnswer[inputs[11].key] = moment().add(Number(apiKeyExpiryAnswer[inputs[11].key]), 'days').unix(); - context.print.info(`Expiry date of the API key set to: ${moment.unix(apiKeyExpiryAnswer[inputs[11].key]).local().format('YYYY-MM-DD HH:mm:ss')}`); + apiKeyExpiryAnswer[inputs[12].key] = moment().add(Number(apiKeyExpiryAnswer[inputs[12].key]), 'days').unix(); + console.log(apiKeyExpiryAnswer); + context.print.info(`Expiry date of the API key set to: ${moment.unix(apiKeyExpiryAnswer[inputs[12].key]).local().format('YYYY-MM-DD HH:mm:ss')}`); return apiKeyExpiryAnswer; } From f0948093db3c2ffb6ab673d3f18c5d1265b28405 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 3 Jul 2018 13:58:22 -0700 Subject: [PATCH 010/587] Remove console statement --- .../service-walkthroughs/appSync-walkthrough.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 5815b49f0a..f956523d6e 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -209,7 +209,6 @@ async function askApiKeyQuestions(context, inputs) { const apiKeyExpiryAnswer = await inquirer.prompt([apiKeyExpiryQuestion]); apiKeyExpiryAnswer[inputs[12].key] = moment().add(Number(apiKeyExpiryAnswer[inputs[12].key]), 'days').unix(); - console.log(apiKeyExpiryAnswer); context.print.info(`Expiry date of the API key set to: ${moment.unix(apiKeyExpiryAnswer[inputs[12].key]).local().format('YYYY-MM-DD HH:mm:ss')}`); return apiKeyExpiryAnswer; } From 58447a252ea60ccc331e4039381c0211219e9d88 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 3 Jul 2018 16:00:56 -0700 Subject: [PATCH 011/587] through lint --- .../amplify-category-api/package-lock.json | 68 ++++--------------- 1 file changed, 13 insertions(+), 55 deletions(-) diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json index 7405c3d9de..242b26571f 100644 --- a/packages/amplify-category-api/package-lock.json +++ b/packages/amplify-category-api/package-lock.json @@ -1,8 +1,6 @@ { - "name": "amplify-category-api", - "version": "0.1.0", - "lockfileVersion": 1, "requires": true, + "lockfileVersion": 1, "dependencies": { "acorn": { "version": "5.7.1", @@ -1300,8 +1298,7 @@ "builtin-modules": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" }, "caller-path": { "version": "0.1.0", @@ -1404,8 +1401,7 @@ "contains-path": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" }, "core-util-is": { "version": "1.0.2", @@ -1461,7 +1457,6 @@ "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "0.2.1" } @@ -1520,7 +1515,6 @@ "version": "12.1.0", "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", - "dev": true, "requires": { "eslint-restricted-globals": "0.1.1" } @@ -1529,7 +1523,6 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "dev": true, "requires": { "debug": "2.6.9", "resolve": "1.8.1" @@ -1539,7 +1532,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1550,7 +1542,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "dev": true, "requires": { "debug": "2.6.9", "pkg-dir": "1.0.0" @@ -1560,7 +1551,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1571,7 +1561,6 @@ "version": "2.13.0", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", - "dev": true, "requires": { "contains-path": "0.1.0", "debug": "2.6.9", @@ -1589,7 +1578,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, "requires": { "ms": "2.0.0" } @@ -1598,7 +1586,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, "requires": { "esutils": "2.0.2", "isarray": "1.0.0" @@ -1609,8 +1596,7 @@ "eslint-restricted-globals": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", - "dev": true + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" }, "eslint-scope": { "version": "3.7.1", @@ -1712,7 +1698,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, "requires": { "path-exists": "2.1.0", "pinkie-promise": "2.0.1" @@ -1737,8 +1722,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "functional-red-black-tree": { "version": "1.0.1", @@ -1785,7 +1769,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "1.1.1" } @@ -1806,8 +1789,7 @@ "hosted-git-info": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==", - "dev": true + "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==" }, "iconv-lite": { "version": "0.4.23", @@ -1865,14 +1847,12 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-builtin-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, "requires": { "builtin-modules": "1.1.1" } @@ -1960,7 +1940,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, "requires": { "graceful-fs": "4.1.11", "parse-json": "2.2.0", @@ -1972,7 +1951,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, "requires": { "p-locate": "2.0.0", "path-exists": "3.0.0" @@ -1981,8 +1959,7 @@ "path-exists": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" } } }, @@ -2050,7 +2027,6 @@ "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "dev": true, "requires": { "hosted-git-info": "2.6.1", "is-builtin-module": "1.0.0", @@ -2101,7 +2077,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "dev": true, "requires": { "p-try": "1.0.0" } @@ -2110,7 +2085,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, "requires": { "p-limit": "1.3.0" } @@ -2118,14 +2092,12 @@ "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" }, "parse-json": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, "requires": { "error-ex": "1.3.2" } @@ -2134,7 +2106,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, "requires": { "pinkie-promise": "2.0.1" } @@ -2152,14 +2123,12 @@ "path-parse": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" }, "path-type": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, "requires": { "pify": "2.3.0" } @@ -2186,7 +2155,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, "requires": { "find-up": "1.1.2" } @@ -2220,7 +2188,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, "requires": { "load-json-file": "2.0.0", "normalize-package-data": "2.4.0", @@ -2231,7 +2198,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, "requires": { "find-up": "2.1.0", "read-pkg": "2.0.0" @@ -2241,7 +2207,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, "requires": { "locate-path": "2.0.0" } @@ -2280,7 +2245,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "dev": true, "requires": { "path-parse": "1.0.5" } @@ -2373,7 +2337,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "dev": true, "requires": { "spdx-expression-parse": "3.0.0", "spdx-license-ids": "3.0.0" @@ -2382,14 +2345,12 @@ "spdx-exceptions": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==", - "dev": true + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" }, "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, "requires": { "spdx-exceptions": "2.1.0", "spdx-license-ids": "3.0.0" @@ -2398,8 +2359,7 @@ "spdx-license-ids": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==", - "dev": true + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" }, "sprintf-js": { "version": "1.0.3", @@ -2441,8 +2401,7 @@ "strip-bom": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" }, "strip-json-comments": { "version": "2.0.1", @@ -2512,7 +2471,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "dev": true, "requires": { "spdx-correct": "3.0.0", "spdx-expression-parse": "3.0.0" From d228449338b435d444227631e0f1e6ecd29945d1 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 5 Jul 2018 12:09:43 -0700 Subject: [PATCH 012/587] Lambda/Function feature --- .../amplify-category-api/package-lock.json | 2511 ----------------- packages/amplify-category-api/package.json | 12 +- 2 files changed, 6 insertions(+), 2517 deletions(-) delete mode 100644 packages/amplify-category-api/package-lock.json diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json deleted file mode 100644 index 242b26571f..0000000000 --- a/packages/amplify-category-api/package-lock.json +++ /dev/null @@ -1,2511 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha512-d+nbxBUGKg7Arpsvbnlq61mc12ek3EY8EQldM3GPAhWJ1UVxC6TDGbIvUMNU6obBX3i1+ptCIzV4vq0gFPEGVQ==" - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" - } - } - }, - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" - }, - "amplify-category-storage": { - "version": "file:../amplify-category-storage", - "requires": { - "eslint": "4.19.1", - "inquirer": "3.3.0", - "uuid": "2.0.3" - }, - "dependencies": { - "acorn": { - "version": "5.6.2", - "bundled": true - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "ansi-escapes": { - "version": "3.1.0", - "bundled": true - }, - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "argparse": { - "version": "1.0.10", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.1.0", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.1", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "doctrine": { - "version": "2.1.0", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "eslint": { - "version": "4.19.1", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.5.0", - "ignore": "3.3.8", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "bundled": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "bundled": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "bundled": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.12.0", - "bundled": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "bundled": true - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.4", - "bundled": true, - "requires": { - "acorn": "5.6.2", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "external-editor": { - "version": "2.2.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.5.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.8", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.1.0", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.12.0", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "p-limit": { - "version": "1.3.0", - "bundled": true, - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "regexpp": { - "version": "1.1.0", - "bundled": true - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.7.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "3.0.0" - } - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "2.0.3", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "yallist": { - "version": "2.1.2", - "bundled": true - } - } - }, - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha512-UgAb8H9D41AQnu/PbWlCofQVcnV4Gs2bBJi9eZPxfU/hgglFh3SMDMENRIqdr7H6XFnXdoknctFByVsCOotTVw==" - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - } - } - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha512-c5mRlguI/Pe2dSZmpER62rSCu0ryKmWddzRYsuXc50U2/g8jMOulc31VZMa4mYx31U5xsmSOpDCgH88Vl9cDGQ==" - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - }, - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "requires": { - "color-convert": "1.9.2" - } - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==", - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" - }, - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==" - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==", - "requires": { - "color-name": "1.1.1" - } - }, - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "requires": { - "esutils": "2.0.2" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", - "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha512-sfmTqJfPSizWu4aymbPr4Iidp5yKm8yDkHp+Ir3YiTHiiDfxh69mOUsmiqW6RZ9zRXFaF64GtYmN7e+8GHBv6Q==", - "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", - "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==" - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==", - "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==" - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==", - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A==", - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha512-K8BNSPySfeShBQXsahYB/AbbWruVOTyVpgoIDnl8odPpeSfP2J5QO2oLFFdl2j7GfDCtZj2bMKar2T49itTPCg==" - }, - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - }, - "hosted-git-info": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha512-Ba4+0M4YvIDUUsprMjhVTU1yN9F2/LJSAl69ZpzaLT4l4j5mwTS6jqqW9Ojvj6lKz/veqPzpJBqGbXspOb533A==" - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha512-UejweD1pDoXu+AD825lWwp4ZGtSwgnpZxb3JDViD7StjQz+Nb/6l093lx4OQ0foGWNRoc19mWy7BzL+UAK2iVg==" - }, - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", - "requires": { - "hosted-git-info": "2.6.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "1.3.2" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "2.3.0" - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==" - }, - "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha512-LOPw8FpgdQF9etWMaAfG/WRthIdXJGYp4mJ2Jgn/2lpkbod9jPn0t9UqN7AxBOKNfzRbYyVfgc7Vk4t/MpnXgw==" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha512-AicPrAC7Qu1JxPCZ9ZgCZlY35QgFnNqc+0LtbRNxnVw4TXvjQ72wnuL9JQcEBgXkI9JM8MsT9kaQoHcpCRJOYA==", - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" - }, - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "requires": { - "mkdirp": "0.5.1" - } - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } -} diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7a79313df7..4a2029137e 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -3,18 +3,18 @@ "version": "0.1.0", "description": "amplify-cli api plugin", "main": "index.js", + "license": "Apache-2.0", + "scripts": { + "lint": "eslint .", + "lint-fix": "eslint . --fix" + }, "dependencies": { "amplify-category-storage": "file:../amplify-category-storage", - "eslint": "^4.19.1", + "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", "uuid": "^2.0.3" }, - "scripts": { - "lint": "eslint .", - "lint-fix": "eslint . --fix" - }, - "license": "Apache-2.0", "devDependencies": { "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" From 4c4fd510739f6ff8ba5e1230e6da63d27a30c7b0 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 5 Jul 2018 18:51:23 -0700 Subject: [PATCH 013/587] Use Lambda as a data source with AppSync --- .../amplify-category-api/package-lock.json | 6420 +++++++++++++++++ packages/amplify-category-api/package.json | 1 + ...ync-cloudformation-template-custom.yml.ejs | 33 + .../appSync-walkthrough.js | 65 + .../provider-utils/supported-services.json | 21 + 5 files changed, 6540 insertions(+) create mode 100644 packages/amplify-category-api/package-lock.json diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json new file mode 100644 index 0000000000..2dc4d6c763 --- /dev/null +++ b/packages/amplify-category-api/package-lock.json @@ -0,0 +1,6420 @@ +{ + "name": "amplify-category-api", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "amplify-category-function": { + "version": "file:../amplify-category-function", + "requires": { + "eslint": "4.19.1", + "grunt": "1.0.3", + "grunt-aws-lambda": "0.13.0", + "inquirer": "3.3.0", + "uuid": "3.3.2" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "acorn": { + "version": "5.7.1", + "bundled": true + }, + "acorn-jsx": { + "version": "3.0.1", + "bundled": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "bundled": true + } + } + }, + "agent-base": { + "version": "4.2.1", + "bundled": true, + "requires": { + "es6-promisify": "5.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "bundled": true + }, + "ansi-escapes": { + "version": "3.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "archiver": { + "version": "0.14.4", + "bundled": true, + "requires": { + "async": "0.9.2", + "buffer-crc32": "0.2.13", + "glob": "4.3.5", + "lazystream": "0.1.0", + "lodash": "3.2.0", + "readable-stream": "1.0.34", + "tar-stream": "1.1.5", + "zip-stream": "0.5.2" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "bundled": true + }, + "glob": { + "version": "4.3.5", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "lodash": { + "version": "3.2.0", + "bundled": true + }, + "minimatch": { + "version": "2.0.10", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "argparse": { + "version": "1.0.10", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-find-index": { + "version": "1.0.2", + "bundled": true + }, + "array-union": { + "version": "1.0.2", + "bundled": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "bundled": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true + }, + "ast-types": { + "version": "0.11.5", + "bundled": true + }, + "async": { + "version": "1.5.2", + "bundled": true + }, + "aws-sdk": { + "version": "2.2.48", + "bundled": true, + "requires": { + "sax": "1.1.5", + "xml2js": "0.4.15", + "xmlbuilder": "2.6.2" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "bl": { + "version": "0.9.5", + "bundled": true, + "requires": { + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "bundled": true + }, + "buffer-from": { + "version": "1.1.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "bytes": { + "version": "3.0.0", + "bundled": true + }, + "caller-path": { + "version": "0.1.0", + "bundled": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "bundled": true + }, + "camelcase": { + "version": "2.1.1", + "bundled": true + }, + "camelcase-keys": { + "version": "2.1.0", + "bundled": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "chardet": { + "version": "0.4.2", + "bundled": true + }, + "circular-json": { + "version": "0.3.3", + "bundled": true + }, + "cli-cursor": { + "version": "2.1.0", + "bundled": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "coffeescript": { + "version": "1.10.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.2", + "bundled": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "bundled": true + }, + "colors": { + "version": "1.1.2", + "bundled": true + }, + "compress-commons": { + "version": "0.2.9", + "bundled": true, + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "0.3.4", + "node-int64": "0.3.3", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "crc32-stream": { + "version": "0.3.4", + "bundled": true, + "requires": { + "buffer-crc32": "0.2.13", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "bundled": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "bundled": true + }, + "dateformat": { + "version": "1.0.12", + "bundled": true, + "requires": { + "get-stdin": "4.0.1", + "meow": "3.7.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "degenerator": { + "version": "1.0.4", + "bundled": true, + "requires": { + "ast-types": "0.11.5", + "escodegen": "1.10.0", + "esprima": "3.1.3" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "bundled": true + } + } + }, + "del": { + "version": "2.2.2", + "bundled": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "depd": { + "version": "1.1.2", + "bundled": true + }, + "doctrine": { + "version": "2.1.0", + "bundled": true, + "requires": { + "esutils": "2.0.2" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es6-promise": { + "version": "4.2.4", + "bundled": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "4.2.4" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "escodegen": { + "version": "1.10.0", + "bundled": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "bundled": true + } + } + }, + "eslint": { + "version": "4.19.1", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "bundled": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "bundled": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "resolve": { + "version": "1.8.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "bundled": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "bundled": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "resolve": { + "version": "1.8.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "bundled": true + }, + "eslint-scope": { + "version": "3.7.1", + "bundled": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "bundled": true + }, + "espree": { + "version": "3.5.4", + "bundled": true, + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "bundled": true + }, + "esquery": { + "version": "1.0.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "eventemitter2": { + "version": "0.4.14", + "bundled": true + }, + "exit": { + "version": "0.1.2", + "bundled": true + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "external-editor": { + "version": "2.2.0", + "bundled": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "figures": { + "version": "2.0.0", + "bundled": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "bundled": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "bundled": true + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findup-sync": { + "version": "0.3.0", + "bundled": true, + "requires": { + "glob": "5.0.15" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "flat-cache": { + "version": "1.3.0", + "bundled": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "ftp": { + "version": "0.3.10", + "bundled": true, + "requires": { + "readable-stream": "1.1.14", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "bundled": true + }, + "get-stdin": { + "version": "4.0.1", + "bundled": true + }, + "get-uri": { + "version": "2.0.2", + "bundled": true, + "requires": { + "data-uri-to-buffer": "1.2.0", + "debug": "2.6.9", + "extend": "3.0.1", + "file-uri-to-path": "1.0.0", + "ftp": "0.3.10", + "readable-stream": "2.3.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "getobject": { + "version": "0.1.0", + "bundled": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.7.0", + "bundled": true + }, + "globby": { + "version": "5.0.0", + "bundled": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "grunt": { + "version": "1.0.3", + "bundled": true, + "requires": { + "coffeescript": "1.10.0", + "dateformat": "1.0.12", + "eventemitter2": "0.4.14", + "exit": "0.1.2", + "findup-sync": "0.3.0", + "glob": "7.0.6", + "grunt-cli": "1.2.0", + "grunt-known-options": "1.1.0", + "grunt-legacy-log": "2.0.0", + "grunt-legacy-util": "1.1.1", + "iconv-lite": "0.4.23", + "js-yaml": "3.5.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "bundled": true + }, + "glob": { + "version": "7.0.6", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "grunt-cli": { + "version": "1.2.0", + "bundled": true, + "requires": { + "findup-sync": "0.3.0", + "grunt-known-options": "1.1.0", + "nopt": "3.0.6", + "resolve": "1.1.7" + } + }, + "js-yaml": { + "version": "3.5.5", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "2.7.3" + } + } + } + }, + "grunt-aws-lambda": { + "version": "0.13.0", + "bundled": true, + "requires": { + "archiver": "0.14.4", + "aws-sdk": "2.2.48", + "glob": "4.3.5", + "mkdirp": "0.5.1", + "npm": "2.15.12", + "proxy-agent": "3.0.0", + "q": "1.5.1", + "rimraf": "2.2.8", + "temporary": "0.0.8" + }, + "dependencies": { + "glob": { + "version": "4.3.5", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "minimatch": { + "version": "2.0.10", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "rimraf": { + "version": "2.2.8", + "bundled": true + } + } + }, + "grunt-known-options": { + "version": "1.1.0", + "bundled": true + }, + "grunt-legacy-log": { + "version": "2.0.0", + "bundled": true, + "requires": { + "colors": "1.1.2", + "grunt-legacy-log-utils": "2.0.1", + "hooker": "0.2.3", + "lodash": "4.17.10" + } + }, + "grunt-legacy-log-utils": { + "version": "2.0.1", + "bundled": true, + "requires": { + "chalk": "2.4.1", + "lodash": "4.17.10" + } + }, + "grunt-legacy-util": { + "version": "1.1.1", + "bundled": true, + "requires": { + "async": "1.5.2", + "exit": "0.1.2", + "getobject": "0.1.0", + "hooker": "0.2.3", + "lodash": "4.17.10", + "underscore.string": "3.3.4", + "which": "1.3.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hooker": { + "version": "0.2.3", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.1", + "bundled": true + }, + "http-errors": { + "version": "1.6.3", + "bundled": true, + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.5.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.10", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "indent-string": { + "version": "2.1.0", + "bundled": true, + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "inquirer": { + "version": "3.3.0", + "bundled": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-path-cwd": { + "version": "1.0.0", + "bundled": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "bundled": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "bundled": true + }, + "is-resolvable": { + "version": "1.1.0", + "bundled": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true + }, + "js-yaml": { + "version": "3.12.0", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "bundled": true + }, + "lazystream": { + "version": "0.1.0", + "bundled": true, + "requires": { + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true + }, + "loud-rejection": { + "version": "1.6.0", + "bundled": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "map-obj": { + "version": "1.0.1", + "bundled": true + }, + "meow": { + "version": "3.7.0", + "bundled": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "natural-compare": { + "version": "1.4.0", + "bundled": true + }, + "netmask": { + "version": "1.0.6", + "bundled": true + }, + "node-int64": { + "version": "0.3.3", + "bundled": true + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "npm": { + "version": "2.15.12", + "bundled": true, + "requires": { + "abbrev": "1.0.9", + "ansi": "0.3.1", + "ansi-regex": "2.0.0", + "ansicolors": "0.3.2", + "ansistyles": "0.1.3", + "archy": "1.0.0", + "async-some": "1.0.2", + "block-stream": "0.0.9", + "char-spinner": "1.0.1", + "chmodr": "1.0.2", + "chownr": "1.0.1", + "cmd-shim": "2.0.2", + "columnify": "1.5.4", + "config-chain": "1.1.10", + "dezalgo": "1.0.3", + "editor": "1.0.0", + "fs-vacuum": "1.2.9", + "fs-write-stream-atomic": "1.0.8", + "fstream": "1.0.10", + "fstream-npm": "1.1.1", + "github-url-from-git": "1.4.0", + "github-url-from-username-repo": "1.0.2", + "glob": "7.0.6", + "graceful-fs": "4.1.6", + "hosted-git-info": "2.1.5", + "imurmurhash": "0.1.4", + "inflight": "1.0.5", + "inherits": "2.0.3", + "ini": "1.3.4", + "init-package-json": "1.9.4", + "lockfile": "1.0.1", + "lru-cache": "4.0.1", + "minimatch": "3.0.3", + "mkdirp": "0.5.1", + "node-gyp": "3.6.0", + "nopt": "3.0.6", + "normalize-git-url": "3.0.2", + "normalize-package-data": "2.3.5", + "npm-cache-filename": "1.0.2", + "npm-install-checks": "1.0.7", + "npm-package-arg": "4.1.0", + "npm-registry-client": "7.2.1", + "npm-user-validate": "0.1.5", + "npmlog": "2.0.4", + "once": "1.4.0", + "opener": "1.4.1", + "osenv": "0.1.3", + "path-is-inside": "1.0.1", + "read": "1.0.7", + "read-installed": "4.0.3", + "read-package-json": "2.0.4", + "readable-stream": "2.1.5", + "realize-package-specifier": "3.0.1", + "request": "2.74.0", + "retry": "0.10.0", + "rimraf": "2.5.4", + "semver": "5.1.0", + "sha": "2.0.1", + "slide": "1.1.6", + "sorted-object": "2.0.0", + "spdx-license-ids": "1.2.2", + "strip-ansi": "3.0.1", + "tar": "2.2.1", + "text-table": "0.2.0", + "uid-number": "0.0.6", + "umask": "1.1.0", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "2.2.2", + "which": "1.2.11", + "wrappy": "1.0.2", + "write-file-atomic": "1.1.4" + }, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "bundled": true + }, + "ansi": { + "version": "0.3.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "async-some": { + "version": "1.0.2", + "bundled": true, + "requires": { + "dezalgo": "1.0.3" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "char-spinner": { + "version": "1.0.1", + "bundled": true + }, + "chmodr": { + "version": "1.0.2", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "mkdirp": "0.5.1" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.0" + }, + "dependencies": { + "wcwidth": { + "version": "1.0.0", + "bundled": true, + "requires": { + "defaults": "1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ini": "1.3.4", + "proto-list": "1.2.4" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "2.0.3", + "wrappy": "1.0.2" + }, + "dependencies": { + "asap": { + "version": "2.0.3", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.9", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "path-is-inside": "1.0.1", + "rimraf": "2.5.4" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.8", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.1.5" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "fstream": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.5.4" + } + }, + "fstream-npm": { + "version": "1.1.1", + "bundled": true, + "requires": { + "fstream-ignore": "1.0.5", + "inherits": "2.0.3" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.10", + "inherits": "2.0.3", + "minimatch": "3.0.3" + } + } + } + }, + "github-url-from-git": { + "version": "1.4.0", + "bundled": true + }, + "github-url-from-username-repo": { + "version": "1.0.2", + "bundled": true + }, + "glob": { + "version": "7.0.6", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.6", + "bundled": true + }, + "hosted-git-info": { + "version": "2.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.5", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.9.4", + "bundled": true, + "requires": { + "glob": "6.0.4", + "npm-package-arg": "4.1.0", + "promzard": "0.3.0", + "read": "1.0.7", + "read-package-json": "2.0.4", + "semver": "5.1.0", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "2.2.2" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1.0.7" + } + } + } + }, + "lockfile": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "4.0.1", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.0.0" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.0.0", + "bundled": true + } + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "node-gyp": { + "version": "3.6.0", + "bundled": true, + "requires": { + "fstream": "1.0.10", + "glob": "7.0.6", + "graceful-fs": "4.1.6", + "minimatch": "3.0.3", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "2.0.4", + "osenv": "0.1.3", + "request": "2.74.0", + "rimraf": "2.5.4", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.2.11" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "bundled": true + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "normalize-git-url": { + "version": "3.0.2", + "bundled": true + }, + "normalize-package-data": { + "version": "2.3.5", + "bundled": true, + "requires": { + "hosted-git-info": "2.1.5", + "is-builtin-module": "1.0.0", + "semver": "5.1.0", + "validate-npm-package-license": "3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.0", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "1.0.7", + "bundled": true, + "requires": { + "npmlog": "2.0.4", + "semver": "5.1.0" + } + }, + "npm-package-arg": { + "version": "4.1.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.1.5", + "semver": "5.1.0" + } + }, + "npm-registry-client": { + "version": "7.2.1", + "bundled": true, + "requires": { + "concat-stream": "1.5.2", + "graceful-fs": "4.1.6", + "normalize-package-data": "2.3.5", + "npm-package-arg": "4.1.0", + "npmlog": "2.0.4", + "once": "1.4.0", + "request": "2.74.0", + "retry": "0.10.0", + "semver": "5.1.0", + "slide": "1.1.6" + }, + "dependencies": { + "concat-stream": { + "version": "1.5.2", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + } + } + }, + "npm-user-validate": { + "version": "0.1.5", + "bundled": true + }, + "npmlog": { + "version": "2.0.4", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "are-we-there-yet": "1.1.2", + "gauge": "1.2.7" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.2", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.1.5" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "gauge": { + "version": "1.2.7", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "has-unicode": "2.0.0", + "lodash.pad": "4.4.0", + "lodash.padend": "4.5.0", + "lodash.padstart": "4.5.0" + }, + "dependencies": { + "has-unicode": { + "version": "2.0.0", + "bundled": true + }, + "lodash._baseslice": { + "version": "4.0.0", + "bundled": true + }, + "lodash._basetostring": { + "version": "4.12.0", + "bundled": true + }, + "lodash.pad": { + "version": "4.4.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.padend": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.padstart": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.tostring": { + "version": "4.1.4", + "bundled": true + } + } + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "opener": { + "version": "1.4.1", + "bundled": true + }, + "osenv": { + "version": "0.1.3", + "bundled": true, + "requires": { + "os-homedir": "1.0.0", + "os-tmpdir": "1.0.1" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.0", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.1", + "bundled": true + } + } + }, + "path-is-inside": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "0.0.5" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "bundled": true + } + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "graceful-fs": "4.1.6", + "read-package-json": "2.0.4", + "readdir-scoped-modules": "1.0.2", + "semver": "5.1.0", + "slide": "1.1.6", + "util-extend": "1.0.1" + }, + "dependencies": { + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "graceful-fs": "4.1.6", + "once": "1.4.0" + } + }, + "util-extend": { + "version": "1.0.1", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.4", + "bundled": true, + "requires": { + "glob": "6.0.4", + "graceful-fs": "4.1.6", + "json-parse-helpfulerror": "1.0.3", + "normalize-package-data": "2.3.5" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "1.3.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "readable-stream": { + "version": "2.1.5", + "bundled": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "realize-package-specifier": { + "version": "3.0.1", + "bundled": true, + "requires": { + "dezalgo": "1.0.3", + "npm-package-arg": "4.1.0" + } + }, + "request": { + "version": "2.74.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.4.1", + "bl": "1.1.2", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.0", + "forever-agent": "0.6.1", + "form-data": "1.0.0-rc4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.11", + "node-uuid": "1.4.7", + "oauth-sign": "0.8.2", + "qs": "6.2.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.1", + "tunnel-agent": "0.4.3" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.4.1", + "bundled": true + }, + "bl": { + "version": "1.1.2", + "bundled": true, + "requires": { + "readable-stream": "2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + } + } + }, + "caseless": { + "version": "0.11.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "1.0.0-rc4", + "bundled": true, + "requires": { + "async": "1.5.2", + "combined-stream": "1.0.5", + "mime-types": "2.1.11" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "bundled": true + } + } + }, + "har-validator": { + "version": "2.0.6", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.9.0", + "is-my-json-valid": "2.13.1", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "commander": { + "version": "2.9.0", + "bundled": true, + "requires": { + "graceful-readlink": "1.0.1" + }, + "dependencies": { + "graceful-readlink": { + "version": "1.0.1", + "bundled": true + } + } + }, + "is-my-json-valid": { + "version": "2.13.1", + "bundled": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "2.0.0", + "xtend": "4.0.1" + }, + "dependencies": { + "generate-function": { + "version": "2.0.0", + "bundled": true + }, + "generate-object-property": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-property": "1.0.2" + }, + "dependencies": { + "is-property": { + "version": "1.0.2", + "bundled": true + } + } + }, + "jsonpointer": { + "version": "2.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "bundled": true + } + } + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.3.0", + "sshpk": "1.9.2" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.3.0", + "bundled": true, + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.2", + "verror": "1.3.6" + }, + "dependencies": { + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.2", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.9.2", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "dashdash": "1.14.0", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.6", + "jodid25519": "1.0.2", + "jsbn": "0.1.0", + "tweetnacl": "0.13.3" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "dashdash": { + "version": "1.14.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "jsbn": { + "version": "0.1.0", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.13.3", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.11", + "bundled": true, + "requires": { + "mime-db": "1.23.0" + }, + "dependencies": { + "mime-db": { + "version": "1.23.0", + "bundled": true + } + } + }, + "node-uuid": { + "version": "1.4.7", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "qs": { + "version": "6.2.1", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.1", + "bundled": true + }, + "tunnel-agent": { + "version": "0.4.3", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + }, + "rimraf": { + "version": "2.5.4", + "bundled": true, + "requires": { + "glob": "7.0.6" + } + }, + "semver": { + "version": "5.1.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "readable-stream": "2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.2", + "bundled": true, + "requires": { + "core-util-is": "1.0.1", + "inherits": "2.0.3", + "isarray": "0.0.1", + "process-nextick-args": "1.0.3", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.3", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.0", + "bundled": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.10", + "inherits": "2.0.3" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.2" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-exceptions": "1.0.4", + "spdx-license-ids": "1.2.2" + }, + "dependencies": { + "spdx-exceptions": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "validate-npm-package-name": { + "version": "2.2.2", + "bundled": true, + "requires": { + "builtins": "0.0.7" + }, + "dependencies": { + "builtins": { + "version": "0.0.7", + "bundled": true + } + } + }, + "which": { + "version": "1.2.11", + "bundled": true, + "requires": { + "isexe": "1.1.2" + }, + "dependencies": { + "isexe": { + "version": "1.1.2", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "1.1.4", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "bundled": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "pac-proxy-agent": { + "version": "2.0.2", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "get-uri": "2.0.2", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "pac-resolver": "3.0.0", + "raw-body": "2.3.3", + "socks-proxy-agent": "3.0.1" + } + }, + "pac-resolver": { + "version": "3.0.0", + "bundled": true, + "requires": { + "co": "4.6.0", + "degenerator": "1.0.4", + "ip": "1.1.5", + "netmask": "1.0.6", + "thunkify": "2.1.2" + } + }, + "package": { + "version": "1.0.1", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.2" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "bundled": true + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "progress": { + "version": "2.0.0", + "bundled": true + }, + "proxy-agent": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "lru-cache": "4.1.3", + "pac-proxy-agent": "2.0.2", + "proxy-from-env": "1.0.0", + "socks-proxy-agent": "3.0.1" + } + }, + "proxy-from-env": { + "version": "1.0.0", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "q": { + "version": "1.5.1", + "bundled": true + }, + "raw-body": { + "version": "2.3.3", + "bundled": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "redent": { + "version": "1.0.0", + "bundled": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "regexpp": { + "version": "1.1.0", + "bundled": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "require-uncached": { + "version": "1.0.3", + "bundled": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.1.7", + "bundled": true + }, + "resolve-from": { + "version": "1.0.1", + "bundled": true + }, + "restore-cursor": { + "version": "2.0.0", + "bundled": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "bundled": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "bundled": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "bundled": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "sax": { + "version": "1.1.5", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "setprototypeof": { + "version": "1.1.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slice-ansi": { + "version": "1.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "1.1.15" + } + }, + "socks-proxy-agent": { + "version": "3.0.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "socks": "1.1.10" + } + }, + "source-map": { + "version": "0.6.1", + "bundled": true, + "optional": true + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "statuses": { + "version": "1.5.0", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + } + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "bundled": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + }, + "table": { + "version": "4.0.2", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "tar-stream": { + "version": "1.1.5", + "bundled": true, + "requires": { + "bl": "0.9.5", + "end-of-stream": "1.4.1", + "readable-stream": "1.0.34", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "temporary": { + "version": "0.0.8", + "bundled": true, + "requires": { + "package": "1.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "thunkify": { + "version": "2.1.2", + "bundled": true + }, + "tmp": { + "version": "0.0.33", + "bundled": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "trim-newlines": { + "version": "1.0.0", + "bundled": true + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "underscore.string": { + "version": "3.3.4", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.3.2", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write": { + "version": "0.2.1", + "bundled": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "xml2js": { + "version": "0.4.15", + "bundled": true, + "requires": { + "sax": "1.1.5", + "xmlbuilder": "2.6.2" + } + }, + "xmlbuilder": { + "version": "2.6.2", + "bundled": true, + "requires": { + "lodash": "3.5.0" + }, + "dependencies": { + "lodash": { + "version": "3.5.0", + "bundled": true + } + } + }, + "xregexp": { + "version": "2.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + }, + "zip-stream": { + "version": "0.5.2", + "bundled": true, + "requires": { + "compress-commons": "0.2.9", + "lodash": "3.2.0", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "lodash": { + "version": "3.2.0", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "amplify-category-storage": { + "version": "file:../amplify-category-storage", + "requires": { + "eslint": "4.19.1", + "inquirer": "3.3.0", + "uuid": "2.0.3" + }, + "dependencies": { + "acorn": { + "version": "5.6.2", + "bundled": true + }, + "acorn-jsx": { + "version": "3.0.1", + "bundled": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "bundled": true + } + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "bundled": true + }, + "ansi-escapes": { + "version": "3.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "argparse": { + "version": "1.0.10", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-union": { + "version": "1.0.2", + "bundled": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "bundled": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "caller-path": { + "version": "0.1.0", + "bundled": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "bundled": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "chardet": { + "version": "0.4.2", + "bundled": true + }, + "circular-json": { + "version": "0.3.3", + "bundled": true + }, + "cli-cursor": { + "version": "2.1.0", + "bundled": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "del": { + "version": "2.2.2", + "bundled": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.1.0", + "bundled": true, + "requires": { + "esutils": "2.0.2" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "eslint": { + "version": "4.19.1", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.5.0", + "ignore": "3.3.8", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "bundled": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "bundled": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.12.0", + "bundled": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "bundled": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "bundled": true + }, + "eslint-scope": { + "version": "3.7.1", + "bundled": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "bundled": true + }, + "espree": { + "version": "3.5.4", + "bundled": true, + "requires": { + "acorn": "5.6.2", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "bundled": true + }, + "esquery": { + "version": "1.0.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "external-editor": { + "version": "2.2.0", + "bundled": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "figures": { + "version": "2.0.0", + "bundled": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "bundled": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "bundled": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "bundled": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.5.0", + "bundled": true + }, + "globby": { + "version": "5.0.0", + "bundled": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.8", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "inquirer": { + "version": "3.3.0", + "bundled": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-path-cwd": { + "version": "1.0.0", + "bundled": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "bundled": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "bundled": true + }, + "is-resolvable": { + "version": "1.1.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true + }, + "js-yaml": { + "version": "3.12.0", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "bundled": true + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "natural-compare": { + "version": "1.4.0", + "bundled": true + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "bundled": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "bundled": true + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "progress": { + "version": "2.0.0", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "regexpp": { + "version": "1.1.0", + "bundled": true + }, + "require-uncached": { + "version": "1.0.3", + "bundled": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.7.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "bundled": true + }, + "restore-cursor": { + "version": "2.0.0", + "bundled": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "bundled": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "bundled": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "bundled": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slice-ansi": { + "version": "1.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "table": { + "version": "4.0.2", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "tmp": { + "version": "0.0.33", + "bundled": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "2.0.3", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write": { + "version": "0.2.1", + "bundled": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha1-MtHWU+HZBAiFS/spbwdux+GGowA=", + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + } + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "1.9.2" + }, + "dependencies": { + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", + "requires": { + "color-name": "1.1.1" + }, + "dependencies": { + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + } + } + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "requires": { + "has-flag": "3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + } + } + } + } + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha1-h/yqOimDWOCt5uRCz86EB0DRrQQ=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + } + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + }, + "dependencies": { + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "requires": { + "isexe": "2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + } + } + } + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "requires": { + "esutils": "2.0.2" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + }, + "dependencies": { + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + } + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=" + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha1-8JWCkpdwanyXdpWMCvyJMKm52dg=" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + } + } + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "requires": { + "estraverse": "4.2.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + } + } + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + }, + "dependencies": { + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + }, + "dependencies": { + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=" + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + }, + "dependencies": { + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + } + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "requires": { + "is-path-inside": "1.0.1" + }, + "dependencies": { + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + } + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "requires": { + "glob": "7.1.2" + } + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "0.5.1" + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + }, + "dependencies": { + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + }, + "dependencies": { + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + } + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha1-pYP6pDBVsayncZFL9oJY4vwSVnM=" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=" + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "requires": { + "sprintf-js": "1.0.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + } + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" + } + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + }, + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.11" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + } + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + } + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "requires": { + "is-fullwidth-code-point": "2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + } + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha1-OGRB5UoSzNlXsKklZKS6/r10eUQ=", + "dev": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + }, + "dependencies": { + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", + "integrity": "sha1-3yTyQRdeMS2RZi3JHKhAZMrsFO0=", + "dev": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" + }, + "dependencies": { + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", + "dev": true, + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + }, + "dependencies": { + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", + "dev": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "dev": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + } + } + } + } + } + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "dev": true, + "requires": { + "brace-expansion": "1.1.11" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + } + } + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + }, + "dependencies": { + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.3.0" + }, + "dependencies": { + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", + "dev": true, + "requires": { + "p-try": "1.0.0" + }, + "dependencies": { + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + } + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.2" + }, + "dependencies": { + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + } + } + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "dev": true, + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", + "integrity": "sha1-bkzueLAbuEnc+TUncIxp/b7kEN8=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + } + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "dev": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "dev": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + }, + "dependencies": { + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "dev": true + } + } + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "dev": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + }, + "dependencies": { + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", + "dev": true + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", + "dev": true + } + } + } + } + } + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + } + } + } + } + } + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha1-gvHsGaQjrB+9CAsLqwa6NuhKeiY=", + "dev": true, + "requires": { + "path-parse": "1.0.5" + }, + "dependencies": { + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + } + } + } + } + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=" + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "1.9.2" + }, + "dependencies": { + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", + "requires": { + "color-name": "1.1.1" + }, + "dependencies": { + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + } + } + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "requires": { + "has-flag": "3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + } + } + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + }, + "dependencies": { + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + }, + "dependencies": { + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.2.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" + } + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + } + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + }, + "dependencies": { + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", + "requires": { + "safer-buffer": "2.1.2" + }, + "dependencies": { + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + } + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "requires": { + "os-tmpdir": "1.0.2" + }, + "dependencies": { + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + } + } + } + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + }, + "dependencies": { + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + } + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + } + } + }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" + } + } +} diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4a2029137e..c3b41e17f3 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -10,6 +10,7 @@ }, "dependencies": { "amplify-category-storage": "file:../amplify-category-storage", + "amplify-category-function": "file:../amplify-category-function", "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index eee9595a21..3619957928 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -91,6 +91,25 @@ Resources: - !Ref ServiceRole <% } %> + <%if (props.dataSources && props.dataSources.lambda) { %> + ServicePolicyLambda: + Type: 'AWS::IAM::Policy' + Properties: + PolicyName: <%= props.servicePolicyName %> + PolicyDocument: + Version: 2012-10-17 + Statement: + - Effect: Allow + Action: + - 'lambda:invokeFunction' + Resource: + <% for(var i=0; i < props.dataSources.lambda.length; i++) { %> + - !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn + <% } %> + Roles: + - !Ref ServiceRole + <% } %> + <%if (props.dataSources && props.dataSources.dynamoDb) { %> <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> <%= props.dataSources.dynamoDb[i].resourceName %>DataSource: @@ -106,6 +125,20 @@ Resources: <% } %> <% } %> + <%if (props.dataSources && props.dataSources.lambda) { %> + <% for(var i=0; i < props.dataSources.lambda.length; i++) { %> + <%= props.dataSources.lambda[i].resourceName %>DataSource: + Type: "AWS::AppSync::DataSource" + Properties: + ApiId: !GetAtt GraphQLApi.ApiId + Name: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Name + ServiceRoleArn: !GetAtt ServiceRole.Arn + Type: AWS_LAMBDA + LambdaConfig: + LambdaFunctionArn: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn + <% } %> + <% } %> + Outputs: GraphQLApiARN: Description: The App ID of the GraphQL endpoint. diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index f956523d6e..0ff7ad904f 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -243,6 +243,20 @@ async function askDataSourceQuestions(context, inputs) { }); } break; + case 'Lambda': { + const resourceName = await askLambdaQuestions(context, inputs); + if (!dataSources.lambda) { + dataSources.lambda = [{ category: 'function', resourceName }]; + } else { + dataSources.lambda.push({ category: 'function', resourceName }); + } + dependsOn.push({ + category: 'function', + resourceName, + attributes: ['Name', 'Arn'], + }); + } + break; default: context.print.error('Feature not yet implemented'); } continueDataSourcesQuestion = await context.prompt.confirm('Do you want to add another data source?'); @@ -303,5 +317,56 @@ async function askDynamoDBQuestions(context, inputs) { } } +async function askLambdaQuestions(context, inputs) { + const lambdaTypeQuestion = { + type: inputs[16].type, + name: inputs[16].key, + message: inputs[16].question, + choices: inputs[16].options, + }; + while (true) { + const lambdaTypeAnswer = await inquirer.prompt([lambdaTypeQuestion]); + switch (lambdaTypeAnswer[inputs[16].key]) { + case 'currentProject': { + const storageResources = context.amplify.getProjectDetails().amplifyMeta.function; + const lambdaProjectResources = []; + Object.keys(storageResources).forEach((resourceName) => { + if (storageResources[resourceName].service === 'Lambda') { + lambdaProjectResources.push(resourceName); + } + }); + if (lambdaProjectResources.length === 0) { + context.print.error('There are no Lambda resources configured in your project currently'); + break; + } + const lambdaResourceQuestion = { + type: inputs[17].type, + name: inputs[17].key, + message: inputs[17].question, + choices: lambdaProjectResources, + }; + + const lambdaResourceAnswer = await inquirer.prompt([lambdaResourceQuestion]); + + return lambdaResourceAnswer[inputs[17].key]; + } + case 'newResource': { + let add; + try { + ({ add } = require('amplify-category-function')); + } catch (e) { + context.print.error('Function plugin not installed in the CLI. Please install it to use this feature'); + break; + } + return add(context, 'amplify-provider-awscloudformation', 'Lambda') + .then((resourceName) => { + context.print.success('Succesfully added Lambda table localy'); + return resourceName; + }); + } + default: context.print.error('Invalid option selected'); + } + } +} module.exports = { serviceWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 05d800b546..138018dceb 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -170,6 +170,27 @@ "key": "dynamoDbResources", "type": "list", "question": "Choose from one of the already configured DynamoDB tables" + }, + { + + "key": "lambdaType", + "type": "list", + "question": "Choose a Lambda data source option", + "options": [{ + "name": "Use a Lambda function configured in the current Amplify project", + "value": "currentProject" + }, + { + "name": "Create a new Lambda function", + "value": "newResource" + } + ] + }, + { + + "key": "lambdaResources", + "type": "list", + "question": "Choose from one of the already configured Lambda functions" } ], "defaultValuesFilename": "appSync-defaults.js", From f8dcaaefaf98efe9e5f95642e8b7383b1804e30f Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 6 Jul 2018 11:47:12 -0700 Subject: [PATCH 014/587] Modified some language in the CLI --- .../provider-utils/supported-services.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 138018dceb..10f75efe02 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -33,7 +33,7 @@ "value": "default" }, { - "name": "Use custom AppSync cloudformation template", + "name": "Create an AppSync API from scratch", "value": "custom" } ], @@ -162,6 +162,10 @@ { "name": "Create a new DynamoDB table", "value": "newResource" + }, + { + "name": "Use a DynamoDB table already deployed on AWS", + "value": "deployedResource" } ] }, @@ -183,6 +187,10 @@ { "name": "Create a new Lambda function", "value": "newResource" + }, + { + "name": "Use a Lambda function already deployed on AWS", + "value": "deployedResource" } ] }, From 82da22ab6d664922012074639f6b3a613ea4d38c Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Sat, 7 Jul 2018 12:45:05 -0700 Subject: [PATCH 015/587] Create README for api plugin --- packages/amplify-category-api/Readme.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 packages/amplify-category-api/Readme.md diff --git a/packages/amplify-category-api/Readme.md b/packages/amplify-category-api/Readme.md new file mode 100644 index 0000000000..30ec473c10 --- /dev/null +++ b/packages/amplify-category-api/Readme.md @@ -0,0 +1,11 @@ +# Amplify CLI API Plugin + +## Commands Summary + +The current set of commands supported by the Amplify API Category Plugin + +| Command | Description | +| --- | --- | +| amplify api add | Takes you through a CLI flow to add an API resource to your backend | +| amplify api push | Provisions only API cloud resources with the latest local developments | +| amplify api remove | Removes API resource from your local backend which would be removed from the cloud on the next push command | From d4e13fdff8ea7188c4799d4a39b3337116fbe2e3 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sat, 7 Jul 2018 20:37:21 -0700 Subject: [PATCH 016/587] Ability to add already provisioned dyanmo and lambda resources as a data source as a part of the appsync api --- ...ync-cloudformation-template-custom.yml.ejs | 27 +++- .../appSync-walkthrough.js | 129 +++++++++++++++--- .../provider-utils/supported-services.json | 21 ++- 3 files changed, 151 insertions(+), 26 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index 3619957928..162608ad7c 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -1,5 +1,5 @@ --- -<%if (props.dependsOn) { %> +<%if (props.dependsOn.length > 0) { %> Parameters: <% for(var i=0; i < props.dependsOn.length; i++) { %> <% for(var j=0; j < props.dependsOn[i].attributes.length; j++) { %> @@ -85,8 +85,12 @@ Resources: - 'dynamodb:UpdateItem' Resource: <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> + <%if (props.dataSources.dynamoDb[i].Arn) { %> + - <%= props.dataSources.dynamoDb[i].Arn %> + <% } else{ %> - !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Arn <% } %> + <% } %> Roles: - !Ref ServiceRole <% } %> @@ -104,8 +108,12 @@ Resources: - 'lambda:invokeFunction' Resource: <% for(var i=0; i < props.dataSources.lambda.length; i++) { %> + <%if (props.dataSources.lambda[i].Arn) { %> + - <%= props.dataSources.lambda[i].Arn %> + <% } else{ %> - !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn <% } %> + <% } %> Roles: - !Ref ServiceRole <% } %> @@ -116,12 +124,21 @@ Resources: Type: "AWS::AppSync::DataSource" Properties: ApiId: !GetAtt GraphQLApi.ApiId + <%if (props.dataSources.dynamoDb[i].Arn) { %> + Name: <%= props.dataSources.dynamoDb[i].resourceName %> + <% } else { %> Name: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name + <% } %> ServiceRoleArn: !GetAtt ServiceRole.Arn Type: AMAZON_DYNAMODB DynamoDBConfig: + <%if (props.dataSources.dynamoDb[i].Arn) { %> + AwsRegion: <%= props.dataSources.dynamoDb[i].region %> + TableName: <%= props.dataSources.dynamoDb[i].TableName %> + <% } else { %> AwsRegion: <%= props.region %> TableName: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name + <% } %> <% } %> <% } %> @@ -131,11 +148,19 @@ Resources: Type: "AWS::AppSync::DataSource" Properties: ApiId: !GetAtt GraphQLApi.ApiId + <%if (props.dataSources.lambda[i].Arn) { %> + Name: <%= props.dataSources.lambda[i].resourceName %> + <% } else { %> Name: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Name + <% } %> ServiceRoleArn: !GetAtt ServiceRole.Arn Type: AWS_LAMBDA LambdaConfig: + <%if (props.dataSources.lambda[i].Arn) { %> + LambdaFunctionArn: <%= props.dataSources.lambda[i].Arn %> + <% } else { %> LambdaFunctionArn: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn + <% } %> <% } %> <% } %> diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 0ff7ad904f..f737f4ded5 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -8,7 +8,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - const resourceQuestions = [ { type: inputs[0].type, @@ -227,34 +226,45 @@ async function askDataSourceQuestions(context, inputs) { // Ask data source related questions while (continueDataSourcesQuestion) { + console.log(dataSources.dynamoDb); + console.log(dependsOn); + const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); switch (dataSourceAnswer[inputs[13].key]) { case 'DynamoDb': { - const resourceName = await askDynamoDBQuestions(context, inputs); + const dynamoAnswers = await askDynamoDBQuestions(context, inputs); + Object.assign(dynamoAnswers, { category: 'storage' }); if (!dataSources.dynamoDb) { - dataSources.dynamoDb = [{ category: 'storage', resourceName }]; + dataSources.dynamoDb = [dynamoAnswers]; } else { - dataSources.dynamoDb.push({ category: 'storage', resourceName }); + dataSources.dynamoDb.push(dynamoAnswers); + } + if (!dynamoAnswers.Arn) { + dependsOn.push({ + category: 'storage', + resourceName: dynamoAnswers.resourceName, + attributes: ['Name', 'Arn'], + }); } - dependsOn.push({ - category: 'storage', - resourceName, - attributes: ['Name', 'Arn'], - }); } break; case 'Lambda': { - const resourceName = await askLambdaQuestions(context, inputs); + const lambdaAnswers = await askLambdaQuestions(context, inputs); + Object.assign(lambdaAnswers, { category: 'function' }); + if (!dataSources.lambda) { - dataSources.lambda = [{ category: 'function', resourceName }]; + dataSources.lambda = [lambdaAnswers]; } else { - dataSources.lambda.push({ category: 'function', resourceName }); + dataSources.lambda.push(lambdaAnswers); + } + + if (!lambdaAnswers.Arn) { + dependsOn.push({ + category: 'function', + resourceName: lambdaAnswers.resourceName, + attributes: ['Name', 'Arn'], + }); } - dependsOn.push({ - category: 'function', - resourceName, - attributes: ['Name', 'Arn'], - }); } break; default: context.print.error('Feature not yet implemented'); @@ -296,7 +306,7 @@ async function askDynamoDBQuestions(context, inputs) { const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); - return dynamoResourceAnswer[inputs[15].key]; + return { resourceName: dynamoResourceAnswer[inputs[15].key] }; } case 'newResource': { let add; @@ -309,9 +319,48 @@ async function askDynamoDBQuestions(context, inputs) { return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') .then((resourceName) => { context.print.success('Succesfully added DynamoDb table localy'); - return resourceName; + return { resourceName }; }); } + case 'cloudResource': { + const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + + const regionQuestion = { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + choices: regions, + }; + + const regionAnswer = await inquirer.prompt([regionQuestion]); + + const dynamodbTables = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getDynamoDBTables', { region: regionAnswer[inputs[4].key] }); + + const dynamodbOptions = dynamodbTables.map(dynamodbTable => ({ + value: { + resourceName: dynamodbTable.Name.replace(/[^0-9a-zA-Z]/gi, ''), + region: dynamodbTable.Region, + Arn: dynamodbTable.Arn, + TableName: dynamodbTable.Name, + }, + name: `${dynamodbTable.Name} (${dynamodbTable.Arn})`, + })); + + if (dynamodbOptions.length === 0) { + context.print.error('You do not have any DynamoDB tables configured for the selected region'); + break; + } + + const dynamoCloudOptionQuestion = { + type: inputs[19].type, + name: inputs[19].key, + message: inputs[19].question, + choices: dynamodbOptions, + }; + + const dynamoCloudOptionAnswer = await inquirer.prompt([dynamoCloudOptionQuestion]); + return dynamoCloudOptionAnswer[inputs[19].key]; + } default: context.print.error('Invalid option selected'); } } @@ -348,7 +397,7 @@ async function askLambdaQuestions(context, inputs) { const lambdaResourceAnswer = await inquirer.prompt([lambdaResourceQuestion]); - return lambdaResourceAnswer[inputs[17].key]; + return { resourceName: lambdaResourceAnswer[inputs[17].key] }; } case 'newResource': { let add; @@ -361,9 +410,47 @@ async function askLambdaQuestions(context, inputs) { return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda table localy'); - return resourceName; + return { resourceName }; }); } + case 'cloudResource': { + const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + + const regionQuestion = { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + choices: regions, + }; + + const regionAnswer = await inquirer.prompt([regionQuestion]); + + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer[inputs[4].key] }); + + const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ + value: { + resourceName: lambdaFunction.FunctionName.replace(/[^0-9a-zA-Z]/gi, ''), + Arn: lambdaFunction.FunctionArn, + FunctionName: lambdaFunction.FunctionName, + }, + name: `${lambdaFunction.FunctionName} (${lambdaFunction.FunctionArn})`, + })); + + if (lambdaOptions.length === 0) { + context.print.error('You do not have any lambda functions configured for the selected region'); + break; + } + + const lambdaCloudOptionQuestion = { + type: inputs[18].type, + name: inputs[18].key, + message: inputs[18].question, + choices: lambdaOptions, + }; + + const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); + return lambdaCloudOptionAnswer[inputs[18].key]; + } default: context.print.error('Invalid option selected'); } } diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 10f75efe02..ebefd6bc53 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -146,8 +146,7 @@ "question": "Choose a data source you would like to add to your AppSync API", "options": [ "DynamoDb", - "Lambda", - "Elasticsearch" + "Lambda" ] }, { @@ -165,7 +164,7 @@ }, { "name": "Use a DynamoDB table already deployed on AWS", - "value": "deployedResource" + "value": "cloudResource" } ] }, @@ -190,7 +189,7 @@ }, { "name": "Use a Lambda function already deployed on AWS", - "value": "deployedResource" + "value": "cloudResource" } ] }, @@ -199,6 +198,20 @@ "key": "lambdaResources", "type": "list", "question": "Choose from one of the already configured Lambda functions" + }, + { + + "key": "lambdaFunctionChoice", + "type": "list", + "question": "Please select a Lambda function:", + "required": true + }, + { + + "key": "dynamodbTableChoice", + "type": "list", + "question": "Please select a DynamoDB table:", + "required": true } ], "defaultValuesFilename": "appSync-defaults.js", From 663bacd5107cdf28d07da9ff4f031f054a3d59f5 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sat, 7 Jul 2018 20:39:07 -0700 Subject: [PATCH 017/587] Remove console statements --- .../service-walkthroughs/appSync-walkthrough.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index f737f4ded5..23e2b89494 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -226,8 +226,6 @@ async function askDataSourceQuestions(context, inputs) { // Ask data source related questions while (continueDataSourcesQuestion) { - console.log(dataSources.dynamoDb); - console.log(dependsOn); const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); switch (dataSourceAnswer[inputs[13].key]) { From c3811a4df58e2ade631321810e106b708ccc85b5 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Sun, 8 Jul 2018 12:09:56 -0700 Subject: [PATCH 018/587] rename to package name pattern violation --- .../amplify-category-api/package-lock.json | 6420 ----------------- 1 file changed, 6420 deletions(-) delete mode 100644 packages/amplify-category-api/package-lock.json diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json deleted file mode 100644 index 2dc4d6c763..0000000000 --- a/packages/amplify-category-api/package-lock.json +++ /dev/null @@ -1,6420 +0,0 @@ -{ - "name": "amplify-category-api", - "version": "0.1.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "amplify-category-function": { - "version": "file:../amplify-category-function", - "requires": { - "eslint": "4.19.1", - "grunt": "1.0.3", - "grunt-aws-lambda": "0.13.0", - "inquirer": "3.3.0", - "uuid": "3.3.2" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true - }, - "acorn": { - "version": "5.7.1", - "bundled": true - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "agent-base": { - "version": "4.2.1", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "ansi-escapes": { - "version": "3.1.0", - "bundled": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "archiver": { - "version": "0.14.4", - "bundled": true, - "requires": { - "async": "0.9.2", - "buffer-crc32": "0.2.13", - "glob": "4.3.5", - "lazystream": "0.1.0", - "lodash": "3.2.0", - "readable-stream": "1.0.34", - "tar-stream": "1.1.5", - "zip-stream": "0.5.2" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "bundled": true - }, - "glob": { - "version": "4.3.5", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" - } - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "lodash": { - "version": "3.2.0", - "bundled": true - }, - "minimatch": { - "version": "2.0.10", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "argparse": { - "version": "1.0.10", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-find-index": { - "version": "1.0.2", - "bundled": true - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "ast-types": { - "version": "0.11.5", - "bundled": true - }, - "async": { - "version": "1.5.2", - "bundled": true - }, - "aws-sdk": { - "version": "2.2.48", - "bundled": true, - "requires": { - "sax": "1.1.5", - "xml2js": "0.4.15", - "xmlbuilder": "2.6.2" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - } - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "bl": { - "version": "0.9.5", - "bundled": true, - "requires": { - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "bundled": true - }, - "buffer-from": { - "version": "1.1.0", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "bytes": { - "version": "3.0.0", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "camelcase": { - "version": "2.1.1", - "bundled": true - }, - "camelcase-keys": { - "version": "2.1.0", - "bundled": true, - "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" - } - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "1.9.2" - } - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "coffeescript": { - "version": "1.10.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.2", - "bundled": true, - "requires": { - "color-name": "1.1.1" - } - }, - "color-name": { - "version": "1.1.1", - "bundled": true - }, - "colors": { - "version": "1.1.2", - "bundled": true - }, - "compress-commons": { - "version": "0.2.9", - "bundled": true, - "requires": { - "buffer-crc32": "0.2.13", - "crc32-stream": "0.3.4", - "node-int64": "0.3.3", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "crc32-stream": { - "version": "0.3.4", - "bundled": true, - "requires": { - "buffer-crc32": "0.2.13", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "bundled": true, - "requires": { - "array-find-index": "1.0.2" - } - }, - "data-uri-to-buffer": { - "version": "1.2.0", - "bundled": true - }, - "dateformat": { - "version": "1.0.12", - "bundled": true, - "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "bundled": true - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "degenerator": { - "version": "1.0.4", - "bundled": true, - "requires": { - "ast-types": "0.11.5", - "escodegen": "1.10.0", - "esprima": "3.1.3" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "bundled": true - } - } - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "depd": { - "version": "1.1.2", - "bundled": true - }, - "doctrine": { - "version": "2.1.0", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es6-promise": { - "version": "4.2.4", - "bundled": true - }, - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "escodegen": { - "version": "1.10.0", - "bundled": true, - "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "bundled": true - } - } - }, - "eslint": { - "version": "4.19.1", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "bundled": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "bundled": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "resolve": { - "version": "1.8.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "bundled": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.13.0", - "bundled": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - } - }, - "resolve": { - "version": "1.8.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "bundled": true - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.4", - "bundled": true, - "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "eventemitter2": { - "version": "0.4.14", - "bundled": true - }, - "exit": { - "version": "0.1.2", - "bundled": true - }, - "extend": { - "version": "3.0.1", - "bundled": true - }, - "external-editor": { - "version": "2.2.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "bundled": true - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "findup-sync": { - "version": "0.3.0", - "bundled": true, - "requires": { - "glob": "5.0.15" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - } - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "ftp": { - "version": "0.3.10", - "bundled": true, - "requires": { - "readable-stream": "1.1.14", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.1.14", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "get-stdin": { - "version": "4.0.1", - "bundled": true - }, - "get-uri": { - "version": "2.0.2", - "bundled": true, - "requires": { - "data-uri-to-buffer": "1.2.0", - "debug": "2.6.9", - "extend": "3.0.1", - "file-uri-to-path": "1.0.0", - "ftp": "0.3.10", - "readable-stream": "2.3.6" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "getobject": { - "version": "0.1.0", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.7.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "grunt": { - "version": "1.0.3", - "bundled": true, - "requires": { - "coffeescript": "1.10.0", - "dateformat": "1.0.12", - "eventemitter2": "0.4.14", - "exit": "0.1.2", - "findup-sync": "0.3.0", - "glob": "7.0.6", - "grunt-cli": "1.2.0", - "grunt-known-options": "1.1.0", - "grunt-legacy-log": "2.0.0", - "grunt-legacy-util": "1.1.1", - "iconv-lite": "0.4.23", - "js-yaml": "3.5.5", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "path-is-absolute": "1.0.1", - "rimraf": "2.6.2" - }, - "dependencies": { - "esprima": { - "version": "2.7.3", - "bundled": true - }, - "glob": { - "version": "7.0.6", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "grunt-cli": { - "version": "1.2.0", - "bundled": true, - "requires": { - "findup-sync": "0.3.0", - "grunt-known-options": "1.1.0", - "nopt": "3.0.6", - "resolve": "1.1.7" - } - }, - "js-yaml": { - "version": "3.5.5", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "2.7.3" - } - } - } - }, - "grunt-aws-lambda": { - "version": "0.13.0", - "bundled": true, - "requires": { - "archiver": "0.14.4", - "aws-sdk": "2.2.48", - "glob": "4.3.5", - "mkdirp": "0.5.1", - "npm": "2.15.12", - "proxy-agent": "3.0.0", - "q": "1.5.1", - "rimraf": "2.2.8", - "temporary": "0.0.8" - }, - "dependencies": { - "glob": { - "version": "4.3.5", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" - } - }, - "minimatch": { - "version": "2.0.10", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "rimraf": { - "version": "2.2.8", - "bundled": true - } - } - }, - "grunt-known-options": { - "version": "1.1.0", - "bundled": true - }, - "grunt-legacy-log": { - "version": "2.0.0", - "bundled": true, - "requires": { - "colors": "1.1.2", - "grunt-legacy-log-utils": "2.0.1", - "hooker": "0.2.3", - "lodash": "4.17.10" - } - }, - "grunt-legacy-log-utils": { - "version": "2.0.1", - "bundled": true, - "requires": { - "chalk": "2.4.1", - "lodash": "4.17.10" - } - }, - "grunt-legacy-util": { - "version": "1.1.1", - "bundled": true, - "requires": { - "async": "1.5.2", - "exit": "0.1.2", - "getobject": "0.1.0", - "hooker": "0.2.3", - "lodash": "4.17.10", - "underscore.string": "3.3.4", - "which": "1.3.1" - } - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "hooker": { - "version": "0.2.3", - "bundled": true - }, - "hosted-git-info": { - "version": "2.6.1", - "bundled": true - }, - "http-errors": { - "version": "1.6.3", - "bundled": true, - "requires": { - "depd": "1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": "1.5.0" - } - }, - "http-proxy-agent": { - "version": "2.1.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "https-proxy-agent": { - "version": "2.2.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.10", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "indent-string": { - "version": "2.1.0", - "bundled": true, - "requires": { - "repeating": "2.0.1" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "ip": { - "version": "1.1.5", - "bundled": true - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.1.0", - "bundled": true - }, - "is-utf8": { - "version": "0.2.1", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.12.0", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "lazystream": { - "version": "0.1.0", - "bundled": true, - "requires": { - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true - }, - "loud-rejection": { - "version": "1.6.0", - "bundled": true, - "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" - } - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "map-obj": { - "version": "1.0.1", - "bundled": true - }, - "meow": { - "version": "3.7.0", - "bundled": true, - "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "netmask": { - "version": "1.0.6", - "bundled": true - }, - "node-int64": { - "version": "0.3.3", - "bundled": true - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1.1.1" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.6.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "npm": { - "version": "2.15.12", - "bundled": true, - "requires": { - "abbrev": "1.0.9", - "ansi": "0.3.1", - "ansi-regex": "2.0.0", - "ansicolors": "0.3.2", - "ansistyles": "0.1.3", - "archy": "1.0.0", - "async-some": "1.0.2", - "block-stream": "0.0.9", - "char-spinner": "1.0.1", - "chmodr": "1.0.2", - "chownr": "1.0.1", - "cmd-shim": "2.0.2", - "columnify": "1.5.4", - "config-chain": "1.1.10", - "dezalgo": "1.0.3", - "editor": "1.0.0", - "fs-vacuum": "1.2.9", - "fs-write-stream-atomic": "1.0.8", - "fstream": "1.0.10", - "fstream-npm": "1.1.1", - "github-url-from-git": "1.4.0", - "github-url-from-username-repo": "1.0.2", - "glob": "7.0.6", - "graceful-fs": "4.1.6", - "hosted-git-info": "2.1.5", - "imurmurhash": "0.1.4", - "inflight": "1.0.5", - "inherits": "2.0.3", - "ini": "1.3.4", - "init-package-json": "1.9.4", - "lockfile": "1.0.1", - "lru-cache": "4.0.1", - "minimatch": "3.0.3", - "mkdirp": "0.5.1", - "node-gyp": "3.6.0", - "nopt": "3.0.6", - "normalize-git-url": "3.0.2", - "normalize-package-data": "2.3.5", - "npm-cache-filename": "1.0.2", - "npm-install-checks": "1.0.7", - "npm-package-arg": "4.1.0", - "npm-registry-client": "7.2.1", - "npm-user-validate": "0.1.5", - "npmlog": "2.0.4", - "once": "1.4.0", - "opener": "1.4.1", - "osenv": "0.1.3", - "path-is-inside": "1.0.1", - "read": "1.0.7", - "read-installed": "4.0.3", - "read-package-json": "2.0.4", - "readable-stream": "2.1.5", - "realize-package-specifier": "3.0.1", - "request": "2.74.0", - "retry": "0.10.0", - "rimraf": "2.5.4", - "semver": "5.1.0", - "sha": "2.0.1", - "slide": "1.1.6", - "sorted-object": "2.0.0", - "spdx-license-ids": "1.2.2", - "strip-ansi": "3.0.1", - "tar": "2.2.1", - "text-table": "0.2.0", - "uid-number": "0.0.6", - "umask": "1.1.0", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "2.2.2", - "which": "1.2.11", - "wrappy": "1.0.2", - "write-file-atomic": "1.1.4" - }, - "dependencies": { - "abbrev": { - "version": "1.0.9", - "bundled": true - }, - "ansi": { - "version": "0.3.1", - "bundled": true - }, - "ansi-regex": { - "version": "2.0.0", - "bundled": true - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true - }, - "ansistyles": { - "version": "0.1.3", - "bundled": true - }, - "archy": { - "version": "1.0.0", - "bundled": true - }, - "async-some": { - "version": "1.0.2", - "bundled": true, - "requires": { - "dezalgo": "1.0.3" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "char-spinner": { - "version": "1.0.1", - "bundled": true - }, - "chmodr": { - "version": "1.0.2", - "bundled": true - }, - "chownr": { - "version": "1.0.1", - "bundled": true - }, - "cmd-shim": { - "version": "2.0.2", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "mkdirp": "0.5.1" - } - }, - "columnify": { - "version": "1.5.4", - "bundled": true, - "requires": { - "strip-ansi": "3.0.1", - "wcwidth": "1.0.0" - }, - "dependencies": { - "wcwidth": { - "version": "1.0.0", - "bundled": true, - "requires": { - "defaults": "1.0.3" - }, - "dependencies": { - "defaults": { - "version": "1.0.3", - "bundled": true, - "requires": { - "clone": "1.0.2" - }, - "dependencies": { - "clone": { - "version": "1.0.2", - "bundled": true - } - } - } - } - } - } - }, - "config-chain": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ini": "1.3.4", - "proto-list": "1.2.4" - }, - "dependencies": { - "proto-list": { - "version": "1.2.4", - "bundled": true - } - } - }, - "dezalgo": { - "version": "1.0.3", - "bundled": true, - "requires": { - "asap": "2.0.3", - "wrappy": "1.0.2" - }, - "dependencies": { - "asap": { - "version": "2.0.3", - "bundled": true - } - } - }, - "editor": { - "version": "1.0.0", - "bundled": true - }, - "fs-vacuum": { - "version": "1.2.9", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "path-is-inside": "1.0.1", - "rimraf": "2.5.4" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.8", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.1.5" - }, - "dependencies": { - "iferr": { - "version": "0.1.5", - "bundled": true - } - } - }, - "fstream": { - "version": "1.0.10", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.5.4" - } - }, - "fstream-npm": { - "version": "1.1.1", - "bundled": true, - "requires": { - "fstream-ignore": "1.0.5", - "inherits": "2.0.3" - }, - "dependencies": { - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "requires": { - "fstream": "1.0.10", - "inherits": "2.0.3", - "minimatch": "3.0.3" - } - } - } - }, - "github-url-from-git": { - "version": "1.4.0", - "bundled": true - }, - "github-url-from-username-repo": { - "version": "1.0.2", - "bundled": true - }, - "glob": { - "version": "7.0.6", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "graceful-fs": { - "version": "4.1.6", - "bundled": true - }, - "hosted-git-info": { - "version": "2.1.5", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.5", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true - }, - "init-package-json": { - "version": "1.9.4", - "bundled": true, - "requires": { - "glob": "6.0.4", - "npm-package-arg": "4.1.0", - "promzard": "0.3.0", - "read": "1.0.7", - "read-package-json": "2.0.4", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "2.2.2" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "bundled": true, - "requires": { - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "requires": { - "read": "1.0.7" - } - } - } - }, - "lockfile": { - "version": "1.0.1", - "bundled": true - }, - "lru-cache": { - "version": "4.0.1", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.0.0" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "2.0.0", - "bundled": true - } - } - }, - "minimatch": { - "version": "3.0.3", - "bundled": true, - "requires": { - "brace-expansion": "1.1.6" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "bundled": true - } - } - }, - "node-gyp": { - "version": "3.6.0", - "bundled": true, - "requires": { - "fstream": "1.0.10", - "glob": "7.0.6", - "graceful-fs": "4.1.6", - "minimatch": "3.0.3", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "2.0.4", - "osenv": "0.1.3", - "request": "2.74.0", - "rimraf": "2.5.4", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.2.11" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "bundled": true - } - } - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1.0.9" - } - }, - "normalize-git-url": { - "version": "3.0.2", - "bundled": true - }, - "normalize-package-data": { - "version": "2.3.5", - "bundled": true, - "requires": { - "hosted-git-info": "2.1.5", - "is-builtin-module": "1.0.0", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1" - }, - "dependencies": { - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.0" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.0", - "bundled": true - } - } - } - } - }, - "npm-cache-filename": { - "version": "1.0.2", - "bundled": true - }, - "npm-install-checks": { - "version": "1.0.7", - "bundled": true, - "requires": { - "npmlog": "2.0.4", - "semver": "5.1.0" - } - }, - "npm-package-arg": { - "version": "4.1.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.1.5", - "semver": "5.1.0" - } - }, - "npm-registry-client": { - "version": "7.2.1", - "bundled": true, - "requires": { - "concat-stream": "1.5.2", - "graceful-fs": "4.1.6", - "normalize-package-data": "2.3.5", - "npm-package-arg": "4.1.0", - "npmlog": "2.0.4", - "once": "1.4.0", - "request": "2.74.0", - "retry": "0.10.0", - "semver": "5.1.0", - "slide": "1.1.6" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "retry": { - "version": "0.10.0", - "bundled": true - } - } - }, - "npm-user-validate": { - "version": "0.1.5", - "bundled": true - }, - "npmlog": { - "version": "2.0.4", - "bundled": true, - "requires": { - "ansi": "0.3.1", - "are-we-there-yet": "1.1.2", - "gauge": "1.2.7" - }, - "dependencies": { - "are-we-there-yet": { - "version": "1.1.2", - "bundled": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.1.5" - }, - "dependencies": { - "delegates": { - "version": "1.0.0", - "bundled": true - } - } - }, - "gauge": { - "version": "1.2.7", - "bundled": true, - "requires": { - "ansi": "0.3.1", - "has-unicode": "2.0.0", - "lodash.pad": "4.4.0", - "lodash.padend": "4.5.0", - "lodash.padstart": "4.5.0" - }, - "dependencies": { - "has-unicode": { - "version": "2.0.0", - "bundled": true - }, - "lodash._baseslice": { - "version": "4.0.0", - "bundled": true - }, - "lodash._basetostring": { - "version": "4.12.0", - "bundled": true - }, - "lodash.pad": { - "version": "4.4.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.padend": { - "version": "4.5.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.padstart": { - "version": "4.5.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.tostring": { - "version": "4.1.4", - "bundled": true - } - } - } - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "opener": { - "version": "1.4.1", - "bundled": true - }, - "osenv": { - "version": "0.1.3", - "bundled": true, - "requires": { - "os-homedir": "1.0.0", - "os-tmpdir": "1.0.1" - }, - "dependencies": { - "os-homedir": { - "version": "1.0.0", - "bundled": true - }, - "os-tmpdir": { - "version": "1.0.1", - "bundled": true - } - } - }, - "path-is-inside": { - "version": "1.0.1", - "bundled": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "requires": { - "mute-stream": "0.0.5" - }, - "dependencies": { - "mute-stream": { - "version": "0.0.5", - "bundled": true - } - } - }, - "read-installed": { - "version": "4.0.3", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "graceful-fs": "4.1.6", - "read-package-json": "2.0.4", - "readdir-scoped-modules": "1.0.2", - "semver": "5.1.0", - "slide": "1.1.6", - "util-extend": "1.0.1" - }, - "dependencies": { - "debuglog": { - "version": "1.0.1", - "bundled": true - }, - "readdir-scoped-modules": { - "version": "1.0.2", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "graceful-fs": "4.1.6", - "once": "1.4.0" - } - }, - "util-extend": { - "version": "1.0.1", - "bundled": true - } - } - }, - "read-package-json": { - "version": "2.0.4", - "bundled": true, - "requires": { - "glob": "6.0.4", - "graceful-fs": "4.1.6", - "json-parse-helpfulerror": "1.0.3", - "normalize-package-data": "2.3.5" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "bundled": true, - "requires": { - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "json-parse-helpfulerror": { - "version": "1.0.3", - "bundled": true, - "requires": { - "jju": "1.3.0" - }, - "dependencies": { - "jju": { - "version": "1.3.0", - "bundled": true - } - } - } - } - }, - "readable-stream": { - "version": "2.1.5", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - }, - "realize-package-specifier": { - "version": "3.0.1", - "bundled": true, - "requires": { - "dezalgo": "1.0.3", - "npm-package-arg": "4.1.0" - } - }, - "request": { - "version": "2.74.0", - "bundled": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.4.1", - "bl": "1.1.2", - "caseless": "0.11.0", - "combined-stream": "1.0.5", - "extend": "3.0.0", - "forever-agent": "0.6.1", - "form-data": "1.0.0-rc4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.11", - "node-uuid": "1.4.7", - "oauth-sign": "0.8.2", - "qs": "6.2.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.1", - "tunnel-agent": "0.4.3" - }, - "dependencies": { - "aws-sign2": { - "version": "0.6.0", - "bundled": true - }, - "aws4": { - "version": "1.4.1", - "bundled": true - }, - "bl": { - "version": "1.1.2", - "bundled": true, - "requires": { - "readable-stream": "2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - } - } - }, - "caseless": { - "version": "0.11.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - }, - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "bundled": true - } - } - }, - "extend": { - "version": "3.0.0", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true - }, - "form-data": { - "version": "1.0.0-rc4", - "bundled": true, - "requires": { - "async": "1.5.2", - "combined-stream": "1.0.5", - "mime-types": "2.1.11" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "bundled": true - } - } - }, - "har-validator": { - "version": "2.0.6", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "commander": "2.9.0", - "is-my-json-valid": "2.13.1", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "commander": { - "version": "2.9.0", - "bundled": true, - "requires": { - "graceful-readlink": "1.0.1" - }, - "dependencies": { - "graceful-readlink": { - "version": "1.0.1", - "bundled": true - } - } - }, - "is-my-json-valid": { - "version": "2.13.1", - "bundled": true, - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "2.0.0", - "xtend": "4.0.1" - }, - "dependencies": { - "generate-function": { - "version": "2.0.0", - "bundled": true - }, - "generate-object-property": { - "version": "1.2.0", - "bundled": true, - "requires": { - "is-property": "1.0.2" - }, - "dependencies": { - "is-property": { - "version": "1.0.2", - "bundled": true - } - } - }, - "jsonpointer": { - "version": "2.0.0", - "bundled": true - }, - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "bundled": true - } - } - } - } - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - }, - "dependencies": { - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.10.1" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - } - } - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.3.0", - "sshpk": "1.9.2" - }, - "dependencies": { - "assert-plus": { - "version": "0.2.0", - "bundled": true - }, - "jsprim": { - "version": "1.3.0", - "bundled": true, - "requires": { - "extsprintf": "1.0.2", - "json-schema": "0.2.2", - "verror": "1.3.6" - }, - "dependencies": { - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "json-schema": { - "version": "0.2.2", - "bundled": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "requires": { - "extsprintf": "1.0.2" - } - } - } - }, - "sshpk": { - "version": "1.9.2", - "bundled": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "dashdash": "1.14.0", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.6", - "jodid25519": "1.0.2", - "jsbn": "0.1.0", - "tweetnacl": "0.13.3" - }, - "dependencies": { - "asn1": { - "version": "0.2.3", - "bundled": true - }, - "assert-plus": { - "version": "1.0.0", - "bundled": true - }, - "dashdash": { - "version": "1.14.0", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.0" - } - }, - "getpass": { - "version": "0.1.6", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.0" - } - }, - "jsbn": { - "version": "0.1.0", - "bundled": true, - "optional": true - }, - "tweetnacl": { - "version": "0.13.3", - "bundled": true, - "optional": true - } - } - } - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true - }, - "mime-types": { - "version": "2.1.11", - "bundled": true, - "requires": { - "mime-db": "1.23.0" - }, - "dependencies": { - "mime-db": { - "version": "1.23.0", - "bundled": true - } - } - }, - "node-uuid": { - "version": "1.4.7", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true - }, - "qs": { - "version": "6.2.1", - "bundled": true - }, - "stringstream": { - "version": "0.0.5", - "bundled": true - }, - "tough-cookie": { - "version": "2.3.1", - "bundled": true - }, - "tunnel-agent": { - "version": "0.4.3", - "bundled": true - } - } - }, - "retry": { - "version": "0.10.0", - "bundled": true - }, - "rimraf": { - "version": "2.5.4", - "bundled": true, - "requires": { - "glob": "7.0.6" - } - }, - "semver": { - "version": "5.1.0", - "bundled": true - }, - "sha": { - "version": "2.0.1", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "readable-stream": "2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.2", - "bundled": true, - "requires": { - "core-util-is": "1.0.1", - "inherits": "2.0.3", - "isarray": "0.0.1", - "process-nextick-args": "1.0.3", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.1" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.1", - "bundled": true - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.3", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.1", - "bundled": true - } - } - } - } - }, - "slide": { - "version": "1.1.6", - "bundled": true - }, - "sorted-object": { - "version": "2.0.0", - "bundled": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "bundled": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.0.0" - } - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.10", - "inherits": "2.0.3" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true - }, - "umask": { - "version": "1.1.0", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "bundled": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.2" - }, - "dependencies": { - "spdx-correct": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-exceptions": "1.0.4", - "spdx-license-ids": "1.2.2" - }, - "dependencies": { - "spdx-exceptions": { - "version": "1.0.4", - "bundled": true - } - } - } - } - }, - "validate-npm-package-name": { - "version": "2.2.2", - "bundled": true, - "requires": { - "builtins": "0.0.7" - }, - "dependencies": { - "builtins": { - "version": "0.0.7", - "bundled": true - } - } - }, - "which": { - "version": "1.2.11", - "bundled": true, - "requires": { - "isexe": "1.1.2" - }, - "dependencies": { - "isexe": { - "version": "1.1.2", - "bundled": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write-file-atomic": { - "version": "1.1.4", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "imurmurhash": "0.1.4", - "slide": "1.1.6" - } - } - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "p-limit": { - "version": "1.3.0", - "bundled": true, - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true - }, - "pac-proxy-agent": { - "version": "2.0.2", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "get-uri": "2.0.2", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "pac-resolver": "3.0.0", - "raw-body": "2.3.3", - "socks-proxy-agent": "3.0.1" - } - }, - "pac-resolver": { - "version": "3.0.0", - "bundled": true, - "requires": { - "co": "4.6.0", - "degenerator": "1.0.4", - "ip": "1.1.5", - "netmask": "1.0.6", - "thunkify": "2.1.2" - } - }, - "package": { - "version": "1.0.1", - "bundled": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.2" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true - }, - "path-type": { - "version": "1.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "proxy-agent": { - "version": "3.0.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "lru-cache": "4.1.3", - "pac-proxy-agent": "2.0.2", - "proxy-from-env": "1.0.0", - "socks-proxy-agent": "3.0.1" - } - }, - "proxy-from-env": { - "version": "1.0.0", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "q": { - "version": "1.5.1", - "bundled": true - }, - "raw-body": { - "version": "2.3.3", - "bundled": true, - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - } - }, - "read-pkg": { - "version": "1.1.0", - "bundled": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "bundled": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "redent": { - "version": "1.0.0", - "bundled": true, - "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" - } - }, - "regexpp": { - "version": "1.1.0", - "bundled": true - }, - "repeating": { - "version": "2.0.1", - "bundled": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.1.7", - "bundled": true - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "sax": { - "version": "1.1.5", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "setprototypeof": { - "version": "1.1.0", - "bundled": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "smart-buffer": { - "version": "1.1.15", - "bundled": true - }, - "socks": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" - } - }, - "socks-proxy-agent": { - "version": "3.0.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "socks": "1.1.10" - } - }, - "source-map": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "statuses": { - "version": "1.5.0", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - } - } - }, - "strip-bom": { - "version": "2.0.0", - "bundled": true, - "requires": { - "is-utf8": "0.2.1" - } - }, - "strip-indent": { - "version": "1.0.1", - "bundled": true, - "requires": { - "get-stdin": "4.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "tar-stream": { - "version": "1.1.5", - "bundled": true, - "requires": { - "bl": "0.9.5", - "end-of-stream": "1.4.1", - "readable-stream": "1.0.34", - "xtend": "4.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "temporary": { - "version": "0.0.8", - "bundled": true, - "requires": { - "package": "1.0.1" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "thunkify": { - "version": "2.1.2", - "bundled": true - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "trim-newlines": { - "version": "1.0.0", - "bundled": true - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "underscore.string": { - "version": "3.3.4", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "unpipe": { - "version": "1.0.0", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.3.2", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "xml2js": { - "version": "0.4.15", - "bundled": true, - "requires": { - "sax": "1.1.5", - "xmlbuilder": "2.6.2" - } - }, - "xmlbuilder": { - "version": "2.6.2", - "bundled": true, - "requires": { - "lodash": "3.5.0" - }, - "dependencies": { - "lodash": { - "version": "3.5.0", - "bundled": true - } - } - }, - "xregexp": { - "version": "2.0.0", - "bundled": true - }, - "xtend": { - "version": "4.0.1", - "bundled": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true - }, - "zip-stream": { - "version": "0.5.2", - "bundled": true, - "requires": { - "compress-commons": "0.2.9", - "lodash": "3.2.0", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "lodash": { - "version": "3.2.0", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - } - } - }, - "amplify-category-storage": { - "version": "file:../amplify-category-storage", - "requires": { - "eslint": "4.19.1", - "inquirer": "3.3.0", - "uuid": "2.0.3" - }, - "dependencies": { - "acorn": { - "version": "5.6.2", - "bundled": true - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "ansi-escapes": { - "version": "3.1.0", - "bundled": true - }, - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "argparse": { - "version": "1.0.10", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.1.0", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.1", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "doctrine": { - "version": "2.1.0", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "eslint": { - "version": "4.19.1", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.5.0", - "ignore": "3.3.8", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "bundled": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "bundled": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "bundled": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.12.0", - "bundled": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "bundled": true - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.4", - "bundled": true, - "requires": { - "acorn": "5.6.2", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "external-editor": { - "version": "2.2.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.5.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.8", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.1.0", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.12.0", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "p-limit": { - "version": "1.3.0", - "bundled": true, - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "regexpp": { - "version": "1.1.0", - "bundled": true - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.7.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "3.0.0" - } - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "2.0.3", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "yallist": { - "version": "2.1.2", - "bundled": true - } - } - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha1-MtHWU+HZBAiFS/spbwdux+GGowA=", - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - }, - "dependencies": { - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - } - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - } - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "requires": { - "color-convert": "1.9.2" - }, - "dependencies": { - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", - "requires": { - "color-name": "1.1.1" - }, - "dependencies": { - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - } - } - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", - "requires": { - "has-flag": "3.0.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - } - } - } - } - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha1-h/yqOimDWOCt5uRCz86EB0DRrQQ=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - } - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - } - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "1.0.0" - }, - "dependencies": { - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "requires": { - "isexe": "2.0.0" - }, - "dependencies": { - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - } - } - } - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", - "requires": { - "esutils": "2.0.2" - } - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - }, - "dependencies": { - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - } - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=" - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", - "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha1-8JWCkpdwanyXdpWMCvyJMKm52dg=" - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" - } - } - } - } - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", - "requires": { - "estraverse": "4.2.0" - }, - "dependencies": { - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - } - } - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - }, - "dependencies": { - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - }, - "dependencies": { - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=" - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - }, - "dependencies": { - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "1.0.3" - }, - "dependencies": { - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - } - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - } - } - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", - "requires": { - "is-path-inside": "1.0.1" - }, - "dependencies": { - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "1.0.2" - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", - "requires": { - "glob": "7.1.2" - } - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "requires": { - "mkdirp": "0.5.1" - } - } - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - } - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - }, - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - }, - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - } - } - }, - "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha1-pYP6pDBVsayncZFL9oJY4vwSVnM=" - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=" - }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "requires": { - "sprintf-js": "1.0.3" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - } - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" - } - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - }, - "dependencies": { - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "1.1.2" - } - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "requires": { - "brace-expansion": "1.1.11" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - }, - "dependencies": { - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "1.1.2" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - } - } - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=" - }, - "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - }, - "dependencies": { - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "requires": { - "callsites": "0.2.0" - }, - "dependencies": { - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" - } - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" - } - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - }, - "dependencies": { - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", - "requires": { - "is-fullwidth-code-point": "2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - } - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", - "integrity": "sha1-OGRB5UoSzNlXsKklZKS6/r10eUQ=", - "dev": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - }, - "dependencies": { - "eslint-restricted-globals": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", - "dev": true - } - } - }, - "eslint-plugin-import": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", - "integrity": "sha1-3yTyQRdeMS2RZi3JHKhAZMrsFO0=", - "dev": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" - }, - "dependencies": { - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", - "dev": true - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", - "dev": true, - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "dev": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - }, - "dependencies": { - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", - "dev": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "dev": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "dev": true, - "requires": { - "find-up": "1.1.2" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true - } - } - } - } - } - } - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "dev": true, - "requires": { - "function-bind": "1.1.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", - "dev": true - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "dev": true, - "requires": { - "brace-expansion": "1.1.11" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "dev": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - } - } - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "dev": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "dev": true, - "requires": { - "locate-path": "2.0.0" - }, - "dependencies": { - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "dev": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "dev": true, - "requires": { - "p-limit": "1.3.0" - }, - "dependencies": { - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", - "dev": true, - "requires": { - "p-try": "1.0.0" - }, - "dependencies": { - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", - "dev": true - } - } - } - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } - } - } - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "dev": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "dev": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", - "dev": true - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "requires": { - "error-ex": "1.3.2" - }, - "dependencies": { - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "dev": true, - "requires": { - "is-arrayish": "0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - } - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", - "dev": true, - "requires": { - "hosted-git-info": "2.6.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha1-bkzueLAbuEnc+TUncIxp/b7kEN8=", - "dev": true - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "dev": true, - "requires": { - "builtin-modules": "1.1.1" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - } - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", - "dev": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - }, - "dependencies": { - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", - "dev": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - }, - "dependencies": { - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", - "dev": true - } - } - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", - "dev": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - }, - "dependencies": { - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=", - "dev": true - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=", - "dev": true - } - } - } - } - } - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "dev": true, - "requires": { - "pify": "2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true - } - } - } - } - } - } - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha1-gvHsGaQjrB+9CAsLqwa6NuhKeiY=", - "dev": true, - "requires": { - "path-parse": "1.0.5" - }, - "dependencies": { - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", - "dev": true - } - } - } - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha1-ndLyrXZdyrH/BEO0kUQqILoifck=", - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "requires": { - "color-convert": "1.9.2" - }, - "dependencies": { - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", - "requires": { - "color-name": "1.1.1" - }, - "dependencies": { - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - } - } - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", - "requires": { - "has-flag": "3.0.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - } - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "2.0.0" - }, - "dependencies": { - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - }, - "dependencies": { - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "1.2.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" - } - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - } - } - } - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - }, - "dependencies": { - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", - "requires": { - "safer-buffer": "2.1.2" - }, - "dependencies": { - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", - "requires": { - "os-tmpdir": "1.0.2" - }, - "dependencies": { - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - } - } - } - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "requires": { - "is-promise": "2.1.0" - }, - "dependencies": { - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - } - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "requires": { - "rx-lite": "4.0.8" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - } - } - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - } - } -} From 5874e7a13ae897df7b277b405bea3014e2ee183c Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Sun, 8 Jul 2018 12:23:49 -0700 Subject: [PATCH 019/587] simple fix --- .../amplify-category-api/package-lock.json | 6430 +++++++++++++++++ 1 file changed, 6430 insertions(+) create mode 100644 packages/amplify-category-api/package-lock.json diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json new file mode 100644 index 0000000000..47beaf4087 --- /dev/null +++ b/packages/amplify-category-api/package-lock.json @@ -0,0 +1,6430 @@ +{ + "requires": true, + "lockfileVersion": 1, + "dependencies": { + "amplify-category-function": { + "version": "file:../amplify-category-function", + "requires": { + "eslint": "4.19.1", + "grunt": "1.0.3", + "grunt-aws-lambda": "0.13.0", + "inquirer": "3.3.0", + "uuid": "3.3.2" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true + }, + "acorn": { + "version": "5.7.1", + "bundled": true + }, + "acorn-jsx": { + "version": "3.0.1", + "bundled": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "bundled": true + } + } + }, + "agent-base": { + "version": "4.2.1", + "bundled": true, + "requires": { + "es6-promisify": "5.0.0" + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "bundled": true + }, + "ansi-escapes": { + "version": "3.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "archiver": { + "version": "0.14.4", + "bundled": true, + "requires": { + "async": "0.9.2", + "buffer-crc32": "0.2.13", + "glob": "4.3.5", + "lazystream": "0.1.0", + "lodash": "3.2.0", + "readable-stream": "1.0.34", + "tar-stream": "1.1.5", + "zip-stream": "0.5.2" + }, + "dependencies": { + "async": { + "version": "0.9.2", + "bundled": true + }, + "glob": { + "version": "4.3.5", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "lodash": { + "version": "3.2.0", + "bundled": true + }, + "minimatch": { + "version": "2.0.10", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "argparse": { + "version": "1.0.10", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-find-index": { + "version": "1.0.2", + "bundled": true + }, + "array-union": { + "version": "1.0.2", + "bundled": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "bundled": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true + }, + "ast-types": { + "version": "0.11.5", + "bundled": true + }, + "async": { + "version": "1.5.2", + "bundled": true + }, + "aws-sdk": { + "version": "2.2.48", + "bundled": true, + "requires": { + "sax": "1.1.5", + "xml2js": "0.4.15", + "xmlbuilder": "2.6.2" + } + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "bl": { + "version": "0.9.5", + "bundled": true, + "requires": { + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "bundled": true + }, + "buffer-from": { + "version": "1.1.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "bytes": { + "version": "3.0.0", + "bundled": true + }, + "caller-path": { + "version": "0.1.0", + "bundled": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "bundled": true + }, + "camelcase": { + "version": "2.1.1", + "bundled": true + }, + "camelcase-keys": { + "version": "2.1.0", + "bundled": true, + "requires": { + "camelcase": "2.1.1", + "map-obj": "1.0.1" + } + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "1.9.2" + } + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "3.0.0" + } + } + } + }, + "chardet": { + "version": "0.4.2", + "bundled": true + }, + "circular-json": { + "version": "0.3.3", + "bundled": true + }, + "cli-cursor": { + "version": "2.1.0", + "bundled": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "coffeescript": { + "version": "1.10.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.2", + "bundled": true, + "requires": { + "color-name": "1.1.1" + } + }, + "color-name": { + "version": "1.1.1", + "bundled": true + }, + "colors": { + "version": "1.1.2", + "bundled": true + }, + "compress-commons": { + "version": "0.2.9", + "bundled": true, + "requires": { + "buffer-crc32": "0.2.13", + "crc32-stream": "0.3.4", + "node-int64": "0.3.3", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "crc32-stream": { + "version": "0.3.4", + "bundled": true, + "requires": { + "buffer-crc32": "0.2.13", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "bundled": true, + "requires": { + "array-find-index": "1.0.2" + } + }, + "data-uri-to-buffer": { + "version": "1.2.0", + "bundled": true + }, + "dateformat": { + "version": "1.0.12", + "bundled": true, + "requires": { + "get-stdin": "4.0.1", + "meow": "3.7.0" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "bundled": true + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "degenerator": { + "version": "1.0.4", + "bundled": true, + "requires": { + "ast-types": "0.11.5", + "escodegen": "1.10.0", + "esprima": "3.1.3" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "bundled": true + } + } + }, + "del": { + "version": "2.2.2", + "bundled": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "depd": { + "version": "1.1.2", + "bundled": true + }, + "doctrine": { + "version": "2.1.0", + "bundled": true, + "requires": { + "esutils": "2.0.2" + } + }, + "end-of-stream": { + "version": "1.4.1", + "bundled": true, + "requires": { + "once": "1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es6-promise": { + "version": "4.2.4", + "bundled": true + }, + "es6-promisify": { + "version": "5.0.0", + "bundled": true, + "requires": { + "es6-promise": "4.2.4" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "escodegen": { + "version": "1.10.0", + "bundled": true, + "requires": { + "esprima": "3.1.3", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.6.1" + }, + "dependencies": { + "esprima": { + "version": "3.1.3", + "bundled": true + } + } + }, + "eslint": { + "version": "4.19.1", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "bundled": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "bundled": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "resolve": { + "version": "1.8.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "bundled": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "bundled": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + }, + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "2.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "requires": { + "pify": "2.3.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "resolve": { + "version": "1.8.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "bundled": true + }, + "eslint-scope": { + "version": "3.7.1", + "bundled": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "bundled": true + }, + "espree": { + "version": "3.5.4", + "bundled": true, + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "bundled": true + }, + "esquery": { + "version": "1.0.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "eventemitter2": { + "version": "0.4.14", + "bundled": true + }, + "exit": { + "version": "0.1.2", + "bundled": true + }, + "extend": { + "version": "3.0.1", + "bundled": true + }, + "external-editor": { + "version": "2.2.0", + "bundled": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "figures": { + "version": "2.0.0", + "bundled": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "bundled": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "file-uri-to-path": { + "version": "1.0.0", + "bundled": true + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "findup-sync": { + "version": "0.3.0", + "bundled": true, + "requires": { + "glob": "5.0.15" + }, + "dependencies": { + "glob": { + "version": "5.0.15", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + } + } + }, + "flat-cache": { + "version": "1.3.0", + "bundled": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "ftp": { + "version": "0.3.10", + "bundled": true, + "requires": { + "readable-stream": "1.1.14", + "xregexp": "2.0.0" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.1.14", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "bundled": true + }, + "get-stdin": { + "version": "4.0.1", + "bundled": true + }, + "get-uri": { + "version": "2.0.2", + "bundled": true, + "requires": { + "data-uri-to-buffer": "1.2.0", + "debug": "2.6.9", + "extend": "3.0.1", + "file-uri-to-path": "1.0.0", + "ftp": "0.3.10", + "readable-stream": "2.3.6" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "getobject": { + "version": "0.1.0", + "bundled": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.7.0", + "bundled": true + }, + "globby": { + "version": "5.0.0", + "bundled": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "grunt": { + "version": "1.0.3", + "bundled": true, + "requires": { + "coffeescript": "1.10.0", + "dateformat": "1.0.12", + "eventemitter2": "0.4.14", + "exit": "0.1.2", + "findup-sync": "0.3.0", + "glob": "7.0.6", + "grunt-cli": "1.2.0", + "grunt-known-options": "1.1.0", + "grunt-legacy-log": "2.0.0", + "grunt-legacy-util": "1.1.1", + "iconv-lite": "0.4.23", + "js-yaml": "3.5.5", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "path-is-absolute": "1.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "esprima": { + "version": "2.7.3", + "bundled": true + }, + "glob": { + "version": "7.0.6", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "grunt-cli": { + "version": "1.2.0", + "bundled": true, + "requires": { + "findup-sync": "0.3.0", + "grunt-known-options": "1.1.0", + "nopt": "3.0.6", + "resolve": "1.1.7" + } + }, + "js-yaml": { + "version": "3.5.5", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "2.7.3" + } + } + } + }, + "grunt-aws-lambda": { + "version": "0.13.0", + "bundled": true, + "requires": { + "archiver": "0.14.4", + "aws-sdk": "2.2.48", + "glob": "4.3.5", + "mkdirp": "0.5.1", + "npm": "2.15.12", + "proxy-agent": "3.0.0", + "q": "1.5.1", + "rimraf": "2.2.8", + "temporary": "0.0.8" + }, + "dependencies": { + "glob": { + "version": "4.3.5", + "bundled": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "2.0.10", + "once": "1.4.0" + } + }, + "minimatch": { + "version": "2.0.10", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "proxy-agent": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "lru-cache": "4.1.3", + "pac-proxy-agent": "2.0.2", + "proxy-from-env": "1.0.0", + "socks-proxy-agent": "3.0.1" + }, + "dependencies": { + "agent-base": { + "version": "4.2.1", + "bundled": true, + "requires": { + "es6-promisify": "5.0.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "pac-proxy-agent": { + "version": "2.0.2", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "get-uri": "2.0.2", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "pac-resolver": "3.0.0", + "raw-body": "2.3.3", + "socks-proxy-agent": "3.0.1" + } + }, + "proxy-from-env": { + "version": "1.0.0", + "bundled": true + }, + "socks-proxy-agent": { + "version": "3.0.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "socks": "1.1.10" + } + } + } + }, + "rimraf": { + "version": "2.2.8", + "bundled": true + } + } + }, + "grunt-known-options": { + "version": "1.1.0", + "bundled": true + }, + "grunt-legacy-log": { + "version": "2.0.0", + "bundled": true, + "requires": { + "colors": "1.1.2", + "grunt-legacy-log-utils": "2.0.1", + "hooker": "0.2.3", + "lodash": "4.17.10" + } + }, + "grunt-legacy-log-utils": { + "version": "2.0.1", + "bundled": true, + "requires": { + "chalk": "2.4.1", + "lodash": "4.17.10" + } + }, + "grunt-legacy-util": { + "version": "1.1.1", + "bundled": true, + "requires": { + "async": "1.5.2", + "exit": "0.1.2", + "getobject": "0.1.0", + "hooker": "0.2.3", + "lodash": "4.17.10", + "underscore.string": "3.3.4", + "which": "1.3.1" + } + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hooker": { + "version": "0.2.3", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.1", + "bundled": true + }, + "http-errors": { + "version": "1.6.3", + "bundled": true, + "requires": { + "depd": "1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": "1.5.0" + } + }, + "http-proxy-agent": { + "version": "2.1.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "https-proxy-agent": { + "version": "2.2.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0" + } + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.10", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "indent-string": { + "version": "2.1.0", + "bundled": true, + "requires": { + "repeating": "2.0.1" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "inquirer": { + "version": "3.3.0", + "bundled": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "ip": { + "version": "1.1.5", + "bundled": true + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-finite": { + "version": "1.0.2", + "bundled": true, + "requires": { + "number-is-nan": "1.0.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-path-cwd": { + "version": "1.0.0", + "bundled": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "bundled": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "bundled": true + }, + "is-resolvable": { + "version": "1.1.0", + "bundled": true + }, + "is-utf8": { + "version": "0.2.1", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true + }, + "js-yaml": { + "version": "3.12.0", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "bundled": true + }, + "lazystream": { + "version": "0.1.0", + "bundled": true, + "requires": { + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "strip-bom": "2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true + }, + "loud-rejection": { + "version": "1.6.0", + "bundled": true, + "requires": { + "currently-unhandled": "0.4.1", + "signal-exit": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "map-obj": { + "version": "1.0.1", + "bundled": true + }, + "meow": { + "version": "3.7.0", + "bundled": true, + "requires": { + "camelcase-keys": "2.1.0", + "decamelize": "1.2.0", + "loud-rejection": "1.6.0", + "map-obj": "1.0.1", + "minimist": "1.2.0", + "normalize-package-data": "2.4.0", + "object-assign": "4.1.1", + "read-pkg-up": "1.0.1", + "redent": "1.0.0", + "trim-newlines": "1.0.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true + } + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "natural-compare": { + "version": "1.4.0", + "bundled": true + }, + "netmask": { + "version": "1.0.6", + "bundled": true + }, + "node-int64": { + "version": "0.3.3", + "bundled": true + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "npm": { + "version": "2.15.12", + "bundled": true, + "requires": { + "abbrev": "1.0.9", + "ansi": "0.3.1", + "ansi-regex": "2.0.0", + "ansicolors": "0.3.2", + "ansistyles": "0.1.3", + "archy": "1.0.0", + "async-some": "1.0.2", + "block-stream": "0.0.9", + "char-spinner": "1.0.1", + "chmodr": "1.0.2", + "chownr": "1.0.1", + "cmd-shim": "2.0.2", + "columnify": "1.5.4", + "config-chain": "1.1.10", + "dezalgo": "1.0.3", + "editor": "1.0.0", + "fs-vacuum": "1.2.9", + "fs-write-stream-atomic": "1.0.8", + "fstream": "1.0.10", + "fstream-npm": "1.1.1", + "github-url-from-git": "1.4.0", + "github-url-from-username-repo": "1.0.2", + "glob": "7.0.6", + "graceful-fs": "4.1.6", + "hosted-git-info": "2.1.5", + "imurmurhash": "0.1.4", + "inflight": "1.0.5", + "inherits": "2.0.3", + "ini": "1.3.4", + "init-package-json": "1.9.4", + "lockfile": "1.0.1", + "lru-cache": "4.0.1", + "minimatch": "3.0.3", + "mkdirp": "0.5.1", + "node-gyp": "3.6.0", + "nopt": "3.0.6", + "normalize-git-url": "3.0.2", + "normalize-package-data": "2.3.5", + "npm-cache-filename": "1.0.2", + "npm-install-checks": "1.0.7", + "npm-package-arg": "4.1.0", + "npm-registry-client": "7.2.1", + "npm-user-validate": "0.1.5", + "npmlog": "2.0.4", + "once": "1.4.0", + "opener": "1.4.1", + "osenv": "0.1.3", + "path-is-inside": "1.0.1", + "read": "1.0.7", + "read-installed": "4.0.3", + "read-package-json": "2.0.4", + "readable-stream": "2.1.5", + "realize-package-specifier": "3.0.1", + "request": "2.74.0", + "retry": "0.10.0", + "rimraf": "2.5.4", + "semver": "5.1.0", + "sha": "2.0.1", + "slide": "1.1.6", + "sorted-object": "2.0.0", + "spdx-license-ids": "1.2.2", + "strip-ansi": "3.0.1", + "tar": "2.2.1", + "text-table": "0.2.0", + "uid-number": "0.0.6", + "umask": "1.1.0", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "2.2.2", + "which": "1.2.11", + "wrappy": "1.0.2", + "write-file-atomic": "1.1.4" + }, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "bundled": true + }, + "ansi": { + "version": "0.3.1", + "bundled": true + }, + "ansi-regex": { + "version": "2.0.0", + "bundled": true + }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "async-some": { + "version": "1.0.2", + "bundled": true, + "requires": { + "dezalgo": "1.0.3" + } + }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "char-spinner": { + "version": "1.0.1", + "bundled": true + }, + "chmodr": { + "version": "1.0.2", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "mkdirp": "0.5.1" + } + }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.0" + }, + "dependencies": { + "wcwidth": { + "version": "1.0.0", + "bundled": true, + "requires": { + "defaults": "1.0.3" + }, + "dependencies": { + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "1.0.2" + }, + "dependencies": { + "clone": { + "version": "1.0.2", + "bundled": true + } + } + } + } + } + } + }, + "config-chain": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ini": "1.3.4", + "proto-list": "1.2.4" + }, + "dependencies": { + "proto-list": { + "version": "1.2.4", + "bundled": true + } + } + }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "2.0.3", + "wrappy": "1.0.2" + }, + "dependencies": { + "asap": { + "version": "2.0.3", + "bundled": true + } + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, + "fs-vacuum": { + "version": "1.2.9", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "path-is-inside": "1.0.1", + "rimraf": "2.5.4" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.8", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.1.5" + }, + "dependencies": { + "iferr": { + "version": "0.1.5", + "bundled": true + } + } + }, + "fstream": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.5.4" + } + }, + "fstream-npm": { + "version": "1.1.1", + "bundled": true, + "requires": { + "fstream-ignore": "1.0.5", + "inherits": "2.0.3" + }, + "dependencies": { + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.10", + "inherits": "2.0.3", + "minimatch": "3.0.3" + } + } + } + }, + "github-url-from-git": { + "version": "1.4.0", + "bundled": true + }, + "github-url-from-username-repo": { + "version": "1.0.2", + "bundled": true + }, + "glob": { + "version": "7.0.6", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "graceful-fs": { + "version": "4.1.6", + "bundled": true + }, + "hosted-git-info": { + "version": "2.1.5", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.5", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "ini": { + "version": "1.3.4", + "bundled": true + }, + "init-package-json": { + "version": "1.9.4", + "bundled": true, + "requires": { + "glob": "6.0.4", + "npm-package-arg": "4.1.0", + "promzard": "0.3.0", + "read": "1.0.7", + "read-package-json": "2.0.4", + "semver": "5.1.0", + "validate-npm-package-license": "3.0.1", + "validate-npm-package-name": "2.2.2" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1.0.7" + } + } + } + }, + "lockfile": { + "version": "1.0.1", + "bundled": true + }, + "lru-cache": { + "version": "4.0.1", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.0.0" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "yallist": { + "version": "2.0.0", + "bundled": true + } + } + }, + "minimatch": { + "version": "3.0.3", + "bundled": true, + "requires": { + "brace-expansion": "1.1.6" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.6", + "bundled": true, + "requires": { + "balanced-match": "0.4.2", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "0.4.2", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "bundled": true + } + } + }, + "node-gyp": { + "version": "3.6.0", + "bundled": true, + "requires": { + "fstream": "1.0.10", + "glob": "7.0.6", + "graceful-fs": "4.1.6", + "minimatch": "3.0.3", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "2.0.4", + "osenv": "0.1.3", + "request": "2.74.0", + "rimraf": "2.5.4", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.2.11" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "bundled": true + } + } + }, + "nopt": { + "version": "3.0.6", + "bundled": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "normalize-git-url": { + "version": "3.0.2", + "bundled": true + }, + "normalize-package-data": { + "version": "2.3.5", + "bundled": true, + "requires": { + "hosted-git-info": "2.1.5", + "is-builtin-module": "1.0.0", + "semver": "5.1.0", + "validate-npm-package-license": "3.0.1" + }, + "dependencies": { + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.0" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.0", + "bundled": true + } + } + } + } + }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "1.0.7", + "bundled": true, + "requires": { + "npmlog": "2.0.4", + "semver": "5.1.0" + } + }, + "npm-package-arg": { + "version": "4.1.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.1.5", + "semver": "5.1.0" + } + }, + "npm-registry-client": { + "version": "7.2.1", + "bundled": true, + "requires": { + "concat-stream": "1.5.2", + "graceful-fs": "4.1.6", + "normalize-package-data": "2.3.5", + "npm-package-arg": "4.1.0", + "npmlog": "2.0.4", + "once": "1.4.0", + "request": "2.74.0", + "retry": "0.10.0", + "semver": "5.1.0", + "slide": "1.1.6" + }, + "dependencies": { + "concat-stream": { + "version": "1.5.2", + "bundled": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.0.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + } + } + }, + "npm-user-validate": { + "version": "0.1.5", + "bundled": true + }, + "npmlog": { + "version": "2.0.4", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "are-we-there-yet": "1.1.2", + "gauge": "1.2.7" + }, + "dependencies": { + "are-we-there-yet": { + "version": "1.1.2", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.1.5" + }, + "dependencies": { + "delegates": { + "version": "1.0.0", + "bundled": true + } + } + }, + "gauge": { + "version": "1.2.7", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "has-unicode": "2.0.0", + "lodash.pad": "4.4.0", + "lodash.padend": "4.5.0", + "lodash.padstart": "4.5.0" + }, + "dependencies": { + "has-unicode": { + "version": "2.0.0", + "bundled": true + }, + "lodash._baseslice": { + "version": "4.0.0", + "bundled": true + }, + "lodash._basetostring": { + "version": "4.12.0", + "bundled": true + }, + "lodash.pad": { + "version": "4.4.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.padend": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.padstart": { + "version": "4.5.0", + "bundled": true, + "requires": { + "lodash._baseslice": "4.0.0", + "lodash._basetostring": "4.12.0", + "lodash.tostring": "4.1.4" + } + }, + "lodash.tostring": { + "version": "4.1.4", + "bundled": true + } + } + } + } + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "opener": { + "version": "1.4.1", + "bundled": true + }, + "osenv": { + "version": "0.1.3", + "bundled": true, + "requires": { + "os-homedir": "1.0.0", + "os-tmpdir": "1.0.1" + }, + "dependencies": { + "os-homedir": { + "version": "1.0.0", + "bundled": true + }, + "os-tmpdir": { + "version": "1.0.1", + "bundled": true + } + } + }, + "path-is-inside": { + "version": "1.0.1", + "bundled": true + }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "0.0.5" + }, + "dependencies": { + "mute-stream": { + "version": "0.0.5", + "bundled": true + } + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "graceful-fs": "4.1.6", + "read-package-json": "2.0.4", + "readdir-scoped-modules": "1.0.2", + "semver": "5.1.0", + "slide": "1.1.6", + "util-extend": "1.0.1" + }, + "dependencies": { + "debuglog": { + "version": "1.0.1", + "bundled": true + }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "graceful-fs": "4.1.6", + "once": "1.4.0" + } + }, + "util-extend": { + "version": "1.0.1", + "bundled": true + } + } + }, + "read-package-json": { + "version": "2.0.4", + "bundled": true, + "requires": { + "glob": "6.0.4", + "graceful-fs": "4.1.6", + "json-parse-helpfulerror": "1.0.3", + "normalize-package-data": "2.3.5" + }, + "dependencies": { + "glob": { + "version": "6.0.4", + "bundled": true, + "requires": { + "inflight": "1.0.5", + "inherits": "2.0.3", + "minimatch": "3.0.3", + "once": "1.4.0", + "path-is-absolute": "1.0.0" + }, + "dependencies": { + "path-is-absolute": { + "version": "1.0.0", + "bundled": true + } + } + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "bundled": true, + "requires": { + "jju": "1.3.0" + }, + "dependencies": { + "jju": { + "version": "1.3.0", + "bundled": true + } + } + } + } + }, + "readable-stream": { + "version": "2.1.5", + "bundled": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + }, + "realize-package-specifier": { + "version": "3.0.1", + "bundled": true, + "requires": { + "dezalgo": "1.0.3", + "npm-package-arg": "4.1.0" + } + }, + "request": { + "version": "2.74.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.4.1", + "bl": "1.1.2", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.0", + "forever-agent": "0.6.1", + "form-data": "1.0.0-rc4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.11", + "node-uuid": "1.4.7", + "oauth-sign": "0.8.2", + "qs": "6.2.1", + "stringstream": "0.0.5", + "tough-cookie": "2.3.1", + "tunnel-agent": "0.4.3" + }, + "dependencies": { + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.4.1", + "bundled": true + }, + "bl": { + "version": "1.1.2", + "bundled": true, + "requires": { + "readable-stream": "2.0.6" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + } + } + } + } + }, + "caseless": { + "version": "0.11.0", + "bundled": true + }, + "combined-stream": { + "version": "1.0.5", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + }, + "dependencies": { + "delayed-stream": { + "version": "1.0.0", + "bundled": true + } + } + }, + "extend": { + "version": "3.0.0", + "bundled": true + }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "1.0.0-rc4", + "bundled": true, + "requires": { + "async": "1.5.2", + "combined-stream": "1.0.5", + "mime-types": "2.1.11" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "bundled": true + } + } + }, + "har-validator": { + "version": "2.0.6", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.9.0", + "is-my-json-valid": "2.13.1", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "commander": { + "version": "2.9.0", + "bundled": true, + "requires": { + "graceful-readlink": "1.0.1" + }, + "dependencies": { + "graceful-readlink": { + "version": "1.0.1", + "bundled": true + } + } + }, + "is-my-json-valid": { + "version": "2.13.1", + "bundled": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "2.0.0", + "xtend": "4.0.1" + }, + "dependencies": { + "generate-function": { + "version": "2.0.0", + "bundled": true + }, + "generate-object-property": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-property": "1.0.2" + }, + "dependencies": { + "is-property": { + "version": "1.0.2", + "bundled": true + } + } + }, + "jsonpointer": { + "version": "2.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + } + } + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "bundled": true + } + } + } + } + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + }, + "dependencies": { + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + } + } + }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.3.0", + "sshpk": "1.9.2" + }, + "dependencies": { + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, + "jsprim": { + "version": "1.3.0", + "bundled": true, + "requires": { + "extsprintf": "1.0.2", + "json-schema": "0.2.2", + "verror": "1.3.6" + }, + "dependencies": { + "extsprintf": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.2", + "bundled": true + }, + "verror": { + "version": "1.3.6", + "bundled": true, + "requires": { + "extsprintf": "1.0.2" + } + } + } + }, + "sshpk": { + "version": "1.9.2", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "dashdash": "1.14.0", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.6", + "jodid25519": "1.0.2", + "jsbn": "0.1.0", + "tweetnacl": "0.13.3" + }, + "dependencies": { + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "1.0.0", + "bundled": true + }, + "dashdash": { + "version": "1.14.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "getpass": { + "version": "0.1.6", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + } + }, + "jodid25519": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.0" + } + }, + "jsbn": { + "version": "0.1.0", + "bundled": true, + "optional": true + }, + "tweetnacl": { + "version": "0.13.3", + "bundled": true, + "optional": true + } + } + } + } + }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "mime-types": { + "version": "2.1.11", + "bundled": true, + "requires": { + "mime-db": "1.23.0" + }, + "dependencies": { + "mime-db": { + "version": "1.23.0", + "bundled": true + } + } + }, + "node-uuid": { + "version": "1.4.7", + "bundled": true + }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, + "qs": { + "version": "6.2.1", + "bundled": true + }, + "stringstream": { + "version": "0.0.5", + "bundled": true + }, + "tough-cookie": { + "version": "2.3.1", + "bundled": true + }, + "tunnel-agent": { + "version": "0.4.3", + "bundled": true + } + } + }, + "retry": { + "version": "0.10.0", + "bundled": true + }, + "rimraf": { + "version": "2.5.4", + "bundled": true, + "requires": { + "glob": "7.0.6" + } + }, + "semver": { + "version": "5.1.0", + "bundled": true + }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "readable-stream": "2.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "2.0.2", + "bundled": true, + "requires": { + "core-util-is": "1.0.1", + "inherits": "2.0.3", + "isarray": "0.0.1", + "process-nextick-args": "1.0.3", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.1" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.1", + "bundled": true + }, + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.3", + "bundled": true + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.1", + "bundled": true + } + } + } + } + }, + "slide": { + "version": "1.1.6", + "bundled": true + }, + "sorted-object": { + "version": "2.0.0", + "bundled": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "bundled": true + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.0.0" + } + }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.10", + "inherits": "2.0.3" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "bundled": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.2" + }, + "dependencies": { + "spdx-correct": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.2", + "bundled": true, + "requires": { + "spdx-exceptions": "1.0.4", + "spdx-license-ids": "1.2.2" + }, + "dependencies": { + "spdx-exceptions": { + "version": "1.0.4", + "bundled": true + } + } + } + } + }, + "validate-npm-package-name": { + "version": "2.2.2", + "bundled": true, + "requires": { + "builtins": "0.0.7" + }, + "dependencies": { + "builtins": { + "version": "0.0.7", + "bundled": true + } + } + }, + "which": { + "version": "1.2.11", + "bundled": true, + "requires": { + "isexe": "1.1.2" + }, + "dependencies": { + "isexe": { + "version": "1.1.2", + "bundled": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write-file-atomic": { + "version": "1.1.4", + "bundled": true, + "requires": { + "graceful-fs": "4.1.6", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + } + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "bundled": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "pac-proxy-agent": { + "version": "2.0.2", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "get-uri": "2.0.2", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "pac-resolver": "3.0.0", + "raw-body": "2.3.3", + "socks-proxy-agent": "3.0.1" + } + }, + "pac-resolver": { + "version": "3.0.0", + "bundled": true, + "requires": { + "co": "4.6.0", + "degenerator": "1.0.4", + "ip": "1.1.5", + "netmask": "1.0.6", + "thunkify": "2.1.2" + } + }, + "package": { + "version": "1.0.1", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.2" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true + }, + "path-type": { + "version": "1.1.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "bundled": true + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "progress": { + "version": "2.0.0", + "bundled": true + }, + "proxy-agent": { + "version": "3.0.0", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "debug": "3.1.0", + "http-proxy-agent": "2.1.0", + "https-proxy-agent": "2.2.1", + "lru-cache": "4.1.3", + "pac-proxy-agent": "2.0.2", + "proxy-from-env": "1.0.0", + "socks-proxy-agent": "3.0.1" + } + }, + "proxy-from-env": { + "version": "1.0.0", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "q": { + "version": "1.5.1", + "bundled": true + }, + "raw-body": { + "version": "2.3.3", + "bundled": true, + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.3", + "iconv-lite": "0.4.23", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "bundled": true, + "requires": { + "load-json-file": "1.1.0", + "normalize-package-data": "2.4.0", + "path-type": "1.1.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "bundled": true, + "requires": { + "find-up": "1.1.2", + "read-pkg": "1.1.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "redent": { + "version": "1.0.0", + "bundled": true, + "requires": { + "indent-string": "2.1.0", + "strip-indent": "1.0.1" + } + }, + "regexpp": { + "version": "1.1.0", + "bundled": true + }, + "repeating": { + "version": "2.0.1", + "bundled": true, + "requires": { + "is-finite": "1.0.2" + } + }, + "require-uncached": { + "version": "1.0.3", + "bundled": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.1.7", + "bundled": true + }, + "resolve-from": { + "version": "1.0.1", + "bundled": true + }, + "restore-cursor": { + "version": "2.0.0", + "bundled": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "bundled": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "bundled": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "bundled": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "sax": { + "version": "1.1.5", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "setprototypeof": { + "version": "1.1.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slice-ansi": { + "version": "1.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "smart-buffer": { + "version": "1.1.15", + "bundled": true + }, + "socks": { + "version": "1.1.10", + "bundled": true, + "requires": { + "ip": "1.1.5", + "smart-buffer": "1.1.15" + } + }, + "socks-proxy-agent": { + "version": "3.0.1", + "bundled": true, + "requires": { + "agent-base": "4.2.1", + "socks": "1.1.10" + } + }, + "source-map": { + "version": "0.6.1", + "bundled": true, + "optional": true + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "statuses": { + "version": "1.5.0", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "bundled": true + } + } + }, + "strip-bom": { + "version": "2.0.0", + "bundled": true, + "requires": { + "is-utf8": "0.2.1" + } + }, + "strip-indent": { + "version": "1.0.1", + "bundled": true, + "requires": { + "get-stdin": "4.0.1" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + }, + "table": { + "version": "4.0.2", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "tar-stream": { + "version": "1.1.5", + "bundled": true, + "requires": { + "bl": "0.9.5", + "end-of-stream": "1.4.1", + "readable-stream": "1.0.34", + "xtend": "4.0.1" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, + "temporary": { + "version": "0.0.8", + "bundled": true, + "requires": { + "package": "1.0.1" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "thunkify": { + "version": "2.1.2", + "bundled": true + }, + "tmp": { + "version": "0.0.33", + "bundled": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "trim-newlines": { + "version": "1.0.0", + "bundled": true + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "underscore.string": { + "version": "3.3.4", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "unpipe": { + "version": "1.0.0", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "3.3.2", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write": { + "version": "0.2.1", + "bundled": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "xml2js": { + "version": "0.4.15", + "bundled": true, + "requires": { + "sax": "1.1.5", + "xmlbuilder": "2.6.2" + } + }, + "xmlbuilder": { + "version": "2.6.2", + "bundled": true, + "requires": { + "lodash": "3.5.0" + }, + "dependencies": { + "lodash": { + "version": "3.5.0", + "bundled": true + } + } + }, + "xregexp": { + "version": "2.0.0", + "bundled": true + }, + "xtend": { + "version": "4.0.1", + "bundled": true + }, + "yallist": { + "version": "2.1.2", + "bundled": true + }, + "zip-stream": { + "version": "0.5.2", + "bundled": true, + "requires": { + "compress-commons": "0.2.9", + "lodash": "3.2.0", + "readable-stream": "1.0.34" + }, + "dependencies": { + "isarray": { + "version": "0.0.1", + "bundled": true + }, + "lodash": { + "version": "3.2.0", + "bundled": true + }, + "readable-stream": { + "version": "1.0.34", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "0.0.1", + "string_decoder": "0.10.31" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + } + } + }, + "amplify-category-storage": { + "version": "file:../amplify-category-storage", + "requires": { + "eslint": "4.19.1", + "inquirer": "3.3.0", + "uuid": "2.0.3" + }, + "dependencies": { + "acorn": { + "version": "5.6.2", + "bundled": true + }, + "acorn-jsx": { + "version": "3.0.1", + "bundled": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "bundled": true + } + } + }, + "ajv": { + "version": "5.5.2", + "bundled": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "bundled": true + }, + "ansi-escapes": { + "version": "3.1.0", + "bundled": true + }, + "ansi-regex": { + "version": "3.0.0", + "bundled": true + }, + "ansi-styles": { + "version": "3.2.1", + "bundled": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "argparse": { + "version": "1.0.10", + "bundled": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-union": { + "version": "1.0.2", + "bundled": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "bundled": true + }, + "arrify": { + "version": "1.0.1", + "bundled": true + }, + "babel-code-frame": { + "version": "6.26.0", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + }, + "ansi-styles": { + "version": "2.2.1", + "bundled": true + }, + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "bundled": true + } + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "buffer-from": { + "version": "1.1.0", + "bundled": true + }, + "builtin-modules": { + "version": "1.1.1", + "bundled": true + }, + "caller-path": { + "version": "0.1.0", + "bundled": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "bundled": true + }, + "chalk": { + "version": "2.4.1", + "bundled": true, + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + } + }, + "chardet": { + "version": "0.4.2", + "bundled": true + }, + "circular-json": { + "version": "0.3.3", + "bundled": true + }, + "cli-cursor": { + "version": "2.1.0", + "bundled": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "bundled": true + }, + "co": { + "version": "4.6.0", + "bundled": true + }, + "color-convert": { + "version": "1.9.1", + "bundled": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "bundled": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true + }, + "concat-stream": { + "version": "1.6.2", + "bundled": true, + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "bundled": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true + }, + "cross-spawn": { + "version": "5.1.0", + "bundled": true, + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + } + }, + "debug": { + "version": "3.1.0", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "bundled": true + }, + "del": { + "version": "2.2.2", + "bundled": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.1.0", + "bundled": true, + "requires": { + "esutils": "2.0.2" + } + }, + "error-ex": { + "version": "1.3.1", + "bundled": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "bundled": true + }, + "eslint": { + "version": "4.19.1", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.5.0", + "ignore": "3.3.8", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "bundled": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "bundled": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "bundled": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.12.0", + "bundled": true, + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.7.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "bundled": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "bundled": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "bundled": true + }, + "eslint-scope": { + "version": "3.7.1", + "bundled": true, + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "bundled": true + }, + "espree": { + "version": "3.5.4", + "bundled": true, + "requires": { + "acorn": "5.6.2", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "bundled": true + }, + "esquery": { + "version": "1.0.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.1", + "bundled": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "bundled": true + }, + "esutils": { + "version": "2.0.2", + "bundled": true + }, + "external-editor": { + "version": "2.2.0", + "bundled": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.1.0", + "bundled": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "bundled": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "bundled": true + }, + "figures": { + "version": "2.0.0", + "bundled": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "bundled": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "find-up": { + "version": "1.1.2", + "bundled": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "bundled": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true + }, + "function-bind": { + "version": "1.1.1", + "bundled": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "bundled": true + }, + "glob": { + "version": "7.1.2", + "bundled": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "11.5.0", + "bundled": true + }, + "globby": { + "version": "5.0.0", + "bundled": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "bundled": true + }, + "has": { + "version": "1.0.3", + "bundled": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "bundled": true + } + } + }, + "has-flag": { + "version": "3.0.0", + "bundled": true + }, + "hosted-git-info": { + "version": "2.6.0", + "bundled": true + }, + "iconv-lite": { + "version": "0.4.23", + "bundled": true, + "requires": { + "safer-buffer": "2.1.2" + } + }, + "ignore": { + "version": "3.3.8", + "bundled": true + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true + }, + "inquirer": { + "version": "3.3.0", + "bundled": true, + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "is-arrayish": { + "version": "0.2.1", + "bundled": true + }, + "is-builtin-module": { + "version": "1.0.0", + "bundled": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "bundled": true + }, + "is-path-cwd": { + "version": "1.0.0", + "bundled": true + }, + "is-path-in-cwd": { + "version": "1.0.1", + "bundled": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "bundled": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "bundled": true + }, + "is-resolvable": { + "version": "1.1.0", + "bundled": true + }, + "isarray": { + "version": "1.0.0", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "js-tokens": { + "version": "3.0.2", + "bundled": true + }, + "js-yaml": { + "version": "3.12.0", + "bundled": true, + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "bundled": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "bundled": true + }, + "levn": { + "version": "0.3.0", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "bundled": true + } + } + }, + "lodash": { + "version": "4.17.10", + "bundled": true + }, + "lru-cache": { + "version": "4.1.3", + "bundled": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.2.0", + "bundled": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "requires": { + "brace-expansion": "1.1.11" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "bundled": true + }, + "mute-stream": { + "version": "0.0.7", + "bundled": true + }, + "natural-compare": { + "version": "1.4.0", + "bundled": true + }, + "normalize-package-data": { + "version": "2.4.0", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "object-assign": { + "version": "4.1.1", + "bundled": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "bundled": true, + "requires": { + "mimic-fn": "1.2.0" + } + }, + "optionator": { + "version": "0.8.2", + "bundled": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true + }, + "p-limit": { + "version": "1.3.0", + "bundled": true, + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "bundled": true, + "requires": { + "p-limit": "1.3.0" + } + }, + "p-try": { + "version": "1.0.0", + "bundled": true + }, + "parse-json": { + "version": "2.2.0", + "bundled": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "bundled": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true + }, + "path-is-inside": { + "version": "1.0.2", + "bundled": true + }, + "path-parse": { + "version": "1.0.5", + "bundled": true + }, + "path-type": { + "version": "2.0.0", + "bundled": true, + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "bundled": true + }, + "pinkie": { + "version": "2.0.4", + "bundled": true + }, + "pinkie-promise": { + "version": "2.0.1", + "bundled": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "bundled": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "bundled": true + }, + "prelude-ls": { + "version": "1.1.2", + "bundled": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true + }, + "progress": { + "version": "2.0.0", + "bundled": true + }, + "pseudomap": { + "version": "1.0.2", + "bundled": true + }, + "read-pkg": { + "version": "2.0.0", + "bundled": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "bundled": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "bundled": true, + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + } + }, + "regexpp": { + "version": "1.1.0", + "bundled": true + }, + "require-uncached": { + "version": "1.0.3", + "bundled": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.7.1", + "bundled": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "bundled": true + }, + "restore-cursor": { + "version": "2.0.0", + "bundled": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "bundled": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "bundled": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "bundled": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "bundled": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true + }, + "semver": { + "version": "5.5.0", + "bundled": true + }, + "shebang-command": { + "version": "1.2.0", + "bundled": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "bundled": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true + }, + "slice-ansi": { + "version": "1.0.0", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "spdx-correct": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "bundled": true, + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "bundled": true + }, + "sprintf-js": { + "version": "1.0.3", + "bundled": true + }, + "string-width": { + "version": "2.1.1", + "bundled": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "requires": { + "safe-buffer": "5.1.2" + } + }, + "strip-ansi": { + "version": "4.0.0", + "bundled": true, + "requires": { + "ansi-regex": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "bundled": true + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true + }, + "supports-color": { + "version": "5.4.0", + "bundled": true, + "requires": { + "has-flag": "3.0.0" + } + }, + "table": { + "version": "4.0.2", + "bundled": true, + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "through": { + "version": "2.3.8", + "bundled": true + }, + "tmp": { + "version": "0.0.33", + "bundled": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "type-check": { + "version": "0.3.2", + "bundled": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "bundled": true + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "uuid": { + "version": "2.0.3", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.3", + "bundled": true, + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "which": { + "version": "1.3.1", + "bundled": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "bundled": true + }, + "wrappy": { + "version": "1.0.2", + "bundled": true + }, + "write": { + "version": "0.2.1", + "bundled": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "bundled": true + } + } + }, + "eslint": { + "version": "4.19.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", + "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", + "requires": { + "ajv": "5.5.2", + "babel-code-frame": "6.26.0", + "chalk": "2.4.1", + "concat-stream": "1.6.2", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.1.0", + "eslint-scope": "3.7.1", + "eslint-visitor-keys": "1.0.0", + "espree": "3.5.4", + "esquery": "1.0.1", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.7.0", + "ignore": "3.3.10", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.1.0", + "js-yaml": "3.12.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "regexpp": "1.1.0", + "require-uncached": "1.0.3", + "semver": "5.5.0", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "ajv": { + "version": "5.5.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", + "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.1.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + }, + "dependencies": { + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "fast-deep-equal": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", + "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" + } + } + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" + } + } + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "1.9.2" + }, + "dependencies": { + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", + "requires": { + "color-name": "1.1.1" + }, + "dependencies": { + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + } + } + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "requires": { + "has-flag": "3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + } + } + } + } + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", + "requires": { + "buffer-from": "1.1.0", + "inherits": "2.0.3", + "readable-stream": "2.3.6", + "typedarray": "0.0.6" + }, + "dependencies": { + "buffer-from": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", + "integrity": "sha1-h/yqOimDWOCt5uRCz86EB0DRrQQ=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "2.0.0", + "safe-buffer": "5.1.2", + "string_decoder": "1.1.1", + "util-deprecate": "1.0.2" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + } + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + } + } + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.3", + "shebang-command": "1.2.0", + "which": "1.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", + "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + }, + "dependencies": { + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + } + } + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + }, + "dependencies": { + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", + "requires": { + "isexe": "2.0.0" + }, + "dependencies": { + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + } + } + } + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", + "requires": { + "esutils": "2.0.2" + } + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "requires": { + "esrecurse": "4.2.1", + "estraverse": "4.2.0" + }, + "dependencies": { + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", + "requires": { + "estraverse": "4.2.0" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + } + } + }, + "eslint-visitor-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", + "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=" + }, + "espree": { + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", + "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", + "requires": { + "acorn": "5.7.1", + "acorn-jsx": "3.0.1" + }, + "dependencies": { + "acorn": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", + "integrity": "sha1-8JWCkpdwanyXdpWMCvyJMKm52dg=" + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" + } + } + } + } + }, + "esquery": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", + "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", + "requires": { + "estraverse": "4.2.0" + }, + "dependencies": { + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" + } + } + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + }, + "dependencies": { + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + }, + "dependencies": { + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=" + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.1", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + }, + "dependencies": { + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "1.0.3" + }, + "dependencies": { + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + } + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + } + } + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" + }, + "is-path-in-cwd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", + "requires": { + "is-path-inside": "1.0.1" + }, + "dependencies": { + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "requires": { + "path-is-inside": "1.0.2" + } + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + } + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", + "requires": { + "glob": "7.1.2" + } + } + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "requires": { + "mkdirp": "0.5.1" + } + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + } + } + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + }, + "dependencies": { + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + }, + "dependencies": { + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + } + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + } + } + }, + "globals": { + "version": "11.7.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", + "integrity": "sha1-pYP6pDBVsayncZFL9oJY4vwSVnM=" + }, + "ignore": { + "version": "3.3.10", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", + "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=" + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "is-resolvable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", + "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=" + }, + "js-yaml": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", + "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", + "requires": { + "argparse": "1.0.10", + "esprima": "4.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", + "requires": { + "sprintf-js": "1.0.3" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + } + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" + } + } + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + }, + "dependencies": { + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.11" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + } + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + }, + "dependencies": { + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "requires": { + "prelude-ls": "1.1.2" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + } + } + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=" + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" + }, + "regexpp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", + "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=" + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + }, + "dependencies": { + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "requires": { + "callsites": "0.2.0" + }, + "dependencies": { + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" + } + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" + } + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", + "requires": { + "ajv": "5.5.2", + "ajv-keywords": "2.1.1", + "chalk": "2.4.1", + "lodash": "4.17.10", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + }, + "dependencies": { + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", + "requires": { + "is-fullwidth-code-point": "2.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" + } + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "requires": { + "eslint-restricted-globals": "0.1.1" + }, + "dependencies": { + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" + } + } + }, + "eslint-plugin-import": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", + "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", + "requires": { + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.2", + "eslint-module-utils": "2.2.0", + "has": "1.0.3", + "lodash": "4.17.10", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0", + "resolve": "1.8.1" + }, + "dependencies": { + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + }, + "dependencies": { + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", + "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", + "requires": { + "debug": "2.6.9", + "resolve": "1.8.1" + } + }, + "eslint-module-utils": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", + "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "requires": { + "find-up": "1.1.2" + }, + "dependencies": { + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "2.0.4" + }, + "dependencies": { + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" + } + } + } + } + } + } + } + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", + "requires": { + "function-bind": "1.1.1" + }, + "dependencies": { + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", + "requires": { + "brace-expansion": "1.1.11" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + } + } + } + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "2.0.0" + }, + "dependencies": { + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "1.3.0" + }, + "dependencies": { + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", + "requires": { + "p-try": "1.0.0" + }, + "dependencies": { + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + } + } + } + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + } + } + } + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.2" + }, + "dependencies": { + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", + "requires": { + "is-arrayish": "0.2.1" + }, + "dependencies": { + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + } + } + } + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + } + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", + "requires": { + "hosted-git-info": "2.6.1", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", + "integrity": "sha1-bkzueLAbuEnc+TUncIxp/b7kEN8=" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + }, + "dependencies": { + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + } + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + }, + "dependencies": { + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + }, + "dependencies": { + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" + } + } + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + }, + "dependencies": { + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=" + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" + } + } + } + } + } + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "2.3.0" + }, + "dependencies": { + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + } + } + } + } + } + } + }, + "resolve": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", + "integrity": "sha1-gvHsGaQjrB+9CAsLqwa6NuhKeiY=", + "requires": { + "path-parse": "1.0.5" + }, + "dependencies": { + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + } + } + } + } + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "requires": { + "ansi-escapes": "3.1.0", + "chalk": "2.4.1", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.2.0", + "figures": "2.0.0", + "lodash": "4.17.10", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + }, + "dependencies": { + "ansi-escapes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", + "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=" + }, + "chalk": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", + "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.4.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", + "requires": { + "color-convert": "1.9.2" + }, + "dependencies": { + "color-convert": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", + "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", + "requires": { + "color-name": "1.1.1" + }, + "dependencies": { + "color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" + } + } + } + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "supports-color": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", + "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", + "requires": { + "has-flag": "3.0.0" + }, + "dependencies": { + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + } + } + } + } + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "requires": { + "restore-cursor": "2.0.0" + }, + "dependencies": { + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + }, + "dependencies": { + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "requires": { + "mimic-fn": "1.2.0" + }, + "dependencies": { + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" + } + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + } + } + } + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" + }, + "external-editor": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", + "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.23", + "tmp": "0.0.33" + }, + "dependencies": { + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" + }, + "iconv-lite": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", + "requires": { + "safer-buffer": "2.1.2" + }, + "dependencies": { + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" + } + } + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", + "requires": { + "os-tmpdir": "1.0.2" + }, + "dependencies": { + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + } + } + } + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "requires": { + "escape-string-regexp": "1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + } + } + }, + "lodash": { + "version": "4.17.10", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", + "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "requires": { + "is-promise": "2.1.0" + }, + "dependencies": { + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + } + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "requires": { + "rx-lite": "4.0.8" + } + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + }, + "dependencies": { + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" + } + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + } + } + }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, + "uuid": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", + "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" + } + } +} From a4057ad07934c91fb93390519ebc6b2ab42d0926 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 8 Jul 2018 14:54:09 -0700 Subject: [PATCH 020/587] Fix eslint errors --- .../service-walkthroughs/appSync-walkthrough.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 23e2b89494..cce4877e09 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -226,7 +226,6 @@ async function askDataSourceQuestions(context, inputs) { // Ask data source related questions while (continueDataSourcesQuestion) { - const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); switch (dataSourceAnswer[inputs[13].key]) { case 'DynamoDb': { From 720b8f3d2991613a31f04b423fddbb2ac95468b7 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 8 Jul 2018 14:54:09 -0700 Subject: [PATCH 021/587] Fix eslint errors --- .../service-walkthroughs/appSync-walkthrough.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 23e2b89494..cce4877e09 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -226,7 +226,6 @@ async function askDataSourceQuestions(context, inputs) { // Ask data source related questions while (continueDataSourcesQuestion) { - const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); switch (dataSourceAnswer[inputs[13].key]) { case 'DynamoDb': { From 0e512afeb7e73bb98846a8af6ebf3124b0205eed Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 10 Jul 2018 11:49:14 -0700 Subject: [PATCH 022/587] PR comments --- packages/amplify-category-api/commands/api/remove.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index c763cd008a..0a820cb5b0 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -8,9 +8,10 @@ module.exports = { const resourceName = parameters.first; return amplify.removeResource(context, category, resourceName) + .then(() => context.print.success('Successfully removed resource')) .catch((err) => { context.print.info(err.stack); - context.print.error('There was an error removing the API resource'); + context.print.error('There was an error removing the api resource'); }); }, }; From 57d1f5402cc4847308a83c4819b7e8be11df7016 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 11 Jul 2018 20:05:07 -0700 Subject: [PATCH 023/587] Generate aws-exports.js and amplify-config.js files in javascript project src dirs after resources are pushed to the cloud --- ...appSync-cloudformation-template-custom.yml.ejs | 4 +++- ...ppSync-cloudformation-template-default.yml.ejs | 2 ++ .../amplify-provider-awscloudformation/index.js | 5 +++++ .../service-walkthroughs/appSync-walkthrough.js | 15 ++++++++++++--- .../provider-utils/supported-services.json | 2 +- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index 162608ad7c..28938a9b54 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -1,5 +1,5 @@ --- -<%if (props.dependsOn.length > 0) { %> +<%if (props.dependsOn && props.dependsOn.length > 0) { %> Parameters: <% for(var i=0; i < props.dependsOn.length; i++) { %> <% for(var j=0; j < props.dependsOn[i].attributes.length; j++) { %> @@ -165,6 +165,8 @@ Resources: <% } %> Outputs: + Region: + Value: !Ref 'AWS::Region' GraphQLApiARN: Description: The App ID of the GraphQL endpoint. Value: !Ref GraphQLApi diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs index c7450291b7..09f10cc0f1 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs @@ -523,6 +523,8 @@ Resources: mutation: Mutation } Outputs: + Region: + Value: !Ref 'AWS::Region' GraphQLApiARN: Description: The App ID of the GraphQL endpoint. Value: !Ref GraphQLApi diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index 14e44ebc15..30a47a9f16 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -41,10 +41,15 @@ function addResource(context, category, service, options) { } else { answers = result; } + if(result.output) { + options.output = result.output; + } if (answers.customCfnFile) { cfnFilename = answers.customCfnFile; } + console.log('whaaaaaaaat', options.output); + copyCfnTemplate(context, category, answers, cfnFilename); context.amplify.updateamplifyMetaAfterResourceAdd( category, diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index cce4877e09..2fd9c927ee 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,5 +1,11 @@ const inquirer = require('inquirer'); const moment = require('moment'); +const securityTypeMapping = { + 'apiKey' : 'API_KEY', + 'iam': 'AWS_IAM', + 'cognito': 'AMAZON_COGNITO_USER_POOLS', + 'openId': 'OPENID_CONNECT' +}; async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { const { amplify } = context; @@ -41,14 +47,14 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat Object.assign(allDefaultValues, resourceAnswers); if (resourceAnswers[inputs[2].key] === 'default') { - return allDefaultValues; + return {answers: allDefaultValues, output: {securityType: 'AWS_IAM'}}; } return askCustomQuestions(context, inputs) .then((result) => { Object.assign(allDefaultValues, result.answers); allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; - return { answers: allDefaultValues, dependsOn: result.dependsOn }; + return { answers: allDefaultValues, dependsOn: result.dependsOn, output: result.output }; }); } @@ -57,6 +63,9 @@ async function askCustomQuestions(context, inputs) { let dependsOn = []; const securitySetting = await askSecurityQuestions(context, inputs); + const output = { + securityType: securityTypeMapping[securitySetting.type] + }; Object.assign(answers, { securitySetting }); if (await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { @@ -66,7 +75,7 @@ async function askCustomQuestions(context, inputs) { Object.assign(answers, { dataSources }); Object.assign(answers, { dependsOn }); } - return { answers, dependsOn }; + return { answers, dependsOn, output }; } async function askSecurityQuestions(context, inputs) { diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index ebefd6bc53..8790c04845 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -68,7 +68,7 @@ "key": "cognitoUserPoolRegion", "type": "list", - "question": "Please provide a user pool ID:" + "question": "Please select a region:" }, { From 9ebffebcbf2c39c7e45b3b833432caa86783a7cb Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 11 Jul 2018 20:07:24 -0700 Subject: [PATCH 024/587] Remove debugging statements --- .../provider-utils/amplify-provider-awscloudformation/index.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index 30a47a9f16..f4a75471e8 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -48,8 +48,6 @@ function addResource(context, category, service, options) { cfnFilename = answers.customCfnFile; } - console.log('whaaaaaaaat', options.output); - copyCfnTemplate(context, category, answers, cfnFilename); context.amplify.updateamplifyMetaAfterResourceAdd( category, From 75e56b68d4b98db9305b44612572b278bfe6188f Mon Sep 17 00:00:00 2001 From: elorzafe Date: Thu, 12 Jul 2018 09:36:07 -0700 Subject: [PATCH 025/587] Adding APIGW to api plugin (#39) * Adding APIGW on Api plugin * With support for deployed functions (arn) --- .../amplify-category-api/commands/api/add.js | 1 - ...w-cloudformation-template-default.json.ejs | 407 ++++++++++++++++++ ...ync-cloudformation-template-custom.yml.ejs | 4 +- .../default-values/apigw-defaults.js | 17 + .../index.js | 3 +- .../service-walkthroughs/apigw-walkthrough.js | 292 +++++++++++++ .../provider-utils/supported-services.json | 26 ++ 7 files changed, 745 insertions(+), 5 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index c4317deafc..a227510112 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -10,7 +10,6 @@ module.exports = { name: subcommand, run: async (context) => { const { amplify } = context; - return amplify.serviceSelectionPrompt(context, category, servicesMetadata) .then((result) => { options = { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs new file mode 100644 index 0000000000..40e2d4bea9 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -0,0 +1,407 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + <% if (props.dependsOn) { %> + "Parameters": { + + <% 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) { %>,<% } %> + + <% } %> + <% } %> + }, + <% } %> + "Resources": { + <%if (!props.privacy.open) { %> + "PolicyAPIGW<%= props.apiName %>": { + "DependsOn": [ + "<%= props.apiName %>" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "PolicyAPIGW<%= props.apiName %>", + "Roles": [ + <%if (props.privacy.protected) { %> + "<%= props.privacy.unAuthRoleName %>", + <% } %> + "<%= props.privacy.authRoleName %>" + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "execute-api:Invoke" + ], + "Resource": { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/*/*" + ] + ] + } + } + ] + } + } + }, + <% } %> + "<%= props.apiName %>": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Description": "", + "Name": "<%= props.apiName %>", + "Body": { + "swagger": "2.0", + "info": { + "version": "2018-05-24T17:52:00Z", + "title": "<%= props.apiName %>" + }, + "host": { + "Fn::Join": [ + "", + [ + "apigateway.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + }, + "basePath": "/Prod", + "schemes": [ + "https" + ], + "paths": { + <% for(var i=0; i < props.paths.length; i++) { %> + "<%= props.paths[i].name %>": { + "options": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "200 response", + "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,X-Amz-User-Agent'", + "method.response.header.Access-Control-Allow-Origin": "'*'" + } + } + }, + "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" + } + } + }, + <%if (!props.privacy.open) { %> + "security": [ + { + "sigv4": [] + } + ], + <% } %> + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + <% if (props.paths[i].lambdaArn ) { %> + "<%= props.paths[i].lambdaArn %>", + <% } else { %> + { + + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" + }, + <% } %> + "/invocations" + ] + ] + }, + "passthroughBehavior": "when_no_match", + "httpMethod": "POST", + "type": "aws_proxy" + } + } + }, + "<%= props.paths[i].name %>/{proxy+}": { + "options": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "200 response", + "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,X-Amz-User-Agent'", + "method.response.header.Access-Control-Allow-Origin": "'*'" + } + } + }, + "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" + } + } + }, + <%if (!props.privacy.open) { %> + "security": [ + { + "sigv4": [] + } + ], + <% } %> + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + <% if (props.paths[i].lambdaArn) { %> + "<%= props.paths[i].lambdaArn %>", + <% } else { %> + { + + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" + }, + <% } %> + "/invocations" + ] + ] + }, + "passthroughBehavior": "when_no_match", + "httpMethod": "POST", + "type": "aws_proxy" + } + } + } + <% } %> + }, + "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" + } + } + }, + "FailOnWarnings": true + } + }, + + <%if (props.functionArns) { %> + <% for (var i=0; i < props.functionArns.length; i++) { %> + + "function<%= props.functionArns[i].lambdaFunction %>Permission<%= props.apiName %>": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": <% if (props.functionArns[i].lambdaArn) {%> "<%= props.functionArns[i].lambdaArn %>", <% } else { %> + { + "Ref": "function<%= props.functionArns[i].lambdaFunction %>Name" + }, + <% } %> + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/*/*/*" + ] + ] + } + } + }, + <% } %> + <% } %> + + + + "DeploymentAPIGW<%= props.apiName %>": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "The Development stage deployment of your API.", + "StageName": "Prod", + "RestApiId": { + "Ref": "<%= props.apiName %>" + } + } + } + }, + "Outputs": { + "RootUrl": { + "Description": "Root URL of the API gateway", + "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/Prod"]]} + } + } + } \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs index 28938a9b54..23d9590a11 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs @@ -26,8 +26,8 @@ Resources: UserPoolConfig: AwsRegion: <%= props.securitySetting.options.cognitoUserPoolRegion %> UserPoolId: <%= props.securitySetting.options.cognitoUserPoolId %> - DefaultAction: <%= props.securitySetting.options.cognitoAction %> - <%if (props.securitySetting.options.appClientRegex) { %> + DefaultAction: <%= props.securitySetting.options.cognitoAction %> + <%if (props.securitySetting.options.appClientRegex) { %> AppIdClientRegex: <%= props.securitySetting.options.appClientRegex %> <% } %> <% } %> diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js new file mode 100644 index 0000000000..991d984e42 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js @@ -0,0 +1,17 @@ +const uuid = require('uuid'); + +const getAllDefaults = (project) => { + 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; +}; + +module.exports = { + getAllDefaults, +}; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index f4a75471e8..ff7159d555 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -19,7 +19,7 @@ function copyCfnTemplate(context, category, options, cfnFilename) { { dir: pluginDir, template: `cloudformation-templates/${cfnFilename}`, - target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.yml`, + target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, }, ]; @@ -47,7 +47,6 @@ function addResource(context, category, service, options) { if (answers.customCfnFile) { cfnFilename = answers.customCfnFile; } - copyCfnTemplate(context, category, answers, cfnFilename); context.amplify.updateamplifyMetaAfterResourceAdd( category, diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js new file mode 100644 index 0000000000..b5a213cb24 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -0,0 +1,292 @@ +const inquirer = require('inquirer'); + +async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { + const { amplify } = context; + const { inputs } = serviceMetadata; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = require(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + + let answers = {}, dependsOn = {}; + + const apiNames = await askApiNames(context, allDefaultValues); + answers = { ...answers, ...apiNames }; + + const pathsAnswer = await askPaths(context); + answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; + dependsOn = pathsAnswer.dependsOn; + + const privacy = await askPrivacy(context); + answers = { ...answers, privacy, dependsOn }; + + if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && + context.amplify.getProjectDetails().amplifyMeta.providers && + context.amplify.getProjectDetails().amplifyMeta.providers['amplify-provider-awscloudformation'] + ) { + // TODO: read from utility functions (Dustin PR) + const amplifyMeta = context.amplify.getProjectDetails().amplifyMeta; + const providerInfo = amplifyMeta.providers['amplify-provider-awscloudformation']; + + answers.privacy.authRoleName = providerInfo.AuthRoleName; + answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; + } + + return { answers, dependsOn }; +} + +async function askApiNames(context, defaults) { + const { amplify } = context; + // TODO: Check if default name is already taken + const answer = await inquirer.prompt([ + { + name: "resourceName", + type: "input", + message: "Please provide a friendly name for your resource that will be used to label this category in the project:", + default: defaults["resourceName"], + validate: amplify.inputValidation({ + validation: { + "operator": "regex", + "value": "^[a-zA-Z0-9]+$", + "onErrorMsg": "Resource name should be alphanumeric" + }, + required: true, + }) + }, + { + name: "apiName", + type: "input", + message: "Please provide an API name", + default: defaults["apiName"], + validate: function (value) { + var pass = value.length > 0; + + // TODO: check names with existing apis + // let yamlDef = cloudLogicDefinition.projectDefinition.yamlDefinition; + + // // Check if API already exists + // if (yamlDef.features.cloudlogic && yamlDef.features.cloudlogic.components && + // yamlDef.features.cloudlogic.components[value]) { + // return 'API ' + value + ' already exists'; + // } + if (pass) { + return true; + } + return 'Please enter a valid API name'; + } + } + ]); + + return answer; +} + +async function askPrivacy(context) { + const { amplify } = context; + const answer = await inquirer.prompt({ + name: "privacy", + type: "list", + message: "Which kind of privacy your API should have?", + choices: [ + { + name: "Open (No security)", + value: "open" + }, + { + name: "Protected (AWS_IAM restricted to guest and sign-in users)", + value: "protected" + }, + { + name: "Private (AWS_IAM restricted to sign-in users only)", + value: "private" + } + ] + }); + + let privacy = {}; + privacy[answer.privacy] = true; + let roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' }// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + privacy['unAuthRoleName'] = roles.unAuthRoleName; + privacy['authRoleName'] = roles.authRoleName; + + return privacy; +} + +async function askPaths(context) { + const existingLambdaArns = true; // TODO: add spinner when checking if the account had functions deployed and hide the option from the menu + const existingFunctions = functionsExist(context); + + let choices = [ + { + name: "Create new function", + value: "newFunction" + } + ]; + + if (existingLambdaArns) { + choices.push({ + name: "Arn", + value: "arn" + }); + } + + if (existingFunctions) { + choices.push({ + name: "Function category", + value: "projectFunction" + }); + } + const questions = [ + { + name: "name", + type: "input", + message: "Please provide a path, e.g. /items", + default: '/items' + }, + { + name: "functionType", + type: "list", + message: "Please select lambda source", + choices + } + ]; + + let addAnotherPath; + let paths = []; + let dependsOn = []; + let functionArns = []; + + do { + const answer = await inquirer.prompt(questions); + let path = { name: answer.name }; + let lambda; + do { + lambda = await askLambdaSource(context, answer.functionType); + } while (!lambda) + path = { ...path, ...lambda }; + paths.push(path); + + if (lambda.lambdaFunction && !lambda.lambdaArn) { + dependsOn.push({ + category: 'function', + resourceName: lambda.lambdaFunction, + attributes: ['Name', 'Arn'], + }); + } + + functionArns.push(lambda); + + + addAnotherPath = (await inquirer.prompt({ + name: "anotherPath", + type: "confirm", + message: "Do you want to add another path?", + default: false + })).anotherPath; + + } while (addAnotherPath); + + return { paths, dependsOn, functionArns }; +}; + +function functionsExist(context) { + if (!context.amplify.getProjectDetails().amplifyMeta.function) { + return false; + } + + const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; + const lambdaFunctions = []; + Object.keys(functionResources).forEach((resourceName) => { + if (functionResources[resourceName].service === 'Lambda') { + lambdaFunctions.push(resourceName); + } + }); + + if (lambdaFunctions.length === 0) { + return false; + } + + return true; +} + +async function askLambdaSource(context, functionType) { + switch (functionType) { + case 'arn': return askLambdaArn(context); + case 'projectFunction': return askLambdaFromProject(context); + case 'newFunction': return newLambdaFunction(context); + default: throw new Error('Type not supported'); + } +} + +function newLambdaFunction(context) { + let add; + try { + ({ add } = require('amplify-category-function')); + } catch (e) { + throw new Error('Function plugin not installed in the CLI. Please install it to use this feature'); + } + return add(context, 'amplify-provider-awscloudformation', 'Lambda') + .then((resourceName) => { + context.print.success('Succesfully added Lambda function localy'); + return { lambdaFunction: resourceName }; + }); +} + +async function askLambdaFromProject(context) { + const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; + const lambdaFunctions = []; + Object.keys(functionResources).forEach((resourceName) => { + if (functionResources[resourceName].service === 'Lambda') { + lambdaFunctions.push(resourceName); + } + }); + + const answer = await inquirer.prompt({ + name: "lambdaFunction", + type: "list", + message: "Please select lambda function to invoke by this path", + choices: lambdaFunctions + }); + + return { lambdaFunction: answer.lambdaFunction }; +} + +async function askLambdaArn(context) { + const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + + const regionQuestion = { + type: "list", + name: "region", + message: "Select lambda function region", + choices: regions, + }; + + const regionAnswer = await inquirer.prompt([regionQuestion]); + + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer["region"] }); + + const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ + value: { + resourceName: lambdaFunction.FunctionName.replace(/[^0-9a-zA-Z]/gi, ''), + Arn: lambdaFunction.FunctionArn, + FunctionName: lambdaFunction.FunctionName, + }, + name: `${lambdaFunction.FunctionName} (${lambdaFunction.FunctionArn})`, + })); + + if (lambdaOptions.length === 0) { + context.print.error('You do not have any lambda functions configured for the selected region'); + return null; + } + + const lambdaCloudOptionQuestion = { + type: "list", + name: "lambdaChoice", + message: "Please select a Lambda function", + choices: lambdaOptions, + }; + + const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); + + return { lambdaArn: lambdaCloudOptionAnswer["lambdaChoice"].Arn, lambdaFunction: lambdaCloudOptionAnswer["lambdaChoice"].FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; +} + +module.exports = { serviceWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 8790c04845..f1f13fbe9d 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -218,5 +218,31 @@ "serviceWalkthroughFilename": "appSync-walkthrough.js", "cfnFilename": "appSync-cloudformation-template-default.yml.ejs", "provider": "amplify-provider-awscloudformation" + }, + "API Gateway": { + "inputs": [ + { + "key": "apiName", + "question": "Please provide a friendly name for your api?", + "required": true + }, + { + "key": "pathName", + "question":"HTTP path name?", + "type": "input", + "required":"true" + }, + { + + "key": "lambdaFunction", + "question": "Select lambda function", + "required": true, + "type": "input" + } + ], + "defaultValuesFilename": "apigw-defaults.js", + "serviceWalkthroughFilename": "apigw-walkthrough.js", + "cfnFilename": "apigw-cloudformation-template-default.json.ejs", + "provider": "amplify-provider-awscloudformation" } } \ No newline at end of file From e71e809152745d740fe6493638cec4b6871940d6 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 12 Jul 2018 17:59:12 -0700 Subject: [PATCH 026/587] Add help sections/commands for core and categories --- packages/amplify-category-api/commands/api.js | 20 ++- .../index.js | 2 +- .../service-walkthroughs/apigw-walkthrough.js | 161 +++++++++--------- .../appSync-walkthrough.js | 13 +- 4 files changed, 108 insertions(+), 88 deletions(-) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index 239c510df8..a333a5a1b8 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -3,6 +3,24 @@ const featureName = 'api'; module.exports = { name: featureName, run: async (context) => { - context.print.info("Here's a list of all the Amplify API commands!"); + const header = `amplify ${featureName} `; + const commands = [ + { + name: 'add', + description: `Takes you through a CLI flow to add a ${featureName} resource to your local backend`, + }, + { + name: 'push', + description: `Provisions only ${featureName} cloud resources with the latest local developments`, + }, + { + name: 'remove', + description: `Removes ${featureName} resource from your local backend which would be removed from the cloud on the next push command`, + }, + ]; + + context.amplify.showHelp(header, commands); + + context.print.info(''); }, }; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js index ff7159d555..a95fcf9980 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js @@ -41,7 +41,7 @@ function addResource(context, category, service, options) { } else { answers = result; } - if(result.output) { + if (result.output) { options.output = result.output; } if (answers.customCfnFile) { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index b5a213cb24..b92d0a0c9c 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -1,20 +1,20 @@ const inquirer = require('inquirer'); -async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { +async function serviceWalkthrough(context, defaultValuesFilename) { const { amplify } = context; - const { inputs } = serviceMetadata; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - let answers = {}, dependsOn = {}; + let answers = {}; + let dependsOn = {}; const apiNames = await askApiNames(context, allDefaultValues); answers = { ...answers, ...apiNames }; const pathsAnswer = await askPaths(context); answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; - dependsOn = pathsAnswer.dependsOn; + ({ dependsOn } = pathsAnswer); const privacy = await askPrivacy(context); answers = { ...answers, privacy, dependsOn }; @@ -24,9 +24,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat context.amplify.getProjectDetails().amplifyMeta.providers['amplify-provider-awscloudformation'] ) { // TODO: read from utility functions (Dustin PR) - const amplifyMeta = context.amplify.getProjectDetails().amplifyMeta; + const { amplifyMeta } = context.amplify.getProjectDetails(); const providerInfo = amplifyMeta.providers['amplify-provider-awscloudformation']; - + answers.privacy.authRoleName = providerInfo.AuthRoleName; answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; } @@ -39,26 +39,26 @@ async function askApiNames(context, defaults) { // TODO: Check if default name is already taken const answer = await inquirer.prompt([ { - name: "resourceName", - type: "input", - message: "Please provide a friendly name for your resource that will be used to label this category in the project:", - default: defaults["resourceName"], + name: 'resourceName', + type: 'input', + message: 'Please provide a friendly name for your resource that will be used to label this category in the project:', + default: defaults.resourceName, validate: amplify.inputValidation({ validation: { - "operator": "regex", - "value": "^[a-zA-Z0-9]+$", - "onErrorMsg": "Resource name should be alphanumeric" + operator: 'regex', + value: '^[a-zA-Z0-9]+$', + onErrorMsg: 'Resource name should be alphanumeric', }, required: true, - }) + }), }, { - name: "apiName", - type: "input", - message: "Please provide an API name", - default: defaults["apiName"], - validate: function (value) { - var pass = value.length > 0; + name: 'apiName', + type: 'input', + message: 'Please provide an API name', + default: defaults.apiName, + validate(value) { + const pass = value.length > 0; // TODO: check names with existing apis // let yamlDef = cloudLogicDefinition.projectDefinition.yamlDefinition; @@ -72,87 +72,89 @@ async function askApiNames(context, defaults) { return true; } return 'Please enter a valid API name'; - } - } + }, + }, ]); return answer; } -async function askPrivacy(context) { - const { amplify } = context; +async function askPrivacy() { const answer = await inquirer.prompt({ - name: "privacy", - type: "list", - message: "Which kind of privacy your API should have?", + name: 'privacy', + type: 'list', + message: 'Which kind of privacy your API should have?', choices: [ { - name: "Open (No security)", - value: "open" + name: 'Open (No security)', + value: 'open', }, { - name: "Protected (AWS_IAM restricted to guest and sign-in users)", - value: "protected" + name: 'Protected (AWS_IAM restricted to guest and sign-in users)', + value: 'protected', }, { - name: "Private (AWS_IAM restricted to sign-in users only)", - value: "private" - } - ] + name: 'Private (AWS_IAM restricted to sign-in users only)', + value: 'private', + }, + ], }); - let privacy = {}; + const privacy = {}; privacy[answer.privacy] = true; - let roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' }// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); - privacy['unAuthRoleName'] = roles.unAuthRoleName; - privacy['authRoleName'] = roles.authRoleName; + const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + privacy.unAuthRoleName = roles.unAuthRoleName; + privacy.authRoleName = roles.authRoleName; return privacy; } async function askPaths(context) { - const existingLambdaArns = true; // TODO: add spinner when checking if the account had functions deployed and hide the option from the menu + /* TODO: add spinner when + checking if the account had + functions deployed and hide the option from the menu */ + const existingLambdaArns = true; const existingFunctions = functionsExist(context); - let choices = [ + const choices = [ { - name: "Create new function", - value: "newFunction" - } + name: 'Create new function', + value: 'newFunction', + }, ]; if (existingLambdaArns) { choices.push({ - name: "Arn", - value: "arn" + name: 'Arn', + value: 'arn', }); } if (existingFunctions) { choices.push({ - name: "Function category", - value: "projectFunction" + name: 'Function category', + value: 'projectFunction', }); } const questions = [ { - name: "name", - type: "input", - message: "Please provide a path, e.g. /items", - default: '/items' + name: 'name', + type: 'input', + message: 'Please provide a path, e.g. /items', + default: '/items', }, { - name: "functionType", - type: "list", - message: "Please select lambda source", - choices - } + name: 'functionType', + type: 'list', + message: 'Please select lambda source', + choices, + }, ]; let addAnotherPath; - let paths = []; - let dependsOn = []; - let functionArns = []; + const paths = []; + const dependsOn = []; + const functionArns = []; do { const answer = await inquirer.prompt(questions); @@ -160,7 +162,7 @@ async function askPaths(context) { let lambda; do { lambda = await askLambdaSource(context, answer.functionType); - } while (!lambda) + } while (!lambda); path = { ...path, ...lambda }; paths.push(path); @@ -173,19 +175,18 @@ async function askPaths(context) { } functionArns.push(lambda); - + addAnotherPath = (await inquirer.prompt({ - name: "anotherPath", - type: "confirm", - message: "Do you want to add another path?", - default: false + name: 'anotherPath', + type: 'confirm', + message: 'Do you want to add another path?', + default: false, })).anotherPath; - } while (addAnotherPath); return { paths, dependsOn, functionArns }; -}; +} function functionsExist(context) { if (!context.amplify.getProjectDetails().amplifyMeta.function) { @@ -240,10 +241,10 @@ async function askLambdaFromProject(context) { }); const answer = await inquirer.prompt({ - name: "lambdaFunction", - type: "list", - message: "Please select lambda function to invoke by this path", - choices: lambdaFunctions + name: 'lambdaFunction', + type: 'list', + message: 'Please select lambda function to invoke by this path', + choices: lambdaFunctions, }); return { lambdaFunction: answer.lambdaFunction }; @@ -253,15 +254,15 @@ async function askLambdaArn(context) { const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); const regionQuestion = { - type: "list", - name: "region", - message: "Select lambda function region", + type: 'list', + name: 'region', + message: 'Select lambda function region', choices: regions, }; const regionAnswer = await inquirer.prompt([regionQuestion]); - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer["region"] }); + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ value: { @@ -278,15 +279,15 @@ async function askLambdaArn(context) { } const lambdaCloudOptionQuestion = { - type: "list", - name: "lambdaChoice", - message: "Please select a Lambda function", + type: 'list', + name: 'lambdaChoice', + message: 'Please select a Lambda function', choices: lambdaOptions, }; const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); - return { lambdaArn: lambdaCloudOptionAnswer["lambdaChoice"].Arn, lambdaFunction: lambdaCloudOptionAnswer["lambdaChoice"].FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; + return { lambdaArn: lambdaCloudOptionAnswer.lambdaChoice.Arn, lambdaFunction: lambdaCloudOptionAnswer.lambdaChoice.FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; } module.exports = { serviceWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 2fd9c927ee..6f3e88f586 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,10 +1,11 @@ const inquirer = require('inquirer'); const moment = require('moment'); + const securityTypeMapping = { - 'apiKey' : 'API_KEY', - 'iam': 'AWS_IAM', - 'cognito': 'AMAZON_COGNITO_USER_POOLS', - 'openId': 'OPENID_CONNECT' + apiKey: 'API_KEY', + iam: 'AWS_IAM', + cognito: 'AMAZON_COGNITO_USER_POOLS', + openId: 'OPENID_CONNECT', }; async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { @@ -47,7 +48,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat Object.assign(allDefaultValues, resourceAnswers); if (resourceAnswers[inputs[2].key] === 'default') { - return {answers: allDefaultValues, output: {securityType: 'AWS_IAM'}}; + return { answers: allDefaultValues, output: { securityType: 'AWS_IAM' } }; } return askCustomQuestions(context, inputs) @@ -64,7 +65,7 @@ async function askCustomQuestions(context, inputs) { const securitySetting = await askSecurityQuestions(context, inputs); const output = { - securityType: securityTypeMapping[securitySetting.type] + securityType: securityTypeMapping[securitySetting.type], }; Object.assign(answers, { securitySetting }); From f921c0c4d79278202b6dd0632cd069fbd73f8285 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 12 Jul 2018 21:26:36 -0700 Subject: [PATCH 027/587] Modify some wordings based on PR comments --- packages/amplify-category-api/commands/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index a333a5a1b8..d662679751 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -11,7 +11,7 @@ module.exports = { }, { name: 'push', - description: `Provisions only ${featureName} cloud resources with the latest local developments`, + description: `Provisions ${featureName} cloud resources and it's dependencies with the latest local developments`, }, { name: 'remove', From 825d0cff245830f536a0d93932787e85188cba5b Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 12 Jul 2018 21:58:23 -0700 Subject: [PATCH 028/587] Some minor language/wording changes in th categories --- .../service-walkthroughs/apigw-walkthrough.js | 8 ++++---- .../service-walkthroughs/appSync-walkthrough.js | 4 ++-- .../provider-utils/supported-services.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index b92d0a0c9c..720358cf5c 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -118,21 +118,21 @@ async function askPaths(context) { const choices = [ { - name: 'Create new function', + name: 'Create a new Lambda function', value: 'newFunction', }, ]; if (existingLambdaArns) { choices.push({ - name: 'Arn', + name: 'Use a Lambda function already deployed on AWS', value: 'arn', }); } if (existingFunctions) { choices.push({ - name: 'Function category', + name: 'Use a Lambda function already added in the current Amplify project', value: 'projectFunction', }); } @@ -226,7 +226,7 @@ function newLambdaFunction(context) { } return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { - context.print.success('Succesfully added Lambda function localy'); + context.print.success('Succesfully added Lambda function locally'); return { lambdaFunction: resourceName }; }); } diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index 6f3e88f586..b5622b0579 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -325,7 +325,7 @@ async function askDynamoDBQuestions(context, inputs) { } return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') .then((resourceName) => { - context.print.success('Succesfully added DynamoDb table localy'); + context.print.success('Succesfully added DynamoDb table locally'); return { resourceName }; }); } @@ -416,7 +416,7 @@ async function askLambdaQuestions(context, inputs) { } return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { - context.print.success('Succesfully added Lambda table localy'); + context.print.success('Succesfully added Lambda table locally'); return { resourceName }; }); } diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index f1f13fbe9d..643f3865d5 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -180,7 +180,7 @@ "type": "list", "question": "Choose a Lambda data source option", "options": [{ - "name": "Use a Lambda function configured in the current Amplify project", + "name": "Use a Lambda function already added in the current Amplify project", "value": "currentProject" }, { From 2960f57ca0a977f8ca7df7fa46f2cf8726a36c9e Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 13 Jul 2018 11:57:48 -0700 Subject: [PATCH 029/587] Minor change after PR comments --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js index b5622b0579..0d7149f1a8 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -416,7 +416,7 @@ async function askLambdaQuestions(context, inputs) { } return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { - context.print.success('Succesfully added Lambda table locally'); + context.print.success('Succesfully added Lambda function locally'); return { resourceName }; }); } From 539d96e61534abafa58b8539d7b2e9a1d7f0ec7d Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 13 Jul 2018 11:56:14 -0700 Subject: [PATCH 030/587] Fix lerna bootstrapping issue and some code cleanup --- packages/amplify-category-api/.gitignore | 2 +- .../amplify-category-api/package-lock.json | 6430 ----------------- packages/amplify-category-api/package.json | 4 +- 3 files changed, 3 insertions(+), 6433 deletions(-) delete mode 100644 packages/amplify-category-api/package-lock.json diff --git a/packages/amplify-category-api/.gitignore b/packages/amplify-category-api/.gitignore index 81fae83675..5b7ebfc0d5 100644 --- a/packages/amplify-category-api/.gitignore +++ b/packages/amplify-category-api/.gitignore @@ -4,4 +4,4 @@ npm-debug.log coverage .nyc_output yarn.lock -package.lock +package-lock.json diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json deleted file mode 100644 index 47beaf4087..0000000000 --- a/packages/amplify-category-api/package-lock.json +++ /dev/null @@ -1,6430 +0,0 @@ -{ - "requires": true, - "lockfileVersion": 1, - "dependencies": { - "amplify-category-function": { - "version": "file:../amplify-category-function", - "requires": { - "eslint": "4.19.1", - "grunt": "1.0.3", - "grunt-aws-lambda": "0.13.0", - "inquirer": "3.3.0", - "uuid": "3.3.2" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true - }, - "acorn": { - "version": "5.7.1", - "bundled": true - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "agent-base": { - "version": "4.2.1", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "ansi-escapes": { - "version": "3.1.0", - "bundled": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "archiver": { - "version": "0.14.4", - "bundled": true, - "requires": { - "async": "0.9.2", - "buffer-crc32": "0.2.13", - "glob": "4.3.5", - "lazystream": "0.1.0", - "lodash": "3.2.0", - "readable-stream": "1.0.34", - "tar-stream": "1.1.5", - "zip-stream": "0.5.2" - }, - "dependencies": { - "async": { - "version": "0.9.2", - "bundled": true - }, - "glob": { - "version": "4.3.5", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" - } - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "lodash": { - "version": "3.2.0", - "bundled": true - }, - "minimatch": { - "version": "2.0.10", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "argparse": { - "version": "1.0.10", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-find-index": { - "version": "1.0.2", - "bundled": true - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "ast-types": { - "version": "0.11.5", - "bundled": true - }, - "async": { - "version": "1.5.2", - "bundled": true - }, - "aws-sdk": { - "version": "2.2.48", - "bundled": true, - "requires": { - "sax": "1.1.5", - "xml2js": "0.4.15", - "xmlbuilder": "2.6.2" - } - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - } - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "bl": { - "version": "0.9.5", - "bundled": true, - "requires": { - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "bundled": true - }, - "buffer-from": { - "version": "1.1.0", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "bytes": { - "version": "3.0.0", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "camelcase": { - "version": "2.1.1", - "bundled": true - }, - "camelcase-keys": { - "version": "2.1.0", - "bundled": true, - "requires": { - "camelcase": "2.1.1", - "map-obj": "1.0.1" - } - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "1.9.2" - } - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "3.0.0" - } - } - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "coffeescript": { - "version": "1.10.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.2", - "bundled": true, - "requires": { - "color-name": "1.1.1" - } - }, - "color-name": { - "version": "1.1.1", - "bundled": true - }, - "colors": { - "version": "1.1.2", - "bundled": true - }, - "compress-commons": { - "version": "0.2.9", - "bundled": true, - "requires": { - "buffer-crc32": "0.2.13", - "crc32-stream": "0.3.4", - "node-int64": "0.3.3", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "crc32-stream": { - "version": "0.3.4", - "bundled": true, - "requires": { - "buffer-crc32": "0.2.13", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "currently-unhandled": { - "version": "0.4.1", - "bundled": true, - "requires": { - "array-find-index": "1.0.2" - } - }, - "data-uri-to-buffer": { - "version": "1.2.0", - "bundled": true - }, - "dateformat": { - "version": "1.0.12", - "bundled": true, - "requires": { - "get-stdin": "4.0.1", - "meow": "3.7.0" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "bundled": true - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "degenerator": { - "version": "1.0.4", - "bundled": true, - "requires": { - "ast-types": "0.11.5", - "escodegen": "1.10.0", - "esprima": "3.1.3" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "bundled": true - } - } - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "depd": { - "version": "1.1.2", - "bundled": true - }, - "doctrine": { - "version": "2.1.0", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "end-of-stream": { - "version": "1.4.1", - "bundled": true, - "requires": { - "once": "1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "es6-promise": { - "version": "4.2.4", - "bundled": true - }, - "es6-promisify": { - "version": "5.0.0", - "bundled": true, - "requires": { - "es6-promise": "4.2.4" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "escodegen": { - "version": "1.10.0", - "bundled": true, - "requires": { - "esprima": "3.1.3", - "estraverse": "4.2.0", - "esutils": "2.0.2", - "optionator": "0.8.2", - "source-map": "0.6.1" - }, - "dependencies": { - "esprima": { - "version": "3.1.3", - "bundled": true - } - } - }, - "eslint": { - "version": "4.19.1", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "bundled": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "bundled": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "resolve": { - "version": "1.8.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "bundled": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.13.0", - "bundled": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - }, - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - } - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - } - }, - "resolve": { - "version": "1.8.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "bundled": true - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.4", - "bundled": true, - "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "eventemitter2": { - "version": "0.4.14", - "bundled": true - }, - "exit": { - "version": "0.1.2", - "bundled": true - }, - "extend": { - "version": "3.0.1", - "bundled": true - }, - "external-editor": { - "version": "2.2.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "bundled": true - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "findup-sync": { - "version": "0.3.0", - "bundled": true, - "requires": { - "glob": "5.0.15" - }, - "dependencies": { - "glob": { - "version": "5.0.15", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - } - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "ftp": { - "version": "0.3.10", - "bundled": true, - "requires": { - "readable-stream": "1.1.14", - "xregexp": "2.0.0" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.1.14", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "get-stdin": { - "version": "4.0.1", - "bundled": true - }, - "get-uri": { - "version": "2.0.2", - "bundled": true, - "requires": { - "data-uri-to-buffer": "1.2.0", - "debug": "2.6.9", - "extend": "3.0.1", - "file-uri-to-path": "1.0.0", - "ftp": "0.3.10", - "readable-stream": "2.3.6" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "getobject": { - "version": "0.1.0", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.7.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "grunt": { - "version": "1.0.3", - "bundled": true, - "requires": { - "coffeescript": "1.10.0", - "dateformat": "1.0.12", - "eventemitter2": "0.4.14", - "exit": "0.1.2", - "findup-sync": "0.3.0", - "glob": "7.0.6", - "grunt-cli": "1.2.0", - "grunt-known-options": "1.1.0", - "grunt-legacy-log": "2.0.0", - "grunt-legacy-util": "1.1.1", - "iconv-lite": "0.4.23", - "js-yaml": "3.5.5", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "path-is-absolute": "1.0.1", - "rimraf": "2.6.2" - }, - "dependencies": { - "esprima": { - "version": "2.7.3", - "bundled": true - }, - "glob": { - "version": "7.0.6", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "grunt-cli": { - "version": "1.2.0", - "bundled": true, - "requires": { - "findup-sync": "0.3.0", - "grunt-known-options": "1.1.0", - "nopt": "3.0.6", - "resolve": "1.1.7" - } - }, - "js-yaml": { - "version": "3.5.5", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "2.7.3" - } - } - } - }, - "grunt-aws-lambda": { - "version": "0.13.0", - "bundled": true, - "requires": { - "archiver": "0.14.4", - "aws-sdk": "2.2.48", - "glob": "4.3.5", - "mkdirp": "0.5.1", - "npm": "2.15.12", - "proxy-agent": "3.0.0", - "q": "1.5.1", - "rimraf": "2.2.8", - "temporary": "0.0.8" - }, - "dependencies": { - "glob": { - "version": "4.3.5", - "bundled": true, - "requires": { - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "2.0.10", - "once": "1.4.0" - } - }, - "minimatch": { - "version": "2.0.10", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "proxy-agent": { - "version": "3.0.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "lru-cache": "4.1.3", - "pac-proxy-agent": "2.0.2", - "proxy-from-env": "1.0.0", - "socks-proxy-agent": "3.0.1" - }, - "dependencies": { - "agent-base": { - "version": "4.2.1", - "bundled": true, - "requires": { - "es6-promisify": "5.0.0" - } - }, - "http-proxy-agent": { - "version": "2.1.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "https-proxy-agent": { - "version": "2.2.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "pac-proxy-agent": { - "version": "2.0.2", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "get-uri": "2.0.2", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "pac-resolver": "3.0.0", - "raw-body": "2.3.3", - "socks-proxy-agent": "3.0.1" - } - }, - "proxy-from-env": { - "version": "1.0.0", - "bundled": true - }, - "socks-proxy-agent": { - "version": "3.0.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "socks": "1.1.10" - } - } - } - }, - "rimraf": { - "version": "2.2.8", - "bundled": true - } - } - }, - "grunt-known-options": { - "version": "1.1.0", - "bundled": true - }, - "grunt-legacy-log": { - "version": "2.0.0", - "bundled": true, - "requires": { - "colors": "1.1.2", - "grunt-legacy-log-utils": "2.0.1", - "hooker": "0.2.3", - "lodash": "4.17.10" - } - }, - "grunt-legacy-log-utils": { - "version": "2.0.1", - "bundled": true, - "requires": { - "chalk": "2.4.1", - "lodash": "4.17.10" - } - }, - "grunt-legacy-util": { - "version": "1.1.1", - "bundled": true, - "requires": { - "async": "1.5.2", - "exit": "0.1.2", - "getobject": "0.1.0", - "hooker": "0.2.3", - "lodash": "4.17.10", - "underscore.string": "3.3.4", - "which": "1.3.1" - } - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "hooker": { - "version": "0.2.3", - "bundled": true - }, - "hosted-git-info": { - "version": "2.6.1", - "bundled": true - }, - "http-errors": { - "version": "1.6.3", - "bundled": true, - "requires": { - "depd": "1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": "1.5.0" - } - }, - "http-proxy-agent": { - "version": "2.1.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "https-proxy-agent": { - "version": "2.2.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0" - } - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.10", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "indent-string": { - "version": "2.1.0", - "bundled": true, - "requires": { - "repeating": "2.0.1" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "ip": { - "version": "1.1.5", - "bundled": true - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-finite": { - "version": "1.0.2", - "bundled": true, - "requires": { - "number-is-nan": "1.0.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.1.0", - "bundled": true - }, - "is-utf8": { - "version": "0.2.1", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.12.0", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "lazystream": { - "version": "0.1.0", - "bundled": true, - "requires": { - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "1.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "strip-bom": "2.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true - }, - "loud-rejection": { - "version": "1.6.0", - "bundled": true, - "requires": { - "currently-unhandled": "0.4.1", - "signal-exit": "3.0.2" - } - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "map-obj": { - "version": "1.0.1", - "bundled": true - }, - "meow": { - "version": "3.7.0", - "bundled": true, - "requires": { - "camelcase-keys": "2.1.0", - "decamelize": "1.2.0", - "loud-rejection": "1.6.0", - "map-obj": "1.0.1", - "minimist": "1.2.0", - "normalize-package-data": "2.4.0", - "object-assign": "4.1.1", - "read-pkg-up": "1.0.1", - "redent": "1.0.0", - "trim-newlines": "1.0.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true - } - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "netmask": { - "version": "1.0.6", - "bundled": true - }, - "node-int64": { - "version": "0.3.3", - "bundled": true - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1.1.1" - } - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.6.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "npm": { - "version": "2.15.12", - "bundled": true, - "requires": { - "abbrev": "1.0.9", - "ansi": "0.3.1", - "ansi-regex": "2.0.0", - "ansicolors": "0.3.2", - "ansistyles": "0.1.3", - "archy": "1.0.0", - "async-some": "1.0.2", - "block-stream": "0.0.9", - "char-spinner": "1.0.1", - "chmodr": "1.0.2", - "chownr": "1.0.1", - "cmd-shim": "2.0.2", - "columnify": "1.5.4", - "config-chain": "1.1.10", - "dezalgo": "1.0.3", - "editor": "1.0.0", - "fs-vacuum": "1.2.9", - "fs-write-stream-atomic": "1.0.8", - "fstream": "1.0.10", - "fstream-npm": "1.1.1", - "github-url-from-git": "1.4.0", - "github-url-from-username-repo": "1.0.2", - "glob": "7.0.6", - "graceful-fs": "4.1.6", - "hosted-git-info": "2.1.5", - "imurmurhash": "0.1.4", - "inflight": "1.0.5", - "inherits": "2.0.3", - "ini": "1.3.4", - "init-package-json": "1.9.4", - "lockfile": "1.0.1", - "lru-cache": "4.0.1", - "minimatch": "3.0.3", - "mkdirp": "0.5.1", - "node-gyp": "3.6.0", - "nopt": "3.0.6", - "normalize-git-url": "3.0.2", - "normalize-package-data": "2.3.5", - "npm-cache-filename": "1.0.2", - "npm-install-checks": "1.0.7", - "npm-package-arg": "4.1.0", - "npm-registry-client": "7.2.1", - "npm-user-validate": "0.1.5", - "npmlog": "2.0.4", - "once": "1.4.0", - "opener": "1.4.1", - "osenv": "0.1.3", - "path-is-inside": "1.0.1", - "read": "1.0.7", - "read-installed": "4.0.3", - "read-package-json": "2.0.4", - "readable-stream": "2.1.5", - "realize-package-specifier": "3.0.1", - "request": "2.74.0", - "retry": "0.10.0", - "rimraf": "2.5.4", - "semver": "5.1.0", - "sha": "2.0.1", - "slide": "1.1.6", - "sorted-object": "2.0.0", - "spdx-license-ids": "1.2.2", - "strip-ansi": "3.0.1", - "tar": "2.2.1", - "text-table": "0.2.0", - "uid-number": "0.0.6", - "umask": "1.1.0", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "2.2.2", - "which": "1.2.11", - "wrappy": "1.0.2", - "write-file-atomic": "1.1.4" - }, - "dependencies": { - "abbrev": { - "version": "1.0.9", - "bundled": true - }, - "ansi": { - "version": "0.3.1", - "bundled": true - }, - "ansi-regex": { - "version": "2.0.0", - "bundled": true - }, - "ansicolors": { - "version": "0.3.2", - "bundled": true - }, - "ansistyles": { - "version": "0.1.3", - "bundled": true - }, - "archy": { - "version": "1.0.0", - "bundled": true - }, - "async-some": { - "version": "1.0.2", - "bundled": true, - "requires": { - "dezalgo": "1.0.3" - } - }, - "block-stream": { - "version": "0.0.9", - "bundled": true, - "requires": { - "inherits": "2.0.3" - } - }, - "char-spinner": { - "version": "1.0.1", - "bundled": true - }, - "chmodr": { - "version": "1.0.2", - "bundled": true - }, - "chownr": { - "version": "1.0.1", - "bundled": true - }, - "cmd-shim": { - "version": "2.0.2", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "mkdirp": "0.5.1" - } - }, - "columnify": { - "version": "1.5.4", - "bundled": true, - "requires": { - "strip-ansi": "3.0.1", - "wcwidth": "1.0.0" - }, - "dependencies": { - "wcwidth": { - "version": "1.0.0", - "bundled": true, - "requires": { - "defaults": "1.0.3" - }, - "dependencies": { - "defaults": { - "version": "1.0.3", - "bundled": true, - "requires": { - "clone": "1.0.2" - }, - "dependencies": { - "clone": { - "version": "1.0.2", - "bundled": true - } - } - } - } - } - } - }, - "config-chain": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ini": "1.3.4", - "proto-list": "1.2.4" - }, - "dependencies": { - "proto-list": { - "version": "1.2.4", - "bundled": true - } - } - }, - "dezalgo": { - "version": "1.0.3", - "bundled": true, - "requires": { - "asap": "2.0.3", - "wrappy": "1.0.2" - }, - "dependencies": { - "asap": { - "version": "2.0.3", - "bundled": true - } - } - }, - "editor": { - "version": "1.0.0", - "bundled": true - }, - "fs-vacuum": { - "version": "1.2.9", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "path-is-inside": "1.0.1", - "rimraf": "2.5.4" - } - }, - "fs-write-stream-atomic": { - "version": "1.0.8", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "iferr": "0.1.5", - "imurmurhash": "0.1.4", - "readable-stream": "2.1.5" - }, - "dependencies": { - "iferr": { - "version": "0.1.5", - "bundled": true - } - } - }, - "fstream": { - "version": "1.0.10", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "inherits": "2.0.3", - "mkdirp": "0.5.1", - "rimraf": "2.5.4" - } - }, - "fstream-npm": { - "version": "1.1.1", - "bundled": true, - "requires": { - "fstream-ignore": "1.0.5", - "inherits": "2.0.3" - }, - "dependencies": { - "fstream-ignore": { - "version": "1.0.5", - "bundled": true, - "requires": { - "fstream": "1.0.10", - "inherits": "2.0.3", - "minimatch": "3.0.3" - } - } - } - }, - "github-url-from-git": { - "version": "1.4.0", - "bundled": true - }, - "github-url-from-username-repo": { - "version": "1.0.2", - "bundled": true - }, - "glob": { - "version": "7.0.6", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "graceful-fs": { - "version": "4.1.6", - "bundled": true - }, - "hosted-git-info": { - "version": "2.1.5", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.5", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "ini": { - "version": "1.3.4", - "bundled": true - }, - "init-package-json": { - "version": "1.9.4", - "bundled": true, - "requires": { - "glob": "6.0.4", - "npm-package-arg": "4.1.0", - "promzard": "0.3.0", - "read": "1.0.7", - "read-package-json": "2.0.4", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1", - "validate-npm-package-name": "2.2.2" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "bundled": true, - "requires": { - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "promzard": { - "version": "0.3.0", - "bundled": true, - "requires": { - "read": "1.0.7" - } - } - } - }, - "lockfile": { - "version": "1.0.1", - "bundled": true - }, - "lru-cache": { - "version": "4.0.1", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.0.0" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "2.0.0", - "bundled": true - } - } - }, - "minimatch": { - "version": "3.0.3", - "bundled": true, - "requires": { - "brace-expansion": "1.1.6" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.6", - "bundled": true, - "requires": { - "balanced-match": "0.4.2", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "0.4.2", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "bundled": true - } - } - }, - "node-gyp": { - "version": "3.6.0", - "bundled": true, - "requires": { - "fstream": "1.0.10", - "glob": "7.0.6", - "graceful-fs": "4.1.6", - "minimatch": "3.0.3", - "mkdirp": "0.5.1", - "nopt": "3.0.6", - "npmlog": "2.0.4", - "osenv": "0.1.3", - "request": "2.74.0", - "rimraf": "2.5.4", - "semver": "5.3.0", - "tar": "2.2.1", - "which": "1.2.11" - }, - "dependencies": { - "semver": { - "version": "5.3.0", - "bundled": true - } - } - }, - "nopt": { - "version": "3.0.6", - "bundled": true, - "requires": { - "abbrev": "1.0.9" - } - }, - "normalize-git-url": { - "version": "3.0.2", - "bundled": true - }, - "normalize-package-data": { - "version": "2.3.5", - "bundled": true, - "requires": { - "hosted-git-info": "2.1.5", - "is-builtin-module": "1.0.0", - "semver": "5.1.0", - "validate-npm-package-license": "3.0.1" - }, - "dependencies": { - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.0" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.0", - "bundled": true - } - } - } - } - }, - "npm-cache-filename": { - "version": "1.0.2", - "bundled": true - }, - "npm-install-checks": { - "version": "1.0.7", - "bundled": true, - "requires": { - "npmlog": "2.0.4", - "semver": "5.1.0" - } - }, - "npm-package-arg": { - "version": "4.1.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.1.5", - "semver": "5.1.0" - } - }, - "npm-registry-client": { - "version": "7.2.1", - "bundled": true, - "requires": { - "concat-stream": "1.5.2", - "graceful-fs": "4.1.6", - "normalize-package-data": "2.3.5", - "npm-package-arg": "4.1.0", - "npmlog": "2.0.4", - "once": "1.4.0", - "request": "2.74.0", - "retry": "0.10.0", - "semver": "5.1.0", - "slide": "1.1.6" - }, - "dependencies": { - "concat-stream": { - "version": "1.5.2", - "bundled": true, - "requires": { - "inherits": "2.0.3", - "readable-stream": "2.0.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - } - } - }, - "retry": { - "version": "0.10.0", - "bundled": true - } - } - }, - "npm-user-validate": { - "version": "0.1.5", - "bundled": true - }, - "npmlog": { - "version": "2.0.4", - "bundled": true, - "requires": { - "ansi": "0.3.1", - "are-we-there-yet": "1.1.2", - "gauge": "1.2.7" - }, - "dependencies": { - "are-we-there-yet": { - "version": "1.1.2", - "bundled": true, - "requires": { - "delegates": "1.0.0", - "readable-stream": "2.1.5" - }, - "dependencies": { - "delegates": { - "version": "1.0.0", - "bundled": true - } - } - }, - "gauge": { - "version": "1.2.7", - "bundled": true, - "requires": { - "ansi": "0.3.1", - "has-unicode": "2.0.0", - "lodash.pad": "4.4.0", - "lodash.padend": "4.5.0", - "lodash.padstart": "4.5.0" - }, - "dependencies": { - "has-unicode": { - "version": "2.0.0", - "bundled": true - }, - "lodash._baseslice": { - "version": "4.0.0", - "bundled": true - }, - "lodash._basetostring": { - "version": "4.12.0", - "bundled": true - }, - "lodash.pad": { - "version": "4.4.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.padend": { - "version": "4.5.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.padstart": { - "version": "4.5.0", - "bundled": true, - "requires": { - "lodash._baseslice": "4.0.0", - "lodash._basetostring": "4.12.0", - "lodash.tostring": "4.1.4" - } - }, - "lodash.tostring": { - "version": "4.1.4", - "bundled": true - } - } - } - } - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "opener": { - "version": "1.4.1", - "bundled": true - }, - "osenv": { - "version": "0.1.3", - "bundled": true, - "requires": { - "os-homedir": "1.0.0", - "os-tmpdir": "1.0.1" - }, - "dependencies": { - "os-homedir": { - "version": "1.0.0", - "bundled": true - }, - "os-tmpdir": { - "version": "1.0.1", - "bundled": true - } - } - }, - "path-is-inside": { - "version": "1.0.1", - "bundled": true - }, - "read": { - "version": "1.0.7", - "bundled": true, - "requires": { - "mute-stream": "0.0.5" - }, - "dependencies": { - "mute-stream": { - "version": "0.0.5", - "bundled": true - } - } - }, - "read-installed": { - "version": "4.0.3", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "graceful-fs": "4.1.6", - "read-package-json": "2.0.4", - "readdir-scoped-modules": "1.0.2", - "semver": "5.1.0", - "slide": "1.1.6", - "util-extend": "1.0.1" - }, - "dependencies": { - "debuglog": { - "version": "1.0.1", - "bundled": true - }, - "readdir-scoped-modules": { - "version": "1.0.2", - "bundled": true, - "requires": { - "debuglog": "1.0.1", - "dezalgo": "1.0.3", - "graceful-fs": "4.1.6", - "once": "1.4.0" - } - }, - "util-extend": { - "version": "1.0.1", - "bundled": true - } - } - }, - "read-package-json": { - "version": "2.0.4", - "bundled": true, - "requires": { - "glob": "6.0.4", - "graceful-fs": "4.1.6", - "json-parse-helpfulerror": "1.0.3", - "normalize-package-data": "2.3.5" - }, - "dependencies": { - "glob": { - "version": "6.0.4", - "bundled": true, - "requires": { - "inflight": "1.0.5", - "inherits": "2.0.3", - "minimatch": "3.0.3", - "once": "1.4.0", - "path-is-absolute": "1.0.0" - }, - "dependencies": { - "path-is-absolute": { - "version": "1.0.0", - "bundled": true - } - } - }, - "json-parse-helpfulerror": { - "version": "1.0.3", - "bundled": true, - "requires": { - "jju": "1.3.0" - }, - "dependencies": { - "jju": { - "version": "1.3.0", - "bundled": true - } - } - } - } - }, - "readable-stream": { - "version": "2.1.5", - "bundled": true, - "requires": { - "buffer-shims": "1.0.0", - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "buffer-shims": { - "version": "1.0.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - }, - "realize-package-specifier": { - "version": "3.0.1", - "bundled": true, - "requires": { - "dezalgo": "1.0.3", - "npm-package-arg": "4.1.0" - } - }, - "request": { - "version": "2.74.0", - "bundled": true, - "requires": { - "aws-sign2": "0.6.0", - "aws4": "1.4.1", - "bl": "1.1.2", - "caseless": "0.11.0", - "combined-stream": "1.0.5", - "extend": "3.0.0", - "forever-agent": "0.6.1", - "form-data": "1.0.0-rc4", - "har-validator": "2.0.6", - "hawk": "3.1.3", - "http-signature": "1.1.1", - "is-typedarray": "1.0.0", - "isstream": "0.1.2", - "json-stringify-safe": "5.0.1", - "mime-types": "2.1.11", - "node-uuid": "1.4.7", - "oauth-sign": "0.8.2", - "qs": "6.2.1", - "stringstream": "0.0.5", - "tough-cookie": "2.3.1", - "tunnel-agent": "0.4.3" - }, - "dependencies": { - "aws-sign2": { - "version": "0.6.0", - "bundled": true - }, - "aws4": { - "version": "1.4.1", - "bundled": true - }, - "bl": { - "version": "1.1.2", - "bundled": true, - "requires": { - "readable-stream": "2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "1.0.7", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.7", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - } - } - } - } - }, - "caseless": { - "version": "0.11.0", - "bundled": true - }, - "combined-stream": { - "version": "1.0.5", - "bundled": true, - "requires": { - "delayed-stream": "1.0.0" - }, - "dependencies": { - "delayed-stream": { - "version": "1.0.0", - "bundled": true - } - } - }, - "extend": { - "version": "3.0.0", - "bundled": true - }, - "forever-agent": { - "version": "0.6.1", - "bundled": true - }, - "form-data": { - "version": "1.0.0-rc4", - "bundled": true, - "requires": { - "async": "1.5.2", - "combined-stream": "1.0.5", - "mime-types": "2.1.11" - }, - "dependencies": { - "async": { - "version": "1.5.2", - "bundled": true - } - } - }, - "har-validator": { - "version": "2.0.6", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "commander": "2.9.0", - "is-my-json-valid": "2.13.1", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "commander": { - "version": "2.9.0", - "bundled": true, - "requires": { - "graceful-readlink": "1.0.1" - }, - "dependencies": { - "graceful-readlink": { - "version": "1.0.1", - "bundled": true - } - } - }, - "is-my-json-valid": { - "version": "2.13.1", - "bundled": true, - "requires": { - "generate-function": "2.0.0", - "generate-object-property": "1.2.0", - "jsonpointer": "2.0.0", - "xtend": "4.0.1" - }, - "dependencies": { - "generate-function": { - "version": "2.0.0", - "bundled": true - }, - "generate-object-property": { - "version": "1.2.0", - "bundled": true, - "requires": { - "is-property": "1.0.2" - }, - "dependencies": { - "is-property": { - "version": "1.0.2", - "bundled": true - } - } - }, - "jsonpointer": { - "version": "2.0.0", - "bundled": true - }, - "xtend": { - "version": "4.0.1", - "bundled": true - } - } - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "bundled": true - } - } - } - } - }, - "hawk": { - "version": "3.1.3", - "bundled": true, - "requires": { - "boom": "2.10.1", - "cryptiles": "2.0.5", - "hoek": "2.16.3", - "sntp": "1.0.9" - }, - "dependencies": { - "boom": { - "version": "2.10.1", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - }, - "cryptiles": { - "version": "2.0.5", - "bundled": true, - "requires": { - "boom": "2.10.1" - } - }, - "hoek": { - "version": "2.16.3", - "bundled": true - }, - "sntp": { - "version": "1.0.9", - "bundled": true, - "requires": { - "hoek": "2.16.3" - } - } - } - }, - "http-signature": { - "version": "1.1.1", - "bundled": true, - "requires": { - "assert-plus": "0.2.0", - "jsprim": "1.3.0", - "sshpk": "1.9.2" - }, - "dependencies": { - "assert-plus": { - "version": "0.2.0", - "bundled": true - }, - "jsprim": { - "version": "1.3.0", - "bundled": true, - "requires": { - "extsprintf": "1.0.2", - "json-schema": "0.2.2", - "verror": "1.3.6" - }, - "dependencies": { - "extsprintf": { - "version": "1.0.2", - "bundled": true - }, - "json-schema": { - "version": "0.2.2", - "bundled": true - }, - "verror": { - "version": "1.3.6", - "bundled": true, - "requires": { - "extsprintf": "1.0.2" - } - } - } - }, - "sshpk": { - "version": "1.9.2", - "bundled": true, - "requires": { - "asn1": "0.2.3", - "assert-plus": "1.0.0", - "dashdash": "1.14.0", - "ecc-jsbn": "0.1.1", - "getpass": "0.1.6", - "jodid25519": "1.0.2", - "jsbn": "0.1.0", - "tweetnacl": "0.13.3" - }, - "dependencies": { - "asn1": { - "version": "0.2.3", - "bundled": true - }, - "assert-plus": { - "version": "1.0.0", - "bundled": true - }, - "dashdash": { - "version": "1.14.0", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "ecc-jsbn": { - "version": "0.1.1", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.0" - } - }, - "getpass": { - "version": "0.1.6", - "bundled": true, - "requires": { - "assert-plus": "1.0.0" - } - }, - "jodid25519": { - "version": "1.0.2", - "bundled": true, - "optional": true, - "requires": { - "jsbn": "0.1.0" - } - }, - "jsbn": { - "version": "0.1.0", - "bundled": true, - "optional": true - }, - "tweetnacl": { - "version": "0.13.3", - "bundled": true, - "optional": true - } - } - } - } - }, - "is-typedarray": { - "version": "1.0.0", - "bundled": true - }, - "isstream": { - "version": "0.1.2", - "bundled": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "bundled": true - }, - "mime-types": { - "version": "2.1.11", - "bundled": true, - "requires": { - "mime-db": "1.23.0" - }, - "dependencies": { - "mime-db": { - "version": "1.23.0", - "bundled": true - } - } - }, - "node-uuid": { - "version": "1.4.7", - "bundled": true - }, - "oauth-sign": { - "version": "0.8.2", - "bundled": true - }, - "qs": { - "version": "6.2.1", - "bundled": true - }, - "stringstream": { - "version": "0.0.5", - "bundled": true - }, - "tough-cookie": { - "version": "2.3.1", - "bundled": true - }, - "tunnel-agent": { - "version": "0.4.3", - "bundled": true - } - } - }, - "retry": { - "version": "0.10.0", - "bundled": true - }, - "rimraf": { - "version": "2.5.4", - "bundled": true, - "requires": { - "glob": "7.0.6" - } - }, - "semver": { - "version": "5.1.0", - "bundled": true - }, - "sha": { - "version": "2.0.1", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "readable-stream": "2.0.2" - }, - "dependencies": { - "readable-stream": { - "version": "2.0.2", - "bundled": true, - "requires": { - "core-util-is": "1.0.1", - "inherits": "2.0.3", - "isarray": "0.0.1", - "process-nextick-args": "1.0.3", - "string_decoder": "0.10.31", - "util-deprecate": "1.0.1" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.1", - "bundled": true - }, - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "process-nextick-args": { - "version": "1.0.3", - "bundled": true - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.1", - "bundled": true - } - } - } - } - }, - "slide": { - "version": "1.1.6", - "bundled": true - }, - "sorted-object": { - "version": "2.0.0", - "bundled": true - }, - "spdx-license-ids": { - "version": "1.2.2", - "bundled": true - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.0.0" - } - }, - "tar": { - "version": "2.2.1", - "bundled": true, - "requires": { - "block-stream": "0.0.9", - "fstream": "1.0.10", - "inherits": "2.0.3" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "uid-number": { - "version": "0.0.6", - "bundled": true - }, - "umask": { - "version": "1.1.0", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.1", - "bundled": true, - "requires": { - "spdx-correct": "1.0.2", - "spdx-expression-parse": "1.0.2" - }, - "dependencies": { - "spdx-correct": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-license-ids": "1.2.2" - } - }, - "spdx-expression-parse": { - "version": "1.0.2", - "bundled": true, - "requires": { - "spdx-exceptions": "1.0.4", - "spdx-license-ids": "1.2.2" - }, - "dependencies": { - "spdx-exceptions": { - "version": "1.0.4", - "bundled": true - } - } - } - } - }, - "validate-npm-package-name": { - "version": "2.2.2", - "bundled": true, - "requires": { - "builtins": "0.0.7" - }, - "dependencies": { - "builtins": { - "version": "0.0.7", - "bundled": true - } - } - }, - "which": { - "version": "1.2.11", - "bundled": true, - "requires": { - "isexe": "1.1.2" - }, - "dependencies": { - "isexe": { - "version": "1.1.2", - "bundled": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write-file-atomic": { - "version": "1.1.4", - "bundled": true, - "requires": { - "graceful-fs": "4.1.6", - "imurmurhash": "0.1.4", - "slide": "1.1.6" - } - } - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "p-limit": { - "version": "1.3.0", - "bundled": true, - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true - }, - "pac-proxy-agent": { - "version": "2.0.2", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "get-uri": "2.0.2", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "pac-resolver": "3.0.0", - "raw-body": "2.3.3", - "socks-proxy-agent": "3.0.1" - } - }, - "pac-resolver": { - "version": "3.0.0", - "bundled": true, - "requires": { - "co": "4.6.0", - "degenerator": "1.0.4", - "ip": "1.1.5", - "netmask": "1.0.6", - "thunkify": "2.1.2" - } - }, - "package": { - "version": "1.0.1", - "bundled": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.2" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true - }, - "path-type": { - "version": "1.1.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "proxy-agent": { - "version": "3.0.0", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "debug": "3.1.0", - "http-proxy-agent": "2.1.0", - "https-proxy-agent": "2.2.1", - "lru-cache": "4.1.3", - "pac-proxy-agent": "2.0.2", - "proxy-from-env": "1.0.0", - "socks-proxy-agent": "3.0.1" - } - }, - "proxy-from-env": { - "version": "1.0.0", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "q": { - "version": "1.5.1", - "bundled": true - }, - "raw-body": { - "version": "2.3.3", - "bundled": true, - "requires": { - "bytes": "3.0.0", - "http-errors": "1.6.3", - "iconv-lite": "0.4.23", - "unpipe": "1.0.0" - } - }, - "read-pkg": { - "version": "1.1.0", - "bundled": true, - "requires": { - "load-json-file": "1.1.0", - "normalize-package-data": "2.4.0", - "path-type": "1.1.0" - } - }, - "read-pkg-up": { - "version": "1.0.1", - "bundled": true, - "requires": { - "find-up": "1.1.2", - "read-pkg": "1.1.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "redent": { - "version": "1.0.0", - "bundled": true, - "requires": { - "indent-string": "2.1.0", - "strip-indent": "1.0.1" - } - }, - "regexpp": { - "version": "1.1.0", - "bundled": true - }, - "repeating": { - "version": "2.0.1", - "bundled": true, - "requires": { - "is-finite": "1.0.2" - } - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.1.7", - "bundled": true - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "sax": { - "version": "1.1.5", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "setprototypeof": { - "version": "1.1.0", - "bundled": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "smart-buffer": { - "version": "1.1.15", - "bundled": true - }, - "socks": { - "version": "1.1.10", - "bundled": true, - "requires": { - "ip": "1.1.5", - "smart-buffer": "1.1.15" - } - }, - "socks-proxy-agent": { - "version": "3.0.1", - "bundled": true, - "requires": { - "agent-base": "4.2.1", - "socks": "1.1.10" - } - }, - "source-map": { - "version": "0.6.1", - "bundled": true, - "optional": true - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "statuses": { - "version": "1.5.0", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "bundled": true - } - } - }, - "strip-bom": { - "version": "2.0.0", - "bundled": true, - "requires": { - "is-utf8": "0.2.1" - } - }, - "strip-indent": { - "version": "1.0.1", - "bundled": true, - "requires": { - "get-stdin": "4.0.1" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "tar-stream": { - "version": "1.1.5", - "bundled": true, - "requires": { - "bl": "0.9.5", - "end-of-stream": "1.4.1", - "readable-stream": "1.0.34", - "xtend": "4.0.1" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - }, - "temporary": { - "version": "0.0.8", - "bundled": true, - "requires": { - "package": "1.0.1" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "thunkify": { - "version": "2.1.2", - "bundled": true - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "trim-newlines": { - "version": "1.0.0", - "bundled": true - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "underscore.string": { - "version": "3.3.4", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3", - "util-deprecate": "1.0.2" - } - }, - "unpipe": { - "version": "1.0.0", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "3.3.2", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "xml2js": { - "version": "0.4.15", - "bundled": true, - "requires": { - "sax": "1.1.5", - "xmlbuilder": "2.6.2" - } - }, - "xmlbuilder": { - "version": "2.6.2", - "bundled": true, - "requires": { - "lodash": "3.5.0" - }, - "dependencies": { - "lodash": { - "version": "3.5.0", - "bundled": true - } - } - }, - "xregexp": { - "version": "2.0.0", - "bundled": true - }, - "xtend": { - "version": "4.0.1", - "bundled": true - }, - "yallist": { - "version": "2.1.2", - "bundled": true - }, - "zip-stream": { - "version": "0.5.2", - "bundled": true, - "requires": { - "compress-commons": "0.2.9", - "lodash": "3.2.0", - "readable-stream": "1.0.34" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "bundled": true - }, - "lodash": { - "version": "3.2.0", - "bundled": true - }, - "readable-stream": { - "version": "1.0.34", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "0.0.1", - "string_decoder": "0.10.31" - } - }, - "string_decoder": { - "version": "0.10.31", - "bundled": true - } - } - } - } - }, - "amplify-category-storage": { - "version": "file:../amplify-category-storage", - "requires": { - "eslint": "4.19.1", - "inquirer": "3.3.0", - "uuid": "2.0.3" - }, - "dependencies": { - "acorn": { - "version": "5.6.2", - "bundled": true - }, - "acorn-jsx": { - "version": "3.0.1", - "bundled": true, - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "bundled": true - } - } - }, - "ajv": { - "version": "5.5.2", - "bundled": true, - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - } - }, - "ajv-keywords": { - "version": "2.1.1", - "bundled": true - }, - "ansi-escapes": { - "version": "3.1.0", - "bundled": true - }, - "ansi-regex": { - "version": "3.0.0", - "bundled": true - }, - "ansi-styles": { - "version": "3.2.1", - "bundled": true, - "requires": { - "color-convert": "1.9.1" - } - }, - "argparse": { - "version": "1.0.10", - "bundled": true, - "requires": { - "sprintf-js": "1.0.3" - } - }, - "array-union": { - "version": "1.0.2", - "bundled": true, - "requires": { - "array-uniq": "1.0.3" - } - }, - "array-uniq": { - "version": "1.0.3", - "bundled": true - }, - "arrify": { - "version": "1.0.1", - "bundled": true - }, - "babel-code-frame": { - "version": "6.26.0", - "bundled": true, - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - }, - "ansi-styles": { - "version": "2.2.1", - "bundled": true - }, - "chalk": { - "version": "1.1.3", - "bundled": true, - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - } - }, - "supports-color": { - "version": "2.0.0", - "bundled": true - } - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - } - }, - "buffer-from": { - "version": "1.1.0", - "bundled": true - }, - "builtin-modules": { - "version": "1.1.1", - "bundled": true - }, - "caller-path": { - "version": "0.1.0", - "bundled": true, - "requires": { - "callsites": "0.2.0" - } - }, - "callsites": { - "version": "0.2.0", - "bundled": true - }, - "chalk": { - "version": "2.4.1", - "bundled": true, - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - } - }, - "chardet": { - "version": "0.4.2", - "bundled": true - }, - "circular-json": { - "version": "0.3.3", - "bundled": true - }, - "cli-cursor": { - "version": "2.1.0", - "bundled": true, - "requires": { - "restore-cursor": "2.0.0" - } - }, - "cli-width": { - "version": "2.2.0", - "bundled": true - }, - "co": { - "version": "4.6.0", - "bundled": true - }, - "color-convert": { - "version": "1.9.1", - "bundled": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "bundled": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true - }, - "concat-stream": { - "version": "1.6.2", - "bundled": true, - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - } - }, - "contains-path": { - "version": "0.1.0", - "bundled": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true - }, - "cross-spawn": { - "version": "5.1.0", - "bundled": true, - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - } - }, - "debug": { - "version": "3.1.0", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "deep-is": { - "version": "0.1.3", - "bundled": true - }, - "del": { - "version": "2.2.2", - "bundled": true, - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - } - }, - "doctrine": { - "version": "2.1.0", - "bundled": true, - "requires": { - "esutils": "2.0.2" - } - }, - "error-ex": { - "version": "1.3.1", - "bundled": true, - "requires": { - "is-arrayish": "0.2.1" - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "bundled": true - }, - "eslint": { - "version": "4.19.1", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.5.0", - "ignore": "3.3.8", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "bundled": true, - "requires": { - "eslint-restricted-globals": "0.1.1" - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "bundled": true, - "requires": { - "debug": "2.6.9", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "bundled": true, - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - } - } - }, - "eslint-plugin-import": { - "version": "2.12.0", - "bundled": true, - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.7.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "bundled": true, - "requires": { - "ms": "2.0.0" - } - }, - "doctrine": { - "version": "1.5.0", - "bundled": true, - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - } - } - } - }, - "eslint-restricted-globals": { - "version": "0.1.1", - "bundled": true - }, - "eslint-scope": { - "version": "3.7.1", - "bundled": true, - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "bundled": true - }, - "espree": { - "version": "3.5.4", - "bundled": true, - "requires": { - "acorn": "5.6.2", - "acorn-jsx": "3.0.1" - } - }, - "esprima": { - "version": "4.0.0", - "bundled": true - }, - "esquery": { - "version": "1.0.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "esrecurse": { - "version": "4.2.1", - "bundled": true, - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "bundled": true - }, - "esutils": { - "version": "2.0.2", - "bundled": true - }, - "external-editor": { - "version": "2.2.0", - "bundled": true, - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - } - }, - "fast-deep-equal": { - "version": "1.1.0", - "bundled": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "bundled": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "bundled": true - }, - "figures": { - "version": "2.0.0", - "bundled": true, - "requires": { - "escape-string-regexp": "1.0.5" - } - }, - "file-entry-cache": { - "version": "2.0.0", - "bundled": true, - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - } - }, - "find-up": { - "version": "1.1.2", - "bundled": true, - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - } - }, - "flat-cache": { - "version": "1.3.0", - "bundled": true, - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true - }, - "function-bind": { - "version": "1.1.1", - "bundled": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "bundled": true - }, - "glob": { - "version": "7.1.2", - "bundled": true, - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - } - }, - "globals": { - "version": "11.5.0", - "bundled": true - }, - "globby": { - "version": "5.0.0", - "bundled": true, - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - } - }, - "graceful-fs": { - "version": "4.1.11", - "bundled": true - }, - "has": { - "version": "1.0.3", - "bundled": true, - "requires": { - "function-bind": "1.1.1" - } - }, - "has-ansi": { - "version": "2.0.0", - "bundled": true, - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "bundled": true - } - } - }, - "has-flag": { - "version": "3.0.0", - "bundled": true - }, - "hosted-git-info": { - "version": "2.6.0", - "bundled": true - }, - "iconv-lite": { - "version": "0.4.23", - "bundled": true, - "requires": { - "safer-buffer": "2.1.2" - } - }, - "ignore": { - "version": "3.3.8", - "bundled": true - }, - "imurmurhash": { - "version": "0.1.4", - "bundled": true - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true - }, - "inquirer": { - "version": "3.3.0", - "bundled": true, - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - } - }, - "is-arrayish": { - "version": "0.2.1", - "bundled": true - }, - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.1" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "bundled": true - }, - "is-path-cwd": { - "version": "1.0.0", - "bundled": true - }, - "is-path-in-cwd": { - "version": "1.0.1", - "bundled": true, - "requires": { - "is-path-inside": "1.0.1" - } - }, - "is-path-inside": { - "version": "1.0.1", - "bundled": true, - "requires": { - "path-is-inside": "1.0.2" - } - }, - "is-promise": { - "version": "2.1.0", - "bundled": true - }, - "is-resolvable": { - "version": "1.1.0", - "bundled": true - }, - "isarray": { - "version": "1.0.0", - "bundled": true - }, - "isexe": { - "version": "2.0.0", - "bundled": true - }, - "js-tokens": { - "version": "3.0.2", - "bundled": true - }, - "js-yaml": { - "version": "3.12.0", - "bundled": true, - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - } - }, - "json-schema-traverse": { - "version": "0.3.1", - "bundled": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "bundled": true - }, - "levn": { - "version": "0.3.0", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - } - }, - "load-json-file": { - "version": "2.0.0", - "bundled": true, - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - } - }, - "locate-path": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "bundled": true - } - } - }, - "lodash": { - "version": "4.17.10", - "bundled": true - }, - "lru-cache": { - "version": "4.1.3", - "bundled": true, - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - } - }, - "mimic-fn": { - "version": "1.2.0", - "bundled": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "requires": { - "brace-expansion": "1.1.11" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.0.0", - "bundled": true - }, - "mute-stream": { - "version": "0.0.7", - "bundled": true - }, - "natural-compare": { - "version": "1.4.0", - "bundled": true - }, - "normalize-package-data": { - "version": "2.4.0", - "bundled": true, - "requires": { - "hosted-git-info": "2.6.0", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - } - }, - "object-assign": { - "version": "4.1.1", - "bundled": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "requires": { - "wrappy": "1.0.2" - } - }, - "onetime": { - "version": "2.0.1", - "bundled": true, - "requires": { - "mimic-fn": "1.2.0" - } - }, - "optionator": { - "version": "0.8.2", - "bundled": true, - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true - }, - "p-limit": { - "version": "1.3.0", - "bundled": true, - "requires": { - "p-try": "1.0.0" - } - }, - "p-locate": { - "version": "2.0.0", - "bundled": true, - "requires": { - "p-limit": "1.3.0" - } - }, - "p-try": { - "version": "1.0.0", - "bundled": true - }, - "parse-json": { - "version": "2.2.0", - "bundled": true, - "requires": { - "error-ex": "1.3.1" - } - }, - "path-exists": { - "version": "2.1.0", - "bundled": true, - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true - }, - "path-is-inside": { - "version": "1.0.2", - "bundled": true - }, - "path-parse": { - "version": "1.0.5", - "bundled": true - }, - "path-type": { - "version": "2.0.0", - "bundled": true, - "requires": { - "pify": "2.3.0" - } - }, - "pify": { - "version": "2.3.0", - "bundled": true - }, - "pinkie": { - "version": "2.0.4", - "bundled": true - }, - "pinkie-promise": { - "version": "2.0.1", - "bundled": true, - "requires": { - "pinkie": "2.0.4" - } - }, - "pkg-dir": { - "version": "1.0.0", - "bundled": true, - "requires": { - "find-up": "1.1.2" - } - }, - "pluralize": { - "version": "7.0.0", - "bundled": true - }, - "prelude-ls": { - "version": "1.1.2", - "bundled": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true - }, - "progress": { - "version": "2.0.0", - "bundled": true - }, - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "read-pkg": { - "version": "2.0.0", - "bundled": true, - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - } - }, - "read-pkg-up": { - "version": "2.0.0", - "bundled": true, - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "bundled": true, - "requires": { - "locate-path": "2.0.0" - } - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - } - }, - "regexpp": { - "version": "1.1.0", - "bundled": true - }, - "require-uncached": { - "version": "1.0.3", - "bundled": true, - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - } - }, - "resolve": { - "version": "1.7.1", - "bundled": true, - "requires": { - "path-parse": "1.0.5" - } - }, - "resolve-from": { - "version": "1.0.1", - "bundled": true - }, - "restore-cursor": { - "version": "2.0.0", - "bundled": true, - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - } - }, - "rimraf": { - "version": "2.6.2", - "bundled": true, - "requires": { - "glob": "7.1.2" - } - }, - "run-async": { - "version": "2.3.0", - "bundled": true, - "requires": { - "is-promise": "2.1.0" - } - }, - "rx-lite": { - "version": "4.0.8", - "bundled": true - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "bundled": true, - "requires": { - "rx-lite": "4.0.8" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true - }, - "semver": { - "version": "5.5.0", - "bundled": true - }, - "shebang-command": { - "version": "1.2.0", - "bundled": true, - "requires": { - "shebang-regex": "1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "bundled": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true - }, - "slice-ansi": { - "version": "1.0.0", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0" - } - }, - "spdx-correct": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.1.0", - "bundled": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "bundled": true, - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.0", - "bundled": true - }, - "sprintf-js": { - "version": "1.0.3", - "bundled": true - }, - "string-width": { - "version": "2.1.1", - "bundled": true, - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "requires": { - "safe-buffer": "5.1.2" - } - }, - "strip-ansi": { - "version": "4.0.0", - "bundled": true, - "requires": { - "ansi-regex": "3.0.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "bundled": true - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true - }, - "supports-color": { - "version": "5.4.0", - "bundled": true, - "requires": { - "has-flag": "3.0.0" - } - }, - "table": { - "version": "4.0.2", - "bundled": true, - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - } - }, - "text-table": { - "version": "0.2.0", - "bundled": true - }, - "through": { - "version": "2.3.8", - "bundled": true - }, - "tmp": { - "version": "0.0.33", - "bundled": true, - "requires": { - "os-tmpdir": "1.0.2" - } - }, - "type-check": { - "version": "0.3.2", - "bundled": true, - "requires": { - "prelude-ls": "1.1.2" - } - }, - "typedarray": { - "version": "0.0.6", - "bundled": true - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true - }, - "uuid": { - "version": "2.0.3", - "bundled": true - }, - "validate-npm-package-license": { - "version": "3.0.3", - "bundled": true, - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - } - }, - "which": { - "version": "1.3.1", - "bundled": true, - "requires": { - "isexe": "2.0.0" - } - }, - "wordwrap": { - "version": "1.0.0", - "bundled": true - }, - "wrappy": { - "version": "1.0.2", - "bundled": true - }, - "write": { - "version": "0.2.1", - "bundled": true, - "requires": { - "mkdirp": "0.5.1" - } - }, - "yallist": { - "version": "2.1.2", - "bundled": true - } - } - }, - "eslint": { - "version": "4.19.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.19.1.tgz", - "integrity": "sha512-bT3/1x1EbZB7phzYu7vCr1v3ONuzDtX8WjuM9c0iYxe+cq+pwcKEoQjl7zd3RpC6YOLgnSy3cTN58M2jcoPDIQ==", - "requires": { - "ajv": "5.5.2", - "babel-code-frame": "6.26.0", - "chalk": "2.4.1", - "concat-stream": "1.6.2", - "cross-spawn": "5.1.0", - "debug": "3.1.0", - "doctrine": "2.1.0", - "eslint-scope": "3.7.1", - "eslint-visitor-keys": "1.0.0", - "espree": "3.5.4", - "esquery": "1.0.1", - "esutils": "2.0.2", - "file-entry-cache": "2.0.0", - "functional-red-black-tree": "1.0.1", - "glob": "7.1.2", - "globals": "11.7.0", - "ignore": "3.3.10", - "imurmurhash": "0.1.4", - "inquirer": "3.3.0", - "is-resolvable": "1.1.0", - "js-yaml": "3.12.0", - "json-stable-stringify-without-jsonify": "1.0.1", - "levn": "0.3.0", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "mkdirp": "0.5.1", - "natural-compare": "1.4.0", - "optionator": "0.8.2", - "path-is-inside": "1.0.2", - "pluralize": "7.0.0", - "progress": "2.0.0", - "regexpp": "1.1.0", - "require-uncached": "1.0.3", - "semver": "5.5.0", - "strip-ansi": "4.0.0", - "strip-json-comments": "2.0.1", - "table": "4.0.2", - "text-table": "0.2.0" - }, - "dependencies": { - "ajv": { - "version": "5.5.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz", - "integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=", - "requires": { - "co": "4.6.0", - "fast-deep-equal": "1.1.0", - "fast-json-stable-stringify": "2.0.0", - "json-schema-traverse": "0.3.1" - }, - "dependencies": { - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "fast-deep-equal": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz", - "integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ=" - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" - }, - "json-schema-traverse": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", - "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=" - } - } - }, - "babel-code-frame": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", - "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", - "requires": { - "chalk": "1.1.3", - "esutils": "2.0.2", - "js-tokens": "3.0.2" - }, - "dependencies": { - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "requires": { - "ansi-styles": "2.2.1", - "escape-string-regexp": "1.0.5", - "has-ansi": "2.0.0", - "strip-ansi": "3.0.1", - "supports-color": "2.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "requires": { - "ansi-regex": "2.1.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" - } - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" - } - } - }, - "js-tokens": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", - "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=" - } - } - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "requires": { - "color-convert": "1.9.2" - }, - "dependencies": { - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", - "requires": { - "color-name": "1.1.1" - }, - "dependencies": { - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - } - } - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", - "requires": { - "has-flag": "3.0.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - } - } - } - } - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha1-kEvfGUzTEi/Gdcd/xKw9T/D9GjQ=", - "requires": { - "buffer-from": "1.1.0", - "inherits": "2.0.3", - "readable-stream": "2.3.6", - "typedarray": "0.0.6" - }, - "dependencies": { - "buffer-from": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.0.tgz", - "integrity": "sha1-h/yqOimDWOCt5uRCz86EB0DRrQQ=" - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha1-sRwn2IuP8fvgcGQ8+UsMea4bCq8=", - "requires": { - "core-util-is": "1.0.2", - "inherits": "2.0.3", - "isarray": "1.0.0", - "process-nextick-args": "2.0.0", - "safe-buffer": "5.1.2", - "string_decoder": "1.1.1", - "util-deprecate": "1.0.2" - }, - "dependencies": { - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - }, - "process-nextick-args": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=" - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" - } - } - }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" - } - } - }, - "cross-spawn": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", - "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", - "requires": { - "lru-cache": "4.1.3", - "shebang-command": "1.2.0", - "which": "1.3.1" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", - "requires": { - "pseudomap": "1.0.2", - "yallist": "2.1.2" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - } - } - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "requires": { - "shebang-regex": "1.0.0" - }, - "dependencies": { - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" - } - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha1-pFBD1U9YBTFtqNYvn1CRjT2nCwo=", - "requires": { - "isexe": "2.0.0" - }, - "dependencies": { - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" - } - } - } - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha1-XNAfwQFiG0LEzX9dGmYkNxbT850=", - "requires": { - "esutils": "2.0.2" - } - }, - "eslint-scope": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", - "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", - "requires": { - "esrecurse": "4.2.1", - "estraverse": "4.2.0" - }, - "dependencies": { - "esrecurse": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", - "integrity": "sha1-AHo7n9vCs7uH5IeeoZyS/b05Qs8=", - "requires": { - "estraverse": "4.2.0" - } - }, - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - } - } - }, - "eslint-visitor-keys": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", - "integrity": "sha1-PzGA+y4pEBdxastMnW1bXDSmqB0=" - }, - "espree": { - "version": "3.5.4", - "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz", - "integrity": "sha1-sPRHGHyKi+2US4FaZgvd9d610ac=", - "requires": { - "acorn": "5.7.1", - "acorn-jsx": "3.0.1" - }, - "dependencies": { - "acorn": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.1.tgz", - "integrity": "sha1-8JWCkpdwanyXdpWMCvyJMKm52dg=" - }, - "acorn-jsx": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", - "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", - "requires": { - "acorn": "3.3.0" - }, - "dependencies": { - "acorn": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", - "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=" - } - } - } - } - }, - "esquery": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz", - "integrity": "sha1-QGxRZYsfWZGl+bYrHcJbAOPlxwg=", - "requires": { - "estraverse": "4.2.0" - }, - "dependencies": { - "estraverse": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", - "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" - } - } - }, - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "file-entry-cache": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", - "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", - "requires": { - "flat-cache": "1.3.0", - "object-assign": "4.1.1" - }, - "dependencies": { - "flat-cache": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", - "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", - "requires": { - "circular-json": "0.3.3", - "del": "2.2.2", - "graceful-fs": "4.1.11", - "write": "0.2.1" - }, - "dependencies": { - "circular-json": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", - "integrity": "sha1-gVyZ6oT2gJUp0vRXkb34JxE1LWY=" - }, - "del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", - "requires": { - "globby": "5.0.0", - "is-path-cwd": "1.0.0", - "is-path-in-cwd": "1.0.1", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1", - "rimraf": "2.6.2" - }, - "dependencies": { - "globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", - "requires": { - "array-union": "1.0.2", - "arrify": "1.0.1", - "glob": "7.1.2", - "object-assign": "4.1.1", - "pify": "2.3.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", - "requires": { - "array-uniq": "1.0.3" - }, - "dependencies": { - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - } - } - }, - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - } - } - }, - "is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=" - }, - "is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha1-WsSLNF72dTOb1sekipEhELJBz1I=", - "requires": { - "is-path-inside": "1.0.1" - }, - "dependencies": { - "is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", - "requires": { - "path-is-inside": "1.0.2" - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - }, - "rimraf": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", - "requires": { - "glob": "7.1.2" - } - } - } - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "write": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", - "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", - "requires": { - "mkdirp": "0.5.1" - } - } - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - } - } - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=" - }, - "glob": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", - "integrity": "sha1-wZyd+aAocC1nhhI4SmVSQExjbRU=", - "requires": { - "fs.realpath": "1.0.0", - "inflight": "1.0.6", - "inherits": "2.0.3", - "minimatch": "3.0.4", - "once": "1.4.0", - "path-is-absolute": "1.0.1" - }, - "dependencies": { - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "1.4.0", - "wrappy": "1.0.2" - }, - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1.0.2" - }, - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - } - } - }, - "globals": { - "version": "11.7.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.7.0.tgz", - "integrity": "sha1-pYP6pDBVsayncZFL9oJY4vwSVnM=" - }, - "ignore": { - "version": "3.3.10", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz", - "integrity": "sha1-Cpf7h2mG6AgcYxFg+PnziRV/AEM=" - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" - }, - "is-resolvable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz", - "integrity": "sha1-+xj4fOH+uSUWnJpAfBkxijIG7Yg=" - }, - "js-yaml": { - "version": "3.12.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", - "integrity": "sha1-6u1lbsg0TxD1J8a/obbiJE3hZ9E=", - "requires": { - "argparse": "1.0.10", - "esprima": "4.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", - "requires": { - "sprintf-js": "1.0.3" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" - } - } - }, - "esprima": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", - "integrity": "sha1-RJnt3NERDgshi6zy+n9/WfVcqAQ=" - } - } - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=" - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "requires": { - "prelude-ls": "1.1.2", - "type-check": "0.3.2" - }, - "dependencies": { - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "1.1.2" - } - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "requires": { - "brace-expansion": "1.1.11" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - } - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - }, - "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "requires": { - "deep-is": "0.1.3", - "fast-levenshtein": "2.0.6", - "levn": "0.3.0", - "prelude-ls": "1.1.2", - "type-check": "0.3.2", - "wordwrap": "1.0.0" - }, - "dependencies": { - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "requires": { - "prelude-ls": "1.1.2" - } - }, - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" - } - } - }, - "path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=" - }, - "pluralize": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", - "integrity": "sha1-KYuJ34uTsCIdv0Ia0rGx6iP8Z3c=" - }, - "progress": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", - "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=" - }, - "regexpp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-1.1.0.tgz", - "integrity": "sha1-DjUW3Qt5BPQT0tQZPc5GGMOmias=" - }, - "require-uncached": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", - "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", - "requires": { - "caller-path": "0.1.0", - "resolve-from": "1.0.1" - }, - "dependencies": { - "caller-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", - "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", - "requires": { - "callsites": "0.2.0" - }, - "dependencies": { - "callsites": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", - "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=" - } - } - }, - "resolve-from": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", - "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=" - } - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" - }, - "table": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", - "integrity": "sha1-ozRHN1OR52atNNNIbm4q7chNLjY=", - "requires": { - "ajv": "5.5.2", - "ajv-keywords": "2.1.1", - "chalk": "2.4.1", - "lodash": "4.17.10", - "slice-ansi": "1.0.0", - "string-width": "2.1.1" - }, - "dependencies": { - "ajv-keywords": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", - "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=" - }, - "slice-ansi": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", - "integrity": "sha1-BE8aSdiEL/MHqta1Be0Xi9lQE00=", - "requires": { - "is-fullwidth-code-point": "2.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=" - } - } - }, - "eslint-config-airbnb-base": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", - "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", - "requires": { - "eslint-restricted-globals": "0.1.1" - }, - "dependencies": { - "eslint-restricted-globals": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", - "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=" - } - } - }, - "eslint-plugin-import": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.13.0.tgz", - "integrity": "sha512-t6hGKQDMIt9N8R7vLepsYXgDfeuhp6ZJSgtrLEDxonpSubyxUZHjhm6LsAaZX8q6GYVxkbT3kTsV9G5mBCFR6A==", - "requires": { - "contains-path": "0.1.0", - "debug": "2.6.9", - "doctrine": "1.5.0", - "eslint-import-resolver-node": "0.3.2", - "eslint-module-utils": "2.2.0", - "has": "1.0.3", - "lodash": "4.17.10", - "minimatch": "3.0.4", - "read-pkg-up": "2.0.0", - "resolve": "1.8.1" - }, - "dependencies": { - "contains-path": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", - "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=" - }, - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "requires": { - "ms": "2.0.0" - }, - "dependencies": { - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - } - } - }, - "doctrine": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", - "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", - "requires": { - "esutils": "2.0.2", - "isarray": "1.0.0" - }, - "dependencies": { - "esutils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", - "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" - } - } - }, - "eslint-import-resolver-node": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz", - "integrity": "sha1-WPFfuDm40FdsqYBBNHaqskcttmo=", - "requires": { - "debug": "2.6.9", - "resolve": "1.8.1" - } - }, - "eslint-module-utils": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.2.0.tgz", - "integrity": "sha1-snA2LNiLGkitMIl2zn+lTphBF0Y=", - "requires": { - "debug": "2.6.9", - "pkg-dir": "1.0.0" - }, - "dependencies": { - "pkg-dir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", - "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", - "requires": { - "find-up": "1.1.2" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "2.1.0", - "pinkie-promise": "2.0.1" - }, - "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "2.0.1" - } - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "2.0.4" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } - } - } - } - } - } - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha1-ci18v8H2qoJB8W3YFOAR4fQeh5Y=", - "requires": { - "function-bind": "1.1.1" - }, - "dependencies": { - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=" - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", - "requires": { - "brace-expansion": "1.1.11" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", - "requires": { - "balanced-match": "1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - } - } - } - } - }, - "read-pkg-up": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", - "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", - "requires": { - "find-up": "2.1.0", - "read-pkg": "2.0.0" - }, - "dependencies": { - "find-up": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", - "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", - "requires": { - "locate-path": "2.0.0" - }, - "dependencies": { - "locate-path": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", - "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", - "requires": { - "p-locate": "2.0.0", - "path-exists": "3.0.0" - }, - "dependencies": { - "p-locate": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", - "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", - "requires": { - "p-limit": "1.3.0" - }, - "dependencies": { - "p-limit": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", - "integrity": "sha1-uGvV8MJWkJEcdZD8v8IBDVSzzLg=", - "requires": { - "p-try": "1.0.0" - }, - "dependencies": { - "p-try": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", - "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" - } - } - } - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" - } - } - } - } - }, - "read-pkg": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", - "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", - "requires": { - "load-json-file": "2.0.0", - "normalize-package-data": "2.4.0", - "path-type": "2.0.0" - }, - "dependencies": { - "load-json-file": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", - "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", - "requires": { - "graceful-fs": "4.1.11", - "parse-json": "2.2.0", - "pify": "2.3.0", - "strip-bom": "3.0.0" - }, - "dependencies": { - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "requires": { - "error-ex": "1.3.2" - }, - "dependencies": { - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha1-tKxAZIEH/c3PriQvQovqihTU8b8=", - "requires": { - "is-arrayish": "0.2.1" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" - } - } - } - } - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" - } - } - }, - "normalize-package-data": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", - "requires": { - "hosted-git-info": "2.6.1", - "is-builtin-module": "1.0.0", - "semver": "5.5.0", - "validate-npm-package-license": "3.0.3" - }, - "dependencies": { - "hosted-git-info": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.1.tgz", - "integrity": "sha1-bkzueLAbuEnc+TUncIxp/b7kEN8=" - }, - "is-builtin-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", - "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", - "requires": { - "builtin-modules": "1.1.1" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" - } - } - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha1-3Eu8emyp2Rbe5dQ1FvAJK1j3uKs=" - }, - "validate-npm-package-license": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", - "integrity": "sha1-gWQ7y+8b3+zUYjeT3EZIlIupgzg=", - "requires": { - "spdx-correct": "3.0.0", - "spdx-expression-parse": "3.0.0" - }, - "dependencies": { - "spdx-correct": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", - "integrity": "sha1-BaW01xU6GVvJLDxCW2nzsqlSTII=", - "requires": { - "spdx-expression-parse": "3.0.0", - "spdx-license-ids": "3.0.0" - }, - "dependencies": { - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" - } - } - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", - "requires": { - "spdx-exceptions": "2.1.0", - "spdx-license-ids": "3.0.0" - }, - "dependencies": { - "spdx-exceptions": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", - "integrity": "sha1-LHrmEFbHFKW5ubKyr30xHvXHj+k=" - }, - "spdx-license-ids": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", - "integrity": "sha1-enzShHDMbToc/m1miG9rxDDTrIc=" - } - } - } - } - } - } - }, - "path-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", - "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", - "requires": { - "pify": "2.3.0" - }, - "dependencies": { - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" - } - } - } - } - } - } - }, - "resolve": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.8.1.tgz", - "integrity": "sha1-gvHsGaQjrB+9CAsLqwa6NuhKeiY=", - "requires": { - "path-parse": "1.0.5" - }, - "dependencies": { - "path-parse": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", - "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" - } - } - } - } - }, - "inquirer": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", - "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", - "requires": { - "ansi-escapes": "3.1.0", - "chalk": "2.4.1", - "cli-cursor": "2.1.0", - "cli-width": "2.2.0", - "external-editor": "2.2.0", - "figures": "2.0.0", - "lodash": "4.17.10", - "mute-stream": "0.0.7", - "run-async": "2.3.0", - "rx-lite": "4.0.8", - "rx-lite-aggregates": "4.0.8", - "string-width": "2.1.1", - "strip-ansi": "4.0.0", - "through": "2.3.8" - }, - "dependencies": { - "ansi-escapes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.1.0.tgz", - "integrity": "sha1-9zIHu4EgfXX9bIPxJa8m7qN4yjA=" - }, - "chalk": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", - "requires": { - "ansi-styles": "3.2.1", - "escape-string-regexp": "1.0.5", - "supports-color": "5.4.0" - }, - "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", - "requires": { - "color-convert": "1.9.2" - }, - "dependencies": { - "color-convert": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz", - "integrity": "sha1-SYgbj7pn3xKpa98/VsCqueeRMUc=", - "requires": { - "color-name": "1.1.1" - }, - "dependencies": { - "color-name": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz", - "integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok=" - } - } - } - } - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - }, - "supports-color": { - "version": "5.4.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz", - "integrity": "sha1-HGszdALCE3YF7+GfEP7DkPb6q1Q=", - "requires": { - "has-flag": "3.0.0" - }, - "dependencies": { - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" - } - } - } - } - }, - "cli-cursor": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", - "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", - "requires": { - "restore-cursor": "2.0.0" - }, - "dependencies": { - "restore-cursor": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", - "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", - "requires": { - "onetime": "2.0.1", - "signal-exit": "3.0.2" - }, - "dependencies": { - "onetime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", - "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", - "requires": { - "mimic-fn": "1.2.0" - }, - "dependencies": { - "mimic-fn": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", - "integrity": "sha1-ggyGo5M0ZA6ZUWkovQP8qIBX0CI=" - } - } - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" - } - } - } - } - }, - "cli-width": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", - "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=" - }, - "external-editor": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz", - "integrity": "sha1-BFURz9jRM/OEZnPRBHwVTiFK09U=", - "requires": { - "chardet": "0.4.2", - "iconv-lite": "0.4.23", - "tmp": "0.0.33" - }, - "dependencies": { - "chardet": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", - "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=" - }, - "iconv-lite": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", - "requires": { - "safer-buffer": "2.1.2" - }, - "dependencies": { - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" - } - } - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", - "requires": { - "os-tmpdir": "1.0.2" - }, - "dependencies": { - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - } - } - } - } - }, - "figures": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", - "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", - "requires": { - "escape-string-regexp": "1.0.5" - }, - "dependencies": { - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" - } - } - }, - "lodash": { - "version": "4.17.10", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.10.tgz", - "integrity": "sha1-G3eTz3JZ6jj7NmHU04syYK+K5Oc=" - }, - "mute-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", - "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" - }, - "run-async": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", - "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", - "requires": { - "is-promise": "2.1.0" - }, - "dependencies": { - "is-promise": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", - "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" - } - } - }, - "rx-lite": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", - "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=" - }, - "rx-lite-aggregates": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", - "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", - "requires": { - "rx-lite": "4.0.8" - } - }, - "string-width": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", - "integrity": "sha1-q5Pyeo3BPSjKyBXEYhQ6bZASrp4=", - "requires": { - "is-fullwidth-code-point": "2.0.0", - "strip-ansi": "4.0.0" - }, - "dependencies": { - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" - } - } - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "requires": { - "ansi-regex": "3.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" - } - } - }, - "moment": { - "version": "2.22.2", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", - "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" - }, - "uuid": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", - "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" - } - } -} diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c3b41e17f3..e6e7844063 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -9,8 +9,8 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-storage": "file:../amplify-category-storage", - "amplify-category-function": "file:../amplify-category-function", + "amplify-category-storage": "^0.1.0", + "amplify-category-function": "^0.1.0", "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", From a901c6fac6b17af30333eb7d96e28b4d1ea30474 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Sun, 15 Jul 2018 13:23:16 -0700 Subject: [PATCH 031/587] through eslint --- .../amplify-category-api/package-lock.json | 953 +++++++++++++++++- 1 file changed, 899 insertions(+), 54 deletions(-) diff --git a/packages/amplify-category-api/package-lock.json b/packages/amplify-category-api/package-lock.json index 47beaf4087..51561bb86d 100644 --- a/packages/amplify-category-api/package-lock.json +++ b/packages/amplify-category-api/package-lock.json @@ -54,6 +54,10 @@ "version": "2.1.1", "bundled": true }, + "ansi": { + "version": "0.3.1", + "bundled": true + }, "ansi-escapes": { "version": "3.1.0", "bundled": true @@ -66,6 +70,14 @@ "version": "2.2.1", "bundled": true }, + "ansicolors": { + "version": "0.3.2", + "bundled": true + }, + "ansistyles": { + "version": "0.1.3", + "bundled": true + }, "archiver": { "version": "0.14.4", "bundled": true, @@ -125,6 +137,18 @@ } } }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "requires": { + "delegates": "1.0.0", + "readable-stream": "2.3.6" + } + }, "argparse": { "version": "1.0.10", "bundled": true, @@ -151,6 +175,18 @@ "version": "1.0.1", "bundled": true }, + "asap": { + "version": "2.0.6", + "bundled": true + }, + "asn1": { + "version": "0.2.3", + "bundled": true + }, + "assert-plus": { + "version": "0.2.0", + "bundled": true + }, "ast-types": { "version": "0.11.5", "bundled": true @@ -159,6 +195,13 @@ "version": "1.5.2", "bundled": true }, + "async-some": { + "version": "1.0.2", + "bundled": true, + "requires": { + "dezalgo": "1.0.3" + } + }, "aws-sdk": { "version": "2.2.48", "bundled": true, @@ -168,6 +211,14 @@ "xmlbuilder": "2.6.2" } }, + "aws-sign2": { + "version": "0.6.0", + "bundled": true + }, + "aws4": { + "version": "1.7.0", + "bundled": true + }, "babel-code-frame": { "version": "6.26.0", "bundled": true, @@ -201,6 +252,14 @@ "version": "1.0.0", "bundled": true }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "bundled": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, "bl": { "version": "0.9.5", "bundled": true, @@ -228,6 +287,20 @@ } } }, + "block-stream": { + "version": "0.0.9", + "bundled": true, + "requires": { + "inherits": "2.0.3" + } + }, + "boom": { + "version": "2.10.1", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, "brace-expansion": { "version": "1.1.11", "bundled": true, @@ -244,10 +317,18 @@ "version": "1.1.0", "bundled": true }, + "buffer-shims": { + "version": "1.0.0", + "bundled": true + }, "builtin-modules": { "version": "1.1.1", "bundled": true }, + "builtins": { + "version": "1.0.3", + "bundled": true + }, "bytes": { "version": "3.0.0", "bundled": true @@ -275,6 +356,10 @@ "map-obj": "1.0.1" } }, + "caseless": { + "version": "0.11.0", + "bundled": true + }, "chalk": { "version": "2.4.1", "bundled": true, @@ -300,10 +385,22 @@ } } }, + "char-spinner": { + "version": "1.0.1", + "bundled": true + }, "chardet": { "version": "0.4.2", "bundled": true }, + "chmodr": { + "version": "1.0.2", + "bundled": true + }, + "chownr": { + "version": "1.0.1", + "bundled": true + }, "circular-json": { "version": "0.3.3", "bundled": true @@ -319,6 +416,18 @@ "version": "2.2.0", "bundled": true }, + "clone": { + "version": "1.0.4", + "bundled": true + }, + "cmd-shim": { + "version": "2.0.2", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "mkdirp": "0.5.1" + } + }, "co": { "version": "4.6.0", "bundled": true @@ -342,6 +451,34 @@ "version": "1.1.2", "bundled": true }, + "columnify": { + "version": "1.5.4", + "bundled": true, + "requires": { + "strip-ansi": "3.0.1", + "wcwidth": "1.0.1" + }, + "dependencies": { + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "combined-stream": { + "version": "1.0.6", + "bundled": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.16.0", + "bundled": true + }, "compress-commons": { "version": "0.2.9", "bundled": true, @@ -386,6 +523,14 @@ "typedarray": "0.0.6" } }, + "config-chain": { + "version": "1.1.11", + "bundled": true, + "requires": { + "ini": "1.3.5", + "proto-list": "1.2.4" + } + }, "contains-path": { "version": "0.1.0", "bundled": true @@ -431,6 +576,13 @@ "which": "1.3.1" } }, + "cryptiles": { + "version": "2.0.5", + "bundled": true, + "requires": { + "boom": "2.10.1" + } + }, "currently-unhandled": { "version": "0.4.1", "bundled": true, @@ -438,6 +590,19 @@ "array-find-index": "1.0.2" } }, + "dashdash": { + "version": "1.14.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, "data-uri-to-buffer": { "version": "1.2.0", "bundled": true @@ -457,6 +622,10 @@ "ms": "2.0.0" } }, + "debuglog": { + "version": "1.0.1", + "bundled": true + }, "decamelize": { "version": "1.2.0", "bundled": true @@ -465,6 +634,13 @@ "version": "0.1.3", "bundled": true }, + "defaults": { + "version": "1.0.3", + "bundled": true, + "requires": { + "clone": "1.0.4" + } + }, "degenerator": { "version": "1.0.4", "bundled": true, @@ -493,10 +669,26 @@ "rimraf": "2.6.2" } }, + "delayed-stream": { + "version": "1.0.0", + "bundled": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true + }, "depd": { "version": "1.1.2", "bundled": true }, + "dezalgo": { + "version": "1.0.3", + "bundled": true, + "requires": { + "asap": "2.0.6", + "wrappy": "1.0.2" + } + }, "doctrine": { "version": "2.1.0", "bundled": true, @@ -504,6 +696,18 @@ "esutils": "2.0.2" } }, + "ecc-jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "editor": { + "version": "1.0.0", + "bundled": true + }, "end-of-stream": { "version": "1.4.1", "bundled": true, @@ -798,6 +1002,10 @@ "tmp": "0.0.33" } }, + "extsprintf": { + "version": "1.3.0", + "bundled": true + }, "fast-deep-equal": { "version": "1.1.0", "bundled": true @@ -867,10 +1075,78 @@ "write": "0.2.1" } }, + "forever-agent": { + "version": "0.6.1", + "bundled": true + }, + "form-data": { + "version": "1.0.1", + "bundled": true, + "requires": { + "async": "2.6.1", + "combined-stream": "1.0.6", + "mime-types": "2.1.18" + }, + "dependencies": { + "async": { + "version": "2.6.1", + "bundled": true, + "requires": { + "lodash": "4.17.10" + } + } + } + }, + "fs-vacuum": { + "version": "1.2.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "path-is-inside": "1.0.2", + "rimraf": "2.6.2" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "iferr": "0.1.5", + "imurmurhash": "0.1.4", + "readable-stream": "2.3.6" + } + }, "fs.realpath": { "version": "1.0.0", "bundled": true }, + "fstream": { + "version": "1.0.11", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "inherits": "2.0.3", + "mkdirp": "0.5.1", + "rimraf": "2.6.2" + } + }, + "fstream-ignore": { + "version": "1.0.5", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "inherits": "2.0.3", + "minimatch": "3.0.4" + } + }, + "fstream-npm": { + "version": "1.1.1", + "bundled": true, + "requires": { + "fstream-ignore": "1.0.5", + "inherits": "2.0.3" + } + }, "ftp": { "version": "0.3.10", "bundled": true, @@ -907,6 +1183,28 @@ "version": "1.0.1", "bundled": true }, + "gauge": { + "version": "1.2.7", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "has-unicode": "2.0.1", + "lodash.pad": "4.5.1", + "lodash.padend": "4.6.1", + "lodash.padstart": "4.6.1" + } + }, + "generate-function": { + "version": "2.0.0", + "bundled": true + }, + "generate-object-property": { + "version": "1.2.0", + "bundled": true, + "requires": { + "is-property": "1.0.2" + } + }, "get-stdin": { "version": "4.0.1", "bundled": true @@ -936,6 +1234,27 @@ "version": "0.1.0", "bundled": true }, + "getpass": { + "version": "0.1.7", + "bundled": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "github-url-from-git": { + "version": "1.4.0", + "bundled": true + }, + "github-url-from-username-repo": { + "version": "1.0.2", + "bundled": true + }, "glob": { "version": "7.1.2", "bundled": true, @@ -1165,6 +1484,36 @@ "which": "1.3.1" } }, + "har-validator": { + "version": "2.0.6", + "bundled": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.16.0", + "is-my-json-valid": "2.17.2", + "pinkie-promise": "2.0.1" + }, + "dependencies": { + "chalk": { + "version": "1.1.3", + "bundled": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, "has": { "version": "1.0.3", "bundled": true, @@ -1183,6 +1532,24 @@ "version": "3.0.0", "bundled": true }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hawk": { + "version": "3.1.3", + "bundled": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "hoek": { + "version": "2.16.3", + "bundled": true + }, "hooker": { "version": "0.2.3", "bundled": true @@ -1209,6 +1576,15 @@ "debug": "3.1.0" } }, + "http-signature": { + "version": "1.1.1", + "bundled": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.14.2" + } + }, "https-proxy-agent": { "version": "2.2.1", "bundled": true, @@ -1224,6 +1600,10 @@ "safer-buffer": "2.1.2" } }, + "iferr": { + "version": "0.1.5", + "bundled": true + }, "ignore": { "version": "3.3.10", "bundled": true @@ -1251,6 +1631,33 @@ "version": "2.0.3", "bundled": true }, + "ini": { + "version": "1.3.5", + "bundled": true + }, + "init-package-json": { + "version": "1.9.6", + "bundled": true, + "requires": { + "glob": "7.1.2", + "npm-package-arg": "4.1.1", + "promzard": "0.3.0", + "read": "1.0.7", + "read-package-json": "2.0.13", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3", + "validate-npm-package-name": "3.0.0" + }, + "dependencies": { + "validate-npm-package-name": { + "version": "3.0.0", + "bundled": true, + "requires": { + "builtins": "1.0.3" + } + } + } + }, "inquirer": { "version": "3.3.0", "bundled": true, @@ -1297,6 +1704,21 @@ "version": "2.0.0", "bundled": true }, + "is-my-ip-valid": { + "version": "1.0.0", + "bundled": true + }, + "is-my-json-valid": { + "version": "2.17.2", + "bundled": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "is-my-ip-valid": "1.0.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, "is-path-cwd": { "version": "1.0.0", "bundled": true @@ -1319,10 +1741,18 @@ "version": "2.1.0", "bundled": true }, + "is-property": { + "version": "1.0.2", + "bundled": true + }, "is-resolvable": { "version": "1.1.0", "bundled": true }, + "is-typedarray": { + "version": "1.0.0", + "bundled": true + }, "is-utf8": { "version": "0.2.1", "bundled": true @@ -1335,6 +1765,10 @@ "version": "2.0.0", "bundled": true }, + "isstream": { + "version": "0.1.2", + "bundled": true + }, "js-tokens": { "version": "3.0.2", "bundled": true @@ -1347,6 +1781,19 @@ "esprima": "4.0.0" } }, + "jsbn": { + "version": "0.1.1", + "bundled": true, + "optional": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "bundled": true + }, + "json-schema": { + "version": "0.2.3", + "bundled": true + }, "json-schema-traverse": { "version": "0.3.1", "bundled": true @@ -1355,6 +1802,30 @@ "version": "1.0.1", "bundled": true }, + "json-stringify-safe": { + "version": "5.0.1", + "bundled": true + }, + "jsonpointer": { + "version": "4.0.1", + "bundled": true + }, + "jsprim": { + "version": "1.4.1", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, "lazystream": { "version": "0.1.0", "bundled": true, @@ -1415,10 +1886,29 @@ } } }, + "lockfile": { + "version": "1.0.4", + "bundled": true, + "requires": { + "signal-exit": "3.0.2" + } + }, "lodash": { "version": "4.17.10", "bundled": true }, + "lodash.pad": { + "version": "4.5.1", + "bundled": true + }, + "lodash.padend": { + "version": "4.6.1", + "bundled": true + }, + "lodash.padstart": { + "version": "4.6.1", + "bundled": true + }, "loud-rejection": { "version": "1.6.0", "bundled": true, @@ -1461,6 +1951,17 @@ } } }, + "mime-db": { + "version": "1.33.0", + "bundled": true + }, + "mime-types": { + "version": "2.1.18", + "bundled": true, + "requires": { + "mime-db": "1.33.0" + } + }, "mimic-fn": { "version": "1.2.0", "bundled": true @@ -1499,6 +2000,31 @@ "version": "1.0.6", "bundled": true }, + "node-gyp": { + "version": "3.6.3", + "bundled": true, + "requires": { + "fstream": "1.0.11", + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "npmlog": "2.0.4", + "osenv": "0.1.5", + "request": "2.74.0", + "rimraf": "2.6.2", + "semver": "5.3.0", + "tar": "2.2.1", + "which": "1.3.1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "bundled": true + } + } + }, "node-int64": { "version": "0.3.3", "bundled": true @@ -1510,6 +2036,10 @@ "abbrev": "1.1.1" } }, + "normalize-git-url": { + "version": "3.0.2", + "bundled": true + }, "normalize-package-data": { "version": "2.4.0", "bundled": true, @@ -1555,13 +2085,13 @@ "ini": "1.3.4", "init-package-json": "1.9.4", "lockfile": "1.0.1", - "lru-cache": "4.0.1", + "lru-cache": "4.0.2", "minimatch": "3.0.3", "mkdirp": "0.5.1", "node-gyp": "3.6.0", "nopt": "3.0.6", "normalize-git-url": "3.0.2", - "normalize-package-data": "2.3.5", + "normalize-package-data": "2.3.8", "npm-cache-filename": "1.0.2", "npm-install-checks": "1.0.7", "npm-package-arg": "4.1.0", @@ -1580,7 +2110,7 @@ "request": "2.74.0", "retry": "0.10.0", "rimraf": "2.5.4", - "semver": "5.1.0", + "semver": "5.1.1", "sha": "2.0.1", "slide": "1.1.6", "sorted-object": "2.0.0", @@ -1592,7 +2122,7 @@ "umask": "1.1.0", "validate-npm-package-license": "3.0.1", "validate-npm-package-name": "2.2.2", - "which": "1.2.11", + "which": "1.2.14", "wrappy": "1.0.2", "write-file-atomic": "1.1.4" }, @@ -1840,7 +2370,7 @@ "promzard": "0.3.0", "read": "1.0.7", "read-package-json": "2.0.4", - "semver": "5.1.0", + "semver": "5.1.1", "validate-npm-package-license": "3.0.1", "validate-npm-package-name": "2.2.2" }, @@ -1876,21 +2406,12 @@ "bundled": true }, "lru-cache": { - "version": "4.0.1", - "bundled": true, + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz", + "integrity": "sha1-HRdnnAac2l0ECZGgnbwsDbN35V4=", "requires": { "pseudomap": "1.0.2", - "yallist": "2.0.0" - }, - "dependencies": { - "pseudomap": { - "version": "1.0.2", - "bundled": true - }, - "yallist": { - "version": "2.0.0", - "bundled": true - } + "yallist": "2.1.2" } }, "minimatch": { @@ -1949,7 +2470,7 @@ "rimraf": "2.5.4", "semver": "5.3.0", "tar": "2.2.1", - "which": "1.2.11" + "which": "1.2.14" }, "dependencies": { "semver": { @@ -1970,28 +2491,14 @@ "bundled": true }, "normalize-package-data": { - "version": "2.3.5", - "bundled": true, + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.8.tgz", + "integrity": "sha1-2Bntoqne29H/pWPqQHHZNngilbs=", "requires": { "hosted-git-info": "2.1.5", "is-builtin-module": "1.0.0", - "semver": "5.1.0", + "semver": "5.1.1", "validate-npm-package-license": "3.0.1" - }, - "dependencies": { - "is-builtin-module": { - "version": "1.0.0", - "bundled": true, - "requires": { - "builtin-modules": "1.1.0" - }, - "dependencies": { - "builtin-modules": { - "version": "1.1.0", - "bundled": true - } - } - } } }, "npm-cache-filename": { @@ -2003,7 +2510,7 @@ "bundled": true, "requires": { "npmlog": "2.0.4", - "semver": "5.1.0" + "semver": "5.1.1" } }, "npm-package-arg": { @@ -2011,7 +2518,7 @@ "bundled": true, "requires": { "hosted-git-info": "2.1.5", - "semver": "5.1.0" + "semver": "5.1.1" } }, "npm-registry-client": { @@ -2020,13 +2527,13 @@ "requires": { "concat-stream": "1.5.2", "graceful-fs": "4.1.6", - "normalize-package-data": "2.3.5", + "normalize-package-data": "2.3.8", "npm-package-arg": "4.1.0", "npmlog": "2.0.4", "once": "1.4.0", "request": "2.74.0", "retry": "0.10.0", - "semver": "5.1.0", + "semver": "5.1.1", "slide": "1.1.6" }, "dependencies": { @@ -2203,6 +2710,10 @@ "version": "1.0.1", "bundled": true }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, "read": { "version": "1.0.7", "bundled": true, @@ -2224,7 +2735,7 @@ "graceful-fs": "4.1.6", "read-package-json": "2.0.4", "readdir-scoped-modules": "1.0.2", - "semver": "5.1.0", + "semver": "5.1.1", "slide": "1.1.6", "util-extend": "1.0.1" }, @@ -2256,7 +2767,7 @@ "glob": "6.0.4", "graceful-fs": "4.1.6", "json-parse-helpfulerror": "1.0.3", - "normalize-package-data": "2.3.5" + "normalize-package-data": "2.3.8" }, "dependencies": { "glob": { @@ -2768,8 +3279,9 @@ } }, "semver": { - "version": "5.1.0", - "bundled": true + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.1.1.tgz", + "integrity": "sha1-oykqNz5vPgeY2gsgZBuanFvEfhk=" }, "sha": { "version": "2.0.1", @@ -2827,6 +3339,10 @@ "version": "1.2.2", "bundled": true }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + }, "strip-ansi": { "version": "3.0.1", "bundled": true, @@ -2900,16 +3416,11 @@ } }, "which": { - "version": "1.2.11", - "bundled": true, + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/which/-/which-1.2.14.tgz", + "integrity": "sha1-mofEN48D6CfOyvGs31bHNsAcFOU=", "requires": { - "isexe": "1.1.2" - }, - "dependencies": { - "isexe": { - "version": "1.1.2", - "bundled": true - } + "isexe": "2.0.0" } }, "wrappy": { @@ -2927,10 +3438,63 @@ } } }, + "npm-cache-filename": { + "version": "1.0.2", + "bundled": true + }, + "npm-install-checks": { + "version": "1.0.7", + "bundled": true, + "requires": { + "npmlog": "2.0.4", + "semver": "5.5.0" + } + }, + "npm-package-arg": { + "version": "4.1.1", + "bundled": true, + "requires": { + "hosted-git-info": "2.6.1", + "semver": "5.5.0" + } + }, + "npm-registry-client": { + "version": "7.2.1", + "bundled": true, + "requires": { + "concat-stream": "1.6.2", + "graceful-fs": "4.1.11", + "normalize-package-data": "2.4.0", + "npm-package-arg": "4.1.1", + "npmlog": "2.0.4", + "once": "1.4.0", + "request": "2.74.0", + "retry": "0.10.1", + "semver": "5.5.0", + "slide": "1.1.6" + } + }, + "npm-user-validate": { + "version": "0.1.5", + "bundled": true + }, + "npmlog": { + "version": "2.0.4", + "bundled": true, + "requires": { + "ansi": "0.3.1", + "are-we-there-yet": "1.1.5", + "gauge": "1.2.7" + } + }, "number-is-nan": { "version": "1.0.1", "bundled": true }, + "oauth-sign": { + "version": "0.8.2", + "bundled": true + }, "object-assign": { "version": "4.1.1", "bundled": true @@ -2949,6 +3513,10 @@ "mimic-fn": "1.2.0" } }, + "opener": { + "version": "1.4.3", + "bundled": true + }, "optionator": { "version": "0.8.2", "bundled": true, @@ -2961,10 +3529,22 @@ "wordwrap": "1.0.0" } }, + "os-homedir": { + "version": "1.0.2", + "bundled": true + }, "os-tmpdir": { "version": "1.0.2", "bundled": true }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "requires": { + "os-homedir": "1.0.2", + "os-tmpdir": "1.0.2" + } + }, "p-limit": { "version": "1.3.0", "bundled": true, @@ -3085,6 +3665,17 @@ "version": "2.0.0", "bundled": true }, + "promzard": { + "version": "0.3.0", + "bundled": true, + "requires": { + "read": "1.0.7" + } + }, + "proto-list": { + "version": "1.2.4", + "bundled": true + }, "proxy-agent": { "version": "3.0.0", "bundled": true, @@ -3107,10 +3698,18 @@ "version": "1.0.2", "bundled": true }, + "punycode": { + "version": "1.4.1", + "bundled": true + }, "q": { "version": "1.5.1", "bundled": true }, + "qs": { + "version": "6.2.3", + "bundled": true + }, "raw-body": { "version": "2.3.3", "bundled": true, @@ -3121,6 +3720,37 @@ "unpipe": "1.0.0" } }, + "read": { + "version": "1.0.7", + "bundled": true, + "requires": { + "mute-stream": "0.0.7" + } + }, + "read-installed": { + "version": "4.0.3", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "graceful-fs": "4.1.11", + "read-package-json": "2.0.13", + "readdir-scoped-modules": "1.0.2", + "semver": "5.5.0", + "slide": "1.1.6", + "util-extend": "1.0.3" + } + }, + "read-package-json": { + "version": "2.0.13", + "bundled": true, + "requires": { + "glob": "7.1.2", + "graceful-fs": "4.1.11", + "json-parse-better-errors": "1.0.2", + "normalize-package-data": "2.4.0", + "slash": "1.0.0" + } + }, "read-pkg": { "version": "1.1.0", "bundled": true, @@ -3151,6 +3781,24 @@ "util-deprecate": "1.0.2" } }, + "readdir-scoped-modules": { + "version": "1.0.2", + "bundled": true, + "requires": { + "debuglog": "1.0.1", + "dezalgo": "1.0.3", + "graceful-fs": "4.1.11", + "once": "1.4.0" + } + }, + "realize-package-specifier": { + "version": "3.0.3", + "bundled": true, + "requires": { + "dezalgo": "1.0.3", + "npm-package-arg": "4.1.1" + } + }, "redent": { "version": "1.0.0", "bundled": true, @@ -3170,6 +3818,66 @@ "is-finite": "1.0.2" } }, + "request": { + "version": "2.74.0", + "bundled": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.7.0", + "bl": "1.1.2", + "caseless": "0.11.0", + "combined-stream": "1.0.6", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "1.0.1", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.18", + "node-uuid": "1.4.8", + "oauth-sign": "0.8.2", + "qs": "6.2.3", + "stringstream": "0.0.6", + "tough-cookie": "2.3.4", + "tunnel-agent": "0.4.3" + }, + "dependencies": { + "bl": { + "version": "1.1.2", + "bundled": true, + "requires": { + "readable-stream": "2.0.6" + } + }, + "node-uuid": { + "version": "1.4.8", + "bundled": true + }, + "process-nextick-args": { + "version": "1.0.7", + "bundled": true + }, + "readable-stream": { + "version": "2.0.6", + "bundled": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "0.10.31", + "util-deprecate": "1.0.2" + } + }, + "string_decoder": { + "version": "0.10.31", + "bundled": true + } + } + }, "require-uncached": { "version": "1.0.3", "bundled": true, @@ -3194,6 +3902,10 @@ "signal-exit": "3.0.2" } }, + "retry": { + "version": "0.10.1", + "bundled": true + }, "rimraf": { "version": "2.6.2", "bundled": true, @@ -3239,6 +3951,14 @@ "version": "1.1.0", "bundled": true }, + "sha": { + "version": "2.0.1", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "readable-stream": "2.3.6" + } + }, "shebang-command": { "version": "1.2.0", "bundled": true, @@ -3254,6 +3974,10 @@ "version": "3.0.2", "bundled": true }, + "slash": { + "version": "1.0.0", + "bundled": true + }, "slice-ansi": { "version": "1.0.0", "bundled": true, @@ -3261,10 +3985,21 @@ "is-fullwidth-code-point": "2.0.0" } }, + "slide": { + "version": "1.1.6", + "bundled": true + }, "smart-buffer": { "version": "1.1.15", "bundled": true }, + "sntp": { + "version": "1.0.9", + "bundled": true, + "requires": { + "hoek": "2.16.3" + } + }, "socks": { "version": "1.1.10", "bundled": true, @@ -3281,6 +4016,10 @@ "socks": "1.1.10" } }, + "sorted-object": { + "version": "2.0.1", + "bundled": true + }, "source-map": { "version": "0.6.1", "bundled": true, @@ -3314,6 +4053,27 @@ "version": "1.0.3", "bundled": true }, + "sshpk": { + "version": "1.14.2", + "bundled": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.2", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "safer-buffer": "2.1.2", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, "statuses": { "version": "1.5.0", "bundled": true @@ -3333,6 +4093,10 @@ "safe-buffer": "5.1.2" } }, + "stringstream": { + "version": "0.0.6", + "bundled": true + }, "strip-ansi": { "version": "4.0.0", "bundled": true, @@ -3380,6 +4144,15 @@ "string-width": "2.1.1" } }, + "tar": { + "version": "2.2.1", + "bundled": true, + "requires": { + "block-stream": "0.0.9", + "fstream": "1.0.11", + "inherits": "2.0.3" + } + }, "tar-stream": { "version": "1.1.5", "bundled": true, @@ -3436,10 +4209,26 @@ "os-tmpdir": "1.0.2" } }, + "tough-cookie": { + "version": "2.3.4", + "bundled": true, + "requires": { + "punycode": "1.4.1" + } + }, "trim-newlines": { "version": "1.0.0", "bundled": true }, + "tunnel-agent": { + "version": "0.4.3", + "bundled": true + }, + "tweetnacl": { + "version": "0.14.5", + "bundled": true, + "optional": true + }, "type-check": { "version": "0.3.2", "bundled": true, @@ -3451,6 +4240,14 @@ "version": "0.0.6", "bundled": true }, + "uid-number": { + "version": "0.0.6", + "bundled": true + }, + "umask": { + "version": "1.1.0", + "bundled": true + }, "underscore.string": { "version": "3.3.4", "bundled": true, @@ -3467,6 +4264,10 @@ "version": "1.0.2", "bundled": true }, + "util-extend": { + "version": "1.0.3", + "bundled": true + }, "uuid": { "version": "3.3.2", "bundled": true @@ -3479,6 +4280,41 @@ "spdx-expression-parse": "3.0.0" } }, + "validate-npm-package-name": { + "version": "2.2.2", + "bundled": true, + "requires": { + "builtins": "0.0.7" + }, + "dependencies": { + "builtins": { + "version": "0.0.7", + "bundled": true + } + } + }, + "verror": { + "version": "1.10.0", + "bundled": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "bundled": true + } + } + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "1.0.3" + } + }, "which": { "version": "1.3.1", "bundled": true, @@ -3501,6 +4337,15 @@ "mkdirp": "0.5.1" } }, + "write-file-atomic": { + "version": "1.1.4", + "bundled": true, + "requires": { + "graceful-fs": "4.1.11", + "imurmurhash": "0.1.4", + "slide": "1.1.6" + } + }, "xml2js": { "version": "0.4.15", "bundled": true, From ab49094fd3002a7ef83a1d99fbb0c42c8434c22f Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Tue, 17 Jul 2018 17:47:47 -0700 Subject: [PATCH 032/587] Adding serverless template for function plugin --- .../service-walkthroughs/apigw-walkthrough.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index 720358cf5c..0e27e14379 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -161,7 +161,7 @@ async function askPaths(context) { let path = { name: answer.name }; let lambda; do { - lambda = await askLambdaSource(context, answer.functionType); + lambda = await askLambdaSource(context, answer.functionType, answer.name); } while (!lambda); path = { ...path, ...lambda }; paths.push(path); @@ -208,22 +208,26 @@ function functionsExist(context) { return true; } -async function askLambdaSource(context, functionType) { +async function askLambdaSource(context, functionType, path) { switch (functionType) { case 'arn': return askLambdaArn(context); case 'projectFunction': return askLambdaFromProject(context); - case 'newFunction': return newLambdaFunction(context); + case 'newFunction': return newLambdaFunction(context, path); default: throw new Error('Type not supported'); } } -function newLambdaFunction(context) { +function newLambdaFunction(context, path) { let add; try { ({ add } = require('amplify-category-function')); } catch (e) { throw new Error('Function plugin not installed in the CLI. Please install it to use this feature'); } + context.api = { + path, + functionTemplate: "serverless" + } return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda function locally'); From 798c9331aced7a9b6d27331586a82e31391265a2 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Wed, 25 Jul 2018 09:37:42 -0700 Subject: [PATCH 033/587] Adding apiName on cft output (#65) --- .../apigw-cloudformation-template-default.json.ejs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 40e2d4bea9..cc74e0cbee 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -402,6 +402,10 @@ "RootUrl": { "Description": "Root URL of the API gateway", "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/Prod"]]} + }, + "ApiName": { + "Description": "Api Friendly name", + "Value": "<%= props.resourceName %>" } } } \ No newline at end of file From 5b8749a3c5fbfe677bc4b5238797b3a1e2154431 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 24 Jul 2018 18:55:53 -0700 Subject: [PATCH 034/587] Add help sections after command executions indicating what to do next --- packages/amplify-category-api/commands/api/add.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index a227510112..66e77db903 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -24,7 +24,14 @@ module.exports = { return providerController.addResource(context, category, result.service, options); }) - .then(() => context.print.success('Successfully added resource')) + .then((resourceName) => { + const {print} = context; + print.success(`Successfully added resource ${resourceName} locally`); + print.info(''); + print.success('Some next steps:'); + print.info(`"amplify publish" will build all your local resources and provision everything configured in the cloud`); + print.info(''); + }) .catch((err) => { context.print.info(err.stack); context.print.error('There was an error adding the API resource'); From 793b933949051069e2ae22b92db4c036e2282074 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 24 Jul 2018 19:02:01 -0700 Subject: [PATCH 035/587] Fix linting issues --- packages/amplify-category-api/commands/api/add.js | 6 +++--- .../service-walkthroughs/apigw-walkthrough.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 66e77db903..556b35ea6e 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -24,12 +24,12 @@ module.exports = { return providerController.addResource(context, category, result.service, options); }) - .then((resourceName) => { - const {print} = context; + .then((resourceName) => { + const { print } = context; print.success(`Successfully added resource ${resourceName} locally`); print.info(''); print.success('Some next steps:'); - print.info(`"amplify publish" will build all your local resources and provision everything configured in the cloud`); + print.info('"amplify publish" will build all your local resources and provision everything configured in the cloud'); print.info(''); }) .catch((err) => { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index 0e27e14379..b8b21ea85d 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -226,8 +226,8 @@ function newLambdaFunction(context, path) { } context.api = { path, - functionTemplate: "serverless" - } + functionTemplate: 'serverless', + }; return add(context, 'amplify-provider-awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda function locally'); From 73972a7a321f256397d1e174735f980e6242f7ce Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 25 Jul 2018 13:54:47 -0700 Subject: [PATCH 036/587] Fix some help messages --- packages/amplify-category-api/commands/api/add.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 556b35ea6e..28912af8dd 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -29,7 +29,8 @@ module.exports = { print.success(`Successfully added resource ${resourceName} locally`); print.info(''); print.success('Some next steps:'); - print.info('"amplify publish" will build all your local resources and provision everything configured in the cloud'); + print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); + print.info('"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud'); print.info(''); }) .catch((err) => { From 715e1ebd3e2c367f9c6aa52a6b9af13f62556576 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Fri, 27 Jul 2018 14:46:58 -0700 Subject: [PATCH 037/587] Adding auth flow for api plugin --- .../service-walkthroughs/apigw-walkthrough.js | 92 +++++++++++++------ 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index b8b21ea85d..136e4b1bda 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -79,34 +79,53 @@ async function askApiNames(context, defaults) { return answer; } -async function askPrivacy() { - const answer = await inquirer.prompt({ - name: 'privacy', - type: 'list', - message: 'Which kind of privacy your API should have?', - choices: [ - { - name: 'Open (No security)', - value: 'open', - }, - { - name: 'Protected (AWS_IAM restricted to guest and sign-in users)', - value: 'protected', - }, - { - name: 'Private (AWS_IAM restricted to sign-in users only)', - value: 'private', - }, - ], - }); - - const privacy = {}; - privacy[answer.privacy] = true; - const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); - privacy.unAuthRoleName = roles.unAuthRoleName; - privacy.authRoleName = roles.authRoleName; +async function askPrivacy(context) { + while (true) { + const answer = await inquirer.prompt({ + name: 'privacy', + type: 'list', + message: 'Which kind of privacy your API should have?', + choices: [ + { + name: 'Open (No security)', + value: 'open', + }, + { + name: 'Authenticated - AWS IAM (Signature Version 4 signing)', + value: 'private', + }, + { + name: 'Authenticated and Guest users (AWS_IAM with Cognito Identity)', + value: 'protected', + }, + ], + }); - return privacy; + const privacy = {}; + privacy[answer.privacy] = true; + const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + privacy.unAuthRoleName = roles.unAuthRoleName; + privacy.authRoleName = roles.authRoleName; + + if (answer.privacy === 'open') { return privacy; } + + if (!checkIfAuthExists(context)) { + if (await context.prompt.confirm('You need auth (Cognito) added to your project for adding storage for user files. Do you want to add auth now?')) { + try { + const { add } = require('amplify-category-auth'); + context.api = { + privacy: answer.privacy + } + await add(context); + return privacy; + } catch (e) { + context.print.error('Auth plugin not installed in the CLI. Please install it to use this feature'); + } + } + } else { + return privacy; + } + } } async function askPaths(context) { @@ -294,4 +313,23 @@ async function askLambdaArn(context) { return { lambdaArn: lambdaCloudOptionAnswer.lambdaChoice.Arn, lambdaFunction: lambdaCloudOptionAnswer.lambdaChoice.FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; } +function checkIfAuthExists(context) { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); + let authExists = false; + const authServiceName = 'Cognito'; + const authCategory = 'auth'; + + if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { + const categoryResources = amplifyMeta[authCategory]; + Object.keys(categoryResources).forEach((resource) => { + if (categoryResources[resource].service === authServiceName) { + authExists = true; + } + }); + } + return authExists; +} + + module.exports = { serviceWalkthrough }; From 50d6bf840592d57e8b2323d1913851038e927ecc Mon Sep 17 00:00:00 2001 From: elorzafe Date: Fri, 27 Jul 2018 14:59:42 -0700 Subject: [PATCH 038/587] Fix get object from dynamo function (#76) * Fix get object from dynamo function * Adding auth flow for api plugin --- .../service-walkthroughs/apigw-walkthrough.js | 92 +++++++++++++------ 1 file changed, 65 insertions(+), 27 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index b8b21ea85d..136e4b1bda 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -79,34 +79,53 @@ async function askApiNames(context, defaults) { return answer; } -async function askPrivacy() { - const answer = await inquirer.prompt({ - name: 'privacy', - type: 'list', - message: 'Which kind of privacy your API should have?', - choices: [ - { - name: 'Open (No security)', - value: 'open', - }, - { - name: 'Protected (AWS_IAM restricted to guest and sign-in users)', - value: 'protected', - }, - { - name: 'Private (AWS_IAM restricted to sign-in users only)', - value: 'private', - }, - ], - }); - - const privacy = {}; - privacy[answer.privacy] = true; - const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); - privacy.unAuthRoleName = roles.unAuthRoleName; - privacy.authRoleName = roles.authRoleName; +async function askPrivacy(context) { + while (true) { + const answer = await inquirer.prompt({ + name: 'privacy', + type: 'list', + message: 'Which kind of privacy your API should have?', + choices: [ + { + name: 'Open (No security)', + value: 'open', + }, + { + name: 'Authenticated - AWS IAM (Signature Version 4 signing)', + value: 'private', + }, + { + name: 'Authenticated and Guest users (AWS_IAM with Cognito Identity)', + value: 'protected', + }, + ], + }); - return privacy; + const privacy = {}; + privacy[answer.privacy] = true; + const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + privacy.unAuthRoleName = roles.unAuthRoleName; + privacy.authRoleName = roles.authRoleName; + + if (answer.privacy === 'open') { return privacy; } + + if (!checkIfAuthExists(context)) { + if (await context.prompt.confirm('You need auth (Cognito) added to your project for adding storage for user files. Do you want to add auth now?')) { + try { + const { add } = require('amplify-category-auth'); + context.api = { + privacy: answer.privacy + } + await add(context); + return privacy; + } catch (e) { + context.print.error('Auth plugin not installed in the CLI. Please install it to use this feature'); + } + } + } else { + return privacy; + } + } } async function askPaths(context) { @@ -294,4 +313,23 @@ async function askLambdaArn(context) { return { lambdaArn: lambdaCloudOptionAnswer.lambdaChoice.Arn, lambdaFunction: lambdaCloudOptionAnswer.lambdaChoice.FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; } +function checkIfAuthExists(context) { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); + let authExists = false; + const authServiceName = 'Cognito'; + const authCategory = 'auth'; + + if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { + const categoryResources = amplifyMeta[authCategory]; + Object.keys(categoryResources).forEach((resource) => { + if (categoryResources[resource].service === authServiceName) { + authExists = true; + } + }); + } + return authExists; +} + + module.exports = { serviceWalkthrough }; From 1b47df4f209660e2574c13264c53beee45af983e Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Fri, 27 Jul 2018 16:48:01 -0700 Subject: [PATCH 039/587] Updating package.json on api pluggin --- packages/amplify-category-api/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e6e7844063..01fab8089d 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -9,8 +9,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-storage": "^0.1.0", + "amplify-category-auth": "^0.1.0", "amplify-category-function": "^0.1.0", + "amplify-category-storage": "^0.1.0", "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", From c18f6040b9498ffa4bbd80e64f8a97d2724bf518 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Fri, 27 Jul 2018 16:48:01 -0700 Subject: [PATCH 040/587] Updating package.json on api pluggin --- packages/amplify-category-api/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e6e7844063..01fab8089d 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -9,8 +9,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-storage": "^0.1.0", + "amplify-category-auth": "^0.1.0", "amplify-category-function": "^0.1.0", + "amplify-category-storage": "^0.1.0", "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", From 9776d12f8346b47628d53b4813b2cf026a8f7486 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Fri, 27 Jul 2018 16:55:05 -0700 Subject: [PATCH 041/587] Auth dependency on api plugin (#79) * Updating package.json on api pluggin --- packages/amplify-category-api/package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e6e7844063..01fab8089d 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -9,8 +9,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-storage": "^0.1.0", + "amplify-category-auth": "^0.1.0", "amplify-category-function": "^0.1.0", + "amplify-category-storage": "^0.1.0", "eslint": "^4.9.0", "inquirer": "^3.2.1", "moment": "^2.22.2", From 447e294df1c6acce46a15851941cf40486323378 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 30 Jul 2018 17:41:59 -0700 Subject: [PATCH 042/587] trim amplify-provider-awscloudformation to awscloudformation --- ...pigw-cloudformation-template-default.json.ejs | 0 ...ppSync-cloudformation-template-custom.yml.ejs | 0 ...pSync-cloudformation-template-default.yml.ejs | 0 .../default-values/apigw-defaults.js | 0 .../default-values/appSync-defaults.js | 2 +- .../index.js | 0 .../service-walkthroughs/apigw-walkthrough.js | 12 ++++++------ .../service-walkthroughs/appSync-walkthrough.js | 16 ++++++++-------- .../provider-utils/supported-services.json | 4 ++-- 9 files changed, 17 insertions(+), 17 deletions(-) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/cloudformation-templates/apigw-cloudformation-template-default.json.ejs (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/default-values/apigw-defaults.js (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/default-values/appSync-defaults.js (83%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/index.js (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/service-walkthroughs/apigw-walkthrough.js (95%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/service-walkthroughs/appSync-walkthrough.js (95%) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs rename to packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs rename to packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs rename to packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/apigw-defaults.js rename to packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js similarity index 83% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js rename to packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js index a0ed9b48fe..7c31ecbfb2 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js @@ -2,7 +2,7 @@ const uuid = require('uuid'); const getAllDefaults = (project) => { const name = project.projectConfig.projectName.toLowerCase(); - const region = project.amplifyMeta.providers['amplify-provider-awscloudformation'].Region; + const region = project.amplifyMeta.providers['awscloudformation'].Region; const [shortId] = uuid().split('-'); const defaults = { resourceName: `appsync${shortId}`, diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/index.js rename to packages/amplify-category-api/provider-utils/awscloudformation/index.js diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js similarity index 95% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js rename to packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index b8b21ea85d..aa293093ab 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -21,11 +21,11 @@ async function serviceWalkthrough(context, defaultValuesFilename) { if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && context.amplify.getProjectDetails().amplifyMeta.providers && - context.amplify.getProjectDetails().amplifyMeta.providers['amplify-provider-awscloudformation'] + context.amplify.getProjectDetails().amplifyMeta.providers['awscloudformation'] ) { // TODO: read from utility functions (Dustin PR) const { amplifyMeta } = context.amplify.getProjectDetails(); - const providerInfo = amplifyMeta.providers['amplify-provider-awscloudformation']; + const providerInfo = amplifyMeta.providers['awscloudformation']; answers.privacy.authRoleName = providerInfo.AuthRoleName; answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; @@ -102,7 +102,7 @@ async function askPrivacy() { const privacy = {}; privacy[answer.privacy] = true; - const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'awscloudformation', 'staticRoles'); privacy.unAuthRoleName = roles.unAuthRoleName; privacy.authRoleName = roles.authRoleName; @@ -228,7 +228,7 @@ function newLambdaFunction(context, path) { path, functionTemplate: 'serverless', }; - return add(context, 'amplify-provider-awscloudformation', 'Lambda') + return add(context, 'awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda function locally'); return { lambdaFunction: resourceName }; @@ -255,7 +255,7 @@ async function askLambdaFromProject(context) { } async function askLambdaArn(context) { - const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { type: 'list', @@ -266,7 +266,7 @@ async function askLambdaArn(context) { const regionAnswer = await inquirer.prompt([regionQuestion]); - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ value: { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js similarity index 95% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js rename to packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 0d7149f1a8..a8296cbaca 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -111,7 +111,7 @@ async function askSecurityQuestions(context, inputs) { async function askCognitoQuestions(context, inputs) { const { amplify } = context; - const regions = await amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + const regions = await amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { type: inputs[4].type, @@ -122,7 +122,7 @@ async function askCognitoQuestions(context, inputs) { const regionAnswer = await inquirer.prompt([regionQuestion]); - const userPools = await amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getUserPools', { region: regionAnswer[inputs[4].key] }); + const userPools = await amplify.executeProviderUtils(context, 'awscloudformation', 'getUserPools', { region: regionAnswer[inputs[4].key] }); const userPoolOptions = userPools.map(userPool => ({ value: userPool.Id, @@ -323,14 +323,14 @@ async function askDynamoDBQuestions(context, inputs) { context.print.error('Storage plugin not installed in the CLI. Please install it to use this feature'); break; } - return add(context, 'amplify-provider-awscloudformation', 'DynamoDB') + return add(context, 'awscloudformation', 'DynamoDB') .then((resourceName) => { context.print.success('Succesfully added DynamoDb table locally'); return { resourceName }; }); } case 'cloudResource': { - const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { type: inputs[4].type, @@ -341,7 +341,7 @@ async function askDynamoDBQuestions(context, inputs) { const regionAnswer = await inquirer.prompt([regionQuestion]); - const dynamodbTables = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getDynamoDBTables', { region: regionAnswer[inputs[4].key] }); + const dynamodbTables = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getDynamoDBTables', { region: regionAnswer[inputs[4].key] }); const dynamodbOptions = dynamodbTables.map(dynamodbTable => ({ value: { @@ -414,14 +414,14 @@ async function askLambdaQuestions(context, inputs) { context.print.error('Function plugin not installed in the CLI. Please install it to use this feature'); break; } - return add(context, 'amplify-provider-awscloudformation', 'Lambda') + return add(context, 'awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda function locally'); return { resourceName }; }); } case 'cloudResource': { - const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { type: inputs[4].type, @@ -432,7 +432,7 @@ async function askLambdaQuestions(context, inputs) { const regionAnswer = await inquirer.prompt([regionQuestion]); - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer[inputs[4].key] }); + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions', { region: regionAnswer[inputs[4].key] }); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ value: { diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 643f3865d5..3c6ac59cfc 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -217,7 +217,7 @@ "defaultValuesFilename": "appSync-defaults.js", "serviceWalkthroughFilename": "appSync-walkthrough.js", "cfnFilename": "appSync-cloudformation-template-default.yml.ejs", - "provider": "amplify-provider-awscloudformation" + "provider": "awscloudformation" }, "API Gateway": { "inputs": [ @@ -243,6 +243,6 @@ "defaultValuesFilename": "apigw-defaults.js", "serviceWalkthroughFilename": "apigw-walkthrough.js", "cfnFilename": "apigw-cloudformation-template-default.json.ejs", - "provider": "amplify-provider-awscloudformation" + "provider": "awscloudformation" } } \ No newline at end of file From 51c99fbbcf2ca95c213b2a6f6555675799e738c9 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 30 Jul 2018 20:39:33 -0700 Subject: [PATCH 043/587] Fix issues with native config files --- .../service-walkthroughs/apigw-walkthrough.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index 136e4b1bda..e6e39e9cde 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -114,8 +114,8 @@ async function askPrivacy(context) { try { const { add } = require('amplify-category-auth'); context.api = { - privacy: answer.privacy - } + privacy: answer.privacy, + }; await add(context); return privacy; } catch (e) { From d7d3ce76fb9f46224aa1ad0b8d2417ad276c410c Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 31 Jul 2018 13:58:50 -0700 Subject: [PATCH 044/587] insert console commands stubs --- packages/amplify-category-api/commands/api/console.js | 9 +++++++++ packages/amplify-category-api/index.js | 9 +++++++++ 2 files changed, 18 insertions(+) create mode 100644 packages/amplify-category-api/commands/api/console.js create mode 100644 packages/amplify-category-api/index.js diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js new file mode 100644 index 0000000000..04392f5cbe --- /dev/null +++ b/packages/amplify-category-api/commands/api/console.js @@ -0,0 +1,9 @@ +const subcommand = 'console'; +const category = 'api'; + +module.exports = { + name: subcommand, + run: async (context) => { + context.print.info('to be implemented: ' + category + ' ' + subcommand); + }, +}; diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js new file mode 100644 index 0000000000..02921cef48 --- /dev/null +++ b/packages/amplify-category-api/index.js @@ -0,0 +1,9 @@ +const category = 'api'; + +async function console(context) { + context.print.info('to be implemented: ' + category + ' console'); +} + +module.exports = { + console +}; From 89e3cbd367ce222efec2c190e99f0bd9634d9a92 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 31 Jul 2018 16:05:39 -0700 Subject: [PATCH 045/587] rename --- .../service-walkthroughs/apigw-walkthrough.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index f448facc64..9ff381f064 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -21,11 +21,11 @@ async function serviceWalkthrough(context, defaultValuesFilename) { if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && context.amplify.getProjectDetails().amplifyMeta.providers && - context.amplify.getProjectDetails().amplifyMeta.providers['amplify-provider-awscloudformation'] + context.amplify.getProjectDetails().amplifyMeta.providers['awscloudformation'] ) { // TODO: read from utility functions (Dustin PR) const { amplifyMeta } = context.amplify.getProjectDetails(); - const providerInfo = amplifyMeta.providers['amplify-provider-awscloudformation']; + const providerInfo = amplifyMeta.providers['awscloudformation']; answers.privacy.authRoleName = providerInfo.AuthRoleName; answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; @@ -103,7 +103,7 @@ async function askPrivacy(context) { const privacy = {}; privacy[answer.privacy] = true; - const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'staticRoles'); + const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'awscloudformation', 'staticRoles'); privacy.unAuthRoleName = roles.unAuthRoleName; privacy.authRoleName = roles.authRoleName; @@ -247,7 +247,7 @@ function newLambdaFunction(context, path) { path, functionTemplate: 'serverless', }; - return add(context, 'amplify-provider-awscloudformation', 'Lambda') + return add(context, 'awscloudformation', 'Lambda') .then((resourceName) => { context.print.success('Succesfully added Lambda function locally'); return { lambdaFunction: resourceName }; @@ -274,7 +274,7 @@ async function askLambdaFromProject(context) { } async function askLambdaArn(context) { - const regions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getRegions'); + const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { type: 'list', @@ -285,7 +285,7 @@ async function askLambdaArn(context) { const regionAnswer = await inquirer.prompt([regionQuestion]); - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'amplify-provider-awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ value: { From 8dc25380cc3264a4a396681a24b950409debe900 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Tue, 31 Jul 2018 16:29:40 -0700 Subject: [PATCH 046/587] CRUD API support for tables already deployed --- .../service-walkthroughs/apigw-walkthrough.js | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js index e6e39e9cde..a1b6c3eeff 100644 --- a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -52,30 +52,10 @@ async function askApiNames(context, defaults) { required: true, }), }, - { - name: 'apiName', - type: 'input', - message: 'Please provide an API name', - default: defaults.apiName, - validate(value) { - const pass = value.length > 0; - - // TODO: check names with existing apis - // let yamlDef = cloudLogicDefinition.projectDefinition.yamlDefinition; - - // // Check if API already exists - // if (yamlDef.features.cloudlogic && yamlDef.features.cloudlogic.components && - // yamlDef.features.cloudlogic.components[value]) { - // return 'API ' + value + ' already exists'; - // } - if (pass) { - return true; - } - return 'Please enter a valid API name'; - }, - }, ]); + answer.apiName = defaults.apiName; + return answer; } From 46eeaaa33c83833efad8ae6e73bee5904dfe17fe Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 1 Aug 2018 16:59:18 -0700 Subject: [PATCH 047/587] Support subcommands for windows --- packages/amplify-category-api/commands/api.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index d662679751..574f41bf2e 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -3,6 +3,14 @@ const featureName = 'api'; module.exports = { name: featureName, run: async (context) => { + if(/^win/.test(process.platform)) { + try { + const {run} = require(`./${featureName}/${context.parameters.first}`); + return run(context); + } catch(e) { + context.print.error('Command not found'); + } + } const header = `amplify ${featureName} `; const commands = [ { From d407d7db529f1b3c9d38d3ed402645a9e5eef571 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 3 Aug 2018 21:54:59 -0700 Subject: [PATCH 048/587] Transformer integration with appsync feature --- .../amplify-category-api/commands/api/add.js | 16 + packages/amplify-category-api/package.json | 8 + .../many-relationship-schema.graphql | 4 + .../single-relationship-schema.graphql | 4 + .../default-values/appSync-defaults.js | 1 + .../provider-utils/awscloudformation/index.js | 8 +- .../appSync-walkthrough.js | 514 +++++------------- .../provider-utils/supported-services.json | 200 ++----- 8 files changed, 204 insertions(+), 551 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql create mode 100644 packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 28912af8dd..98178cb544 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -9,6 +9,22 @@ let options; module.exports = { name: subcommand, run: async (context) => { + + + /*const transformer = new GraphQLTransform({ + transformers: [ + new AppSyncTransformer('/Users/kaustavg/my-app'), + new AppSyncDynamoDBTransformer(), + new AppSyncAuthTransformer(), + + ] + }); + const cfdoc = transformer.transform(fs.readFileSync('/Users/kaustavg/my-app/schematransform.graphql', 'utf8')); + console.log(cfdoc); + + + return;*/ + const { amplify } = context; return amplify.serviceSelectionPrompt(context, category, servicesMetadata) .then((result) => { diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 01fab8089d..21577c37b7 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -12,9 +12,17 @@ "amplify-category-auth": "^0.1.0", "amplify-category-function": "^0.1.0", "amplify-category-storage": "^0.1.0", + "graphql-transform": "1.0", + "graphql-dynamodb-transformer": "1.0", + "graphql-elasticsearch-transformer": "1.0", + "graphql-auth-transformer": "1.0", + "graphql-transformer-common": "1.0", + "graphql-appsync-transformer": "1.0", "eslint": "^4.9.0", + "fs-extra": "^6.0.1", "inquirer": "^3.2.1", "moment": "^2.22.2", + "open-in-editor": "^2.2.0", "uuid": "^2.0.3" }, "devDependencies": { diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql new file mode 100644 index 0000000000..829ce71bff --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql @@ -0,0 +1,4 @@ +type Post @model { + id: ID! + title: String! +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql new file mode 100644 index 0000000000..829ce71bff --- /dev/null +++ b/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql @@ -0,0 +1,4 @@ +type Post @model { + id: ID! + title: String! +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js index 7c31ecbfb2..e48476dcd4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js @@ -9,6 +9,7 @@ const getAllDefaults = (project) => { apiName: `${name}${shortId}`, serviceRoleName: `serviceRole${shortId}`, servicePolicyName: `servicePolicy${shortId}`, + apiCreationChoice: false, region, defaultTableName: `Posts${shortId}`, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index a95fcf9980..1973c7f266 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -44,10 +44,12 @@ function addResource(context, category, service, options) { if (result.output) { options.output = result.output; } - if (answers.customCfnFile) { - cfnFilename = answers.customCfnFile; + if(!result.noCfnFile) { + if (answers.customCfnFile) { + cfnFilename = answers.customCfnFile; + } + copyCfnTemplate(context, category, answers, cfnFilename); } - copyCfnTemplate(context, category, answers, cfnFilename); context.amplify.updateamplifyMetaAfterResourceAdd( category, answers.resourceName, diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index a8296cbaca..8593cef68b 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,5 +1,16 @@ const inquirer = require('inquirer'); const moment = require('moment'); +const fs = require('fs-extra'); +const path = require('path'); +const openInEditor = require('open-in-editor'); +const GraphQLTransform = require('graphql-transform').default; +const AppSyncDynamoDBTransformer = require('graphql-dynamodb-transformer').default; +const AppSyncAuthTransformer = require('graphql-auth-transformer').default; +const AppSyncTransformer = require('graphql-appsync-transformer').default; +const category = 'api'; +const parametersFileName = 'parameters.json'; +const templateFileName = 'cloudformation-template.json'; +const schemaFileName = 'schema.graphql'; const securityTypeMapping = { apiKey: 'API_KEY', @@ -22,7 +33,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat message: inputs[0].question, validate: amplify.inputValidation(inputs[0]), default: () => { - const defaultValue = getAllDefaults(amplify.getProjectDetails())[inputs[0].key]; + const defaultValue = allDefaultValues[inputs[0].key]; return defaultValue; }, }, @@ -37,8 +48,11 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat type: inputs[2].type, name: inputs[2].key, message: inputs[2].question, - choices: inputs[2].options, validate: amplify.inputValidation(inputs[2]), + default: () => { + const defaultValue = allDefaultValues[inputs[2].key]; + return defaultValue; + }, }, ]; @@ -47,420 +61,140 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const resourceAnswers = await inquirer.prompt(resourceQuestions); Object.assign(allDefaultValues, resourceAnswers); - if (resourceAnswers[inputs[2].key] === 'default') { - return { answers: allDefaultValues, output: { securityType: 'AWS_IAM' } }; - } + const backendDir = amplify.pathManager.getBackendDirPath(); - return askCustomQuestions(context, inputs) - .then((result) => { - Object.assign(allDefaultValues, result.answers); - allDefaultValues.customCfnFile = 'appSync-cloudformation-template-custom.yml.ejs'; - return { answers: allDefaultValues, dependsOn: result.dependsOn, output: result.output }; - }); -} + const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; + const buildDir = `${resourceDir}/build`; -async function askCustomQuestions(context, inputs) { - const answers = {}; - let dependsOn = []; + fs.ensureDirSync(buildDir); - const securitySetting = await askSecurityQuestions(context, inputs); - const output = { - securityType: securityTypeMapping[securitySetting.type], - }; - Object.assign(answers, { securitySetting }); - - if (await context.prompt.confirm('Do you want to add a data source to your AppSync API?')) { - const dataSourceAnswers = await askDataSourceQuestions(context, inputs); - const { dataSources } = dataSourceAnswers; - ({ dependsOn } = dataSourceAnswers); - Object.assign(answers, { dataSources }); - Object.assign(answers, { dependsOn }); - } - return { answers, dependsOn, output }; -} + const parametersFilePath = path.join(resourceDir, parametersFileName); -async function askSecurityQuestions(context, inputs) { - const securityTypeQuestion = { - type: inputs[3].type, - name: inputs[3].key, - message: inputs[3].question, - choices: inputs[3].options, + const parameters = { + AppSyncApiName: resourceAnswers[inputs[1].key] }; - const securitySetting = {}; - while (!securitySetting.options) { - const securityTypeAnswer = await inquirer.prompt([securityTypeQuestion]); - securitySetting.type = securityTypeAnswer[inputs[3].key]; - - switch (securityTypeAnswer[inputs[3].key]) { - case 'cognito': securitySetting.options = await askCognitoQuestions(context, inputs); - break; - case 'openId': securitySetting.options = await askOpenIdQuestions(context, inputs); - break; - case 'apiKey': securitySetting.options = await askApiKeyQuestions(context, inputs); - break; - case 'iam': securitySetting.options = {}; - break; - default: context.print.error('Invalid option'); - } - } - - return securitySetting; -} - -async function askCognitoQuestions(context, inputs) { - const { amplify } = context; - - const regions = await amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); + const jsonString = JSON.stringify(parameters, null, 4); - const regionQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: regions, - }; + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); - const regionAnswer = await inquirer.prompt([regionQuestion]); + if (resourceAnswers[inputs[2].key]) { + console.log('Yes I have a file'); + const filePathQuestion = { + type: inputs[3].type, + name: inputs[3].key, + message: inputs[3].question, + validate: amplify.inputValidation(inputs[3]) + }; + const { schemaFilePath } = await inquirer.prompt(filePathQuestion); - const userPools = await amplify.executeProviderUtils(context, 'awscloudformation', 'getUserPools', { region: regionAnswer[inputs[4].key] }); + fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); - const userPoolOptions = userPools.map(userPool => ({ - value: userPool.Id, - name: `${userPool.Id} (${userPool.Name})`, - })); + // Transformer compiler code - if (userPoolOptions.length === 0) { - context.print.error('You do not have any user pools configured for the selected region'); - return; - } - - const userPoolIdQuestion = { - type: inputs[5].type, - name: inputs[5].key, - message: inputs[5].question, - choices: userPoolOptions, - }; - - const defaultActionQuestion = { - type: inputs[6].type, - name: inputs[6].key, - message: inputs[6].question, - choices: inputs[6].options, - validate: amplify.inputValidation(inputs[6]), - }; - - const appIdClientRegexQuestion = { - type: inputs[7].type, - name: inputs[7].key, - message: inputs[7].question, - validate: amplify.inputValidation(inputs[7]), - }; - - const cognitoAnswers = await inquirer.prompt([userPoolIdQuestion, - defaultActionQuestion, - appIdClientRegexQuestion]); - Object.assign(cognitoAnswers, regionAnswer); - - return cognitoAnswers; -} - -async function askOpenIdQuestions(context, inputs) { - const { amplify } = context; - - const openIdDomainQuestion = { - type: inputs[8].type, - name: inputs[8].key, - message: inputs[8].question, - validate: amplify.inputValidation(inputs[8]), - }; - - const clientIdQuestion = { - type: inputs[9].type, - name: inputs[9].key, - message: inputs[9].question, - validate: amplify.inputValidation(inputs[9]), - }; - - const issueTTLQuestion = { - type: inputs[10].type, - name: inputs[10].key, - message: inputs[10].question, - validate: amplify.inputValidation(inputs[10]), - default: 0, - }; + const transformer = new GraphQLTransform({ + transformers: [ + new AppSyncTransformer(buildDir), + new AppSyncDynamoDBTransformer(), + new AppSyncAuthTransformer(), + ] + }); + + const cfdoc = transformer.transform(fs.readFileSync(schemaFilePath, 'utf8')); + fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); - const authTTLQuestion = { - type: inputs[11].type, - name: inputs[11].key, - message: inputs[11].question, - validate: amplify.inputValidation(inputs[11]), - default: 0, - }; + return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; - return await inquirer.prompt([openIdDomainQuestion, - clientIdQuestion, - issueTTLQuestion, - authTTLQuestion]); -} + } else { -async function askApiKeyQuestions(context, inputs) { - const apiKeyExpiryQuestion = { - type: inputs[12].type, - name: inputs[12].key, - message: inputs[12].question, - validate: answer => new Promise((resolve, reject) => { - if (!answer || Number.isNaN(Number(answer)) || Number(answer) <= 0 || Number(answer) > 365) { - reject(new Error('The number of days should be set between 1 to 365')); - } - resolve(true); - }), - }; - const apiKeyExpiryAnswer = await inquirer.prompt([apiKeyExpiryQuestion]); - apiKeyExpiryAnswer[inputs[12].key] = moment().add(Number(apiKeyExpiryAnswer[inputs[12].key]), 'days').unix(); - context.print.info(`Expiry date of the API key set to: ${moment.unix(apiKeyExpiryAnswer[inputs[12].key]).local().format('YYYY-MM-DD HH:mm:ss')}`); - return apiKeyExpiryAnswer; -} + console.log('No I dont have a file'); -async function askDataSourceQuestions(context, inputs) { - const dataSourceTypeQuestion = { - type: inputs[13].type, - name: inputs[13].key, - message: inputs[13].question, - choices: inputs[13].options, - }; - const dataSources = {}; - const dependsOn = []; - let continueDataSourcesQuestion = true; - - // Ask data source related questions - - while (continueDataSourcesQuestion) { - const dataSourceAnswer = await inquirer.prompt([dataSourceTypeQuestion]); - switch (dataSourceAnswer[inputs[13].key]) { - case 'DynamoDb': { - const dynamoAnswers = await askDynamoDBQuestions(context, inputs); - Object.assign(dynamoAnswers, { category: 'storage' }); - if (!dataSources.dynamoDb) { - dataSources.dynamoDb = [dynamoAnswers]; - } else { - dataSources.dynamoDb.push(dynamoAnswers); - } - if (!dynamoAnswers.Arn) { - dependsOn.push({ - category: 'storage', - resourceName: dynamoAnswers.resourceName, - attributes: ['Name', 'Arn'], - }); + const templateQuestions = [ + { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + choices: inputs[4].options, + validate: amplify.inputValidation(inputs[4]) + }, + { + type: inputs[5].type, + name: inputs[5].key, + message: inputs[5].question, + validate: amplify.inputValidation(inputs[5]), + default: () => { + const defaultValue = allDefaultValues[inputs[5].key]; + return defaultValue; } } - break; - case 'Lambda': { - const lambdaAnswers = await askLambdaQuestions(context, inputs); - Object.assign(lambdaAnswers, { category: 'function' }); - - if (!dataSources.lambda) { - dataSources.lambda = [lambdaAnswers]; - } else { - dataSources.lambda.push(lambdaAnswers); - } - - if (!lambdaAnswers.Arn) { - dependsOn.push({ - category: 'function', - resourceName: lambdaAnswers.resourceName, - attributes: ['Name', 'Arn'], - }); + ]; + + const {templateSelection, editSchemaChoice} = await inquirer.prompt(templateQuestions); + const schemaFilePath= `${__dirname}/../appsync-schemas/${templateSelection}`; + const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; + + fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + + if(editSchemaChoice) { + const editorQuestion = { + type: inputs[6].type, + name: inputs[6].key, + message: inputs[6].question, + choices: inputs[6].options, + validate: amplify.inputValidation(inputs[6]) + }; + + const {editorSelection} = await inquirer.prompt(editorQuestion); + let editorOption = {}; + if(editorSelection !== 'none') { + editorOption = { + editor: editorSelection } } - break; - default: context.print.error('Feature not yet implemented'); - } - continueDataSourcesQuestion = await context.prompt.confirm('Do you want to add another data source?'); - } - - return { dataSources, dependsOn }; -} - -async function askDynamoDBQuestions(context, inputs) { - const dynamoDbTypeQuestion = { - type: inputs[14].type, - name: inputs[14].key, - message: inputs[14].question, - choices: inputs[14].options, - }; - while (true) { - const dynamoDbTypeAnswer = await inquirer.prompt([dynamoDbTypeQuestion]); - switch (dynamoDbTypeAnswer[inputs[14].key]) { - case 'currentProject': { - const storageResources = context.amplify.getProjectDetails().amplifyMeta.storage; - const dynamoDbProjectResources = []; - Object.keys(storageResources).forEach((resourceName) => { - if (storageResources[resourceName].service === 'DynamoDB') { - dynamoDbProjectResources.push(resourceName); - } + const editor = openInEditor.configure(editorOption, function(err) { + console.error('Editor not found in your machine. Please open your faviorite editor and modify the file if needed: ' + err); + }); + + return editor.open(targetSchemaFilePath) + .then(function() { + console.log('Success!'); + return context.amplify.pressEnterToContinue.run({ message: 'Press Enter to continue' }); + }, function(err) { + console.error('Something went wrong: ' + err); + }) + .then(() => { + const transformer = new GraphQLTransform({ + transformers: [ + new AppSyncTransformer(buildDir), + new AppSyncDynamoDBTransformer(), + new AppSyncAuthTransformer(), + ] }); - if (dynamoDbProjectResources.length === 0) { - context.print.error('There are no DynamoDb resources configured in your project currently'); - break; - } - const dynamoResourceQuestion = { - type: inputs[15].type, - name: inputs[15].key, - message: inputs[15].question, - choices: dynamoDbProjectResources, - }; - - const dynamoResourceAnswer = await inquirer.prompt([dynamoResourceQuestion]); - - return { resourceName: dynamoResourceAnswer[inputs[15].key] }; - } - case 'newResource': { - let add; - try { - ({ add } = require('amplify-category-storage')); - } catch (e) { - context.print.error('Storage plugin not installed in the CLI. Please install it to use this feature'); - break; - } - return add(context, 'awscloudformation', 'DynamoDB') - .then((resourceName) => { - context.print.success('Succesfully added DynamoDb table locally'); - return { resourceName }; - }); - } - case 'cloudResource': { - const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); - - const regionQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: regions, - }; - - const regionAnswer = await inquirer.prompt([regionQuestion]); - - const dynamodbTables = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getDynamoDBTables', { region: regionAnswer[inputs[4].key] }); - - const dynamodbOptions = dynamodbTables.map(dynamodbTable => ({ - value: { - resourceName: dynamodbTable.Name.replace(/[^0-9a-zA-Z]/gi, ''), - region: dynamodbTable.Region, - Arn: dynamodbTable.Arn, - TableName: dynamodbTable.Name, - }, - name: `${dynamodbTable.Name} (${dynamodbTable.Arn})`, - })); - - if (dynamodbOptions.length === 0) { - context.print.error('You do not have any DynamoDB tables configured for the selected region'); - break; - } - - const dynamoCloudOptionQuestion = { - type: inputs[19].type, - name: inputs[19].key, - message: inputs[19].question, - choices: dynamodbOptions, - }; - - const dynamoCloudOptionAnswer = await inquirer.prompt([dynamoCloudOptionQuestion]); - return dynamoCloudOptionAnswer[inputs[19].key]; - } - default: context.print.error('Invalid option selected'); - } - } -} - -async function askLambdaQuestions(context, inputs) { - const lambdaTypeQuestion = { - type: inputs[16].type, - name: inputs[16].key, - message: inputs[16].question, - choices: inputs[16].options, - }; - while (true) { - const lambdaTypeAnswer = await inquirer.prompt([lambdaTypeQuestion]); - switch (lambdaTypeAnswer[inputs[16].key]) { - case 'currentProject': { - const storageResources = context.amplify.getProjectDetails().amplifyMeta.function; - const lambdaProjectResources = []; - Object.keys(storageResources).forEach((resourceName) => { - if (storageResources[resourceName].service === 'Lambda') { - lambdaProjectResources.push(resourceName); - } + const cfdoc = transformer.transform(fs.readFileSync(targetSchemaFilePath, 'utf8')); + fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); + + return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; + }); + } else { + + const transformer = new GraphQLTransform({ + transformers: [ + new AppSyncTransformer(buildDir), + new AppSyncDynamoDBTransformer(), + new AppSyncAuthTransformer(), + ] }); - if (lambdaProjectResources.length === 0) { - context.print.error('There are no Lambda resources configured in your project currently'); - break; - } - const lambdaResourceQuestion = { - type: inputs[17].type, - name: inputs[17].key, - message: inputs[17].question, - choices: lambdaProjectResources, - }; + const cfdoc = transformer.transform(fs.readFileSync(targetSchemaFilePath, 'utf8')); + fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); - const lambdaResourceAnswer = await inquirer.prompt([lambdaResourceQuestion]); - return { resourceName: lambdaResourceAnswer[inputs[17].key] }; - } - case 'newResource': { - let add; - try { - ({ add } = require('amplify-category-function')); - } catch (e) { - context.print.error('Function plugin not installed in the CLI. Please install it to use this feature'); - break; - } - return add(context, 'awscloudformation', 'Lambda') - .then((resourceName) => { - context.print.success('Succesfully added Lambda function locally'); - return { resourceName }; - }); - } - case 'cloudResource': { - const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); - - const regionQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: regions, - }; - - const regionAnswer = await inquirer.prompt([regionQuestion]); - - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions', { region: regionAnswer[inputs[4].key] }); - - const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ - value: { - resourceName: lambdaFunction.FunctionName.replace(/[^0-9a-zA-Z]/gi, ''), - Arn: lambdaFunction.FunctionArn, - FunctionName: lambdaFunction.FunctionName, - }, - name: `${lambdaFunction.FunctionName} (${lambdaFunction.FunctionArn})`, - })); - - if (lambdaOptions.length === 0) { - context.print.error('You do not have any lambda functions configured for the selected region'); - break; - } - - const lambdaCloudOptionQuestion = { - type: inputs[18].type, - name: inputs[18].key, - message: inputs[18].question, - choices: lambdaOptions, - }; - - const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); - return lambdaCloudOptionAnswer[inputs[18].key]; - } - default: context.print.error('Invalid option selected'); + return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; } + } + } + module.exports = { serviceWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 3c6ac59cfc..da1886f6bb 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -3,7 +3,7 @@ "inputs": [{ "key": "resourceName", "type": "input", - "question": "Please provide a friendly name for your resource that will be used to label this category in the project:", + "question": "Provide a friendly name for your resource that will be used to label this category in the project:", "validation": { "operator": "regex", "value": "^[a-zA-Z0-9]+$", @@ -15,7 +15,7 @@ "key": "apiName", "type": "input", - "question": "Please provide API name:", + "question": "Provide API name:", "validation": { "operator": "regex", "value": "^[a-zA-Z0-9._-]+$", @@ -25,192 +25,76 @@ }, { - "key": "templateSelection", - "type": "list", - "question": "Choose from one of the options below", - "options": [{ - "name": "Use sample AppSync-DynamoDB example cloudformation template", - "value": "default" - }, - { - "name": "Create an AppSync API from scratch", - "value": "custom" - } - ], + "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": "authType", + "key": "templateSelection", "type": "list", - "question": "Choose an authorization type for the API", + "question": "What best describes your project:", "options": [{ - "name": "API key", - "value": "apiKey" - }, - { - "name": "AWS Identity and Access Management (IAM)", - "value": "iam" + "name": "Single object with fields (e.g. “Todo” with ID, name, description)", + "value": "single-relationship-schema.graphql" }, { - "name": "Amazon Cognito User Pool", - "value": "cognito" - }, - { - "name": "OpenID Connect", - "value": "openId" + "name": "One to many relationship (e.g. “Blogs” with “Comments”)", + "value": "many-relationship-schema.graphql" } - ], "required": true }, { - "key": "cognitoUserPoolRegion", - "type": "list", - "question": "Please select a region:" - }, - { - - "key": "cognitoUserPoolId", - "type": "list", - "question": "Please select a user pool ID:", - "validation": { - "operator": "regex", - "value": "^[a-zA-Z0-9._-]+$", - "onErrorMsg": "You can use the following characters: a-z A-Z 0-9 . - _" - }, - "required": true - }, - { - - "key": "cognitoAction", - "type": "list", - "question": "Select the default permission for requests to your API", - "options": [ - "ALLOW", - "DENY" - ] - }, - { - - "key": "appClientRegex", - "type": "input", - "question": "Type a regular expression to allow or block requests to this API (Optional)" - }, - { - - "key": "openIdUrl", - "type": "input", - "question": "Please provide the URL of your OpenID Connect provider used for discovery:", + "key": "editSchemaChoice", + "type": "confirm", + "question": "Do you want to edit the schema now?", "required": true }, { - "key": "clientId", - "type": "input", - "question": "Please provide a client id from your OpenID Client Connect application to only allow tokens from that application(Optional):" - }, - { - - "key": "issueTTL", - "type": "input", - "question": "Please provide the number of milliseconds a token is valid for after being issued to a user. Set to 0 to disable(Optional):", - "validation": { - "operator": "regex", - "value": "^[0-9]+$", - "onErrorMsg": "Value entered can only be numeric" - } - }, - { - - "key": "authTTL", - "type": "input", - "question": "Please provide the number of milliseconds a token is valid for after being authenticated. Set to 0 to disable(Optional):", - "validation": { - "operator": "regex", - "value": "^[0-9]+$", - "onErrorMsg": "Value entered can only be numeric" - } - }, - { - - "key": "apiKeyExpiryDays", - "type": "input", - "question": "Please provide the days after which the api key would be invalid (with a minimum of 1 day and a maximum of 365 days):" - }, - { - - "key": "dataSourceType", + "key": "editorSelection", "type": "list", - "question": "Choose a data source you would like to add to your AppSync API", - "options": [ - "DynamoDb", - "Lambda" - ] - }, - { - - "key": "dynamoDbType", - "type": "list", - "question": "Choose a DynamoDB data source option", + "question": "Chose the editor you would want to open the schema in:", "options": [{ - "name": "Use DynamoDB table configured in the current Amplify project", - "value": "currentProject" + "name": "Sublime Text", + "value": "sublime" }, { - "name": "Create a new DynamoDB table", - "value": "newResource" + "name": "Atom Editor", + "value": "atom" }, { - "name": "Use a DynamoDB table already deployed on AWS", - "value": "cloudResource" - } - ] - }, - { - - "key": "dynamoDbResources", - "type": "list", - "question": "Choose from one of the already configured DynamoDB tables" - }, - { - - "key": "lambdaType", - "type": "list", - "question": "Choose a Lambda data source option", - "options": [{ - "name": "Use a Lambda function already added in the current Amplify project", - "value": "currentProject" + "name": "Visual Studio Code", + "value": "code" }, { - "name": "Create a new Lambda function", - "value": "newResource" + "name": "IDEA 14 CE", + "value": "idea14ce" }, { - "name": "Use a Lambda function already deployed on AWS", - "value": "cloudResource" + "name": "Vim (via Terminal, Mac OS only)", + "value": "vim" + }, + { + "name": "Emacs (via Terminal, Mac OS only)", + "value": "emacs" + }, + { + "name": "None - Use my env variables to open my default editor", + "value": "none" } - ] - }, - { - "key": "lambdaResources", - "type": "list", - "question": "Choose from one of the already configured Lambda functions" - }, - { - - "key": "lambdaFunctionChoice", - "type": "list", - "question": "Please select a Lambda function:", - "required": true - }, - { - - "key": "dynamodbTableChoice", - "type": "list", - "question": "Please select a DynamoDB table:", + ], "required": true } ], From 2beb88e917aa01325b5880d3c1dddf21524379a5 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 3 Aug 2018 23:17:16 -0700 Subject: [PATCH 049/587] Rearranging files --- .../appsync-schemas/many-relationship-schema.graphql | 0 .../appsync-schemas/single-relationship-schema.graphql | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/appsync-schemas/many-relationship-schema.graphql (100%) rename packages/amplify-category-api/provider-utils/{amplify-provider-awscloudformation => awscloudformation}/appsync-schemas/single-relationship-schema.graphql (100%) diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/many-relationship-schema.graphql rename to packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql diff --git a/packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql similarity index 100% rename from packages/amplify-category-api/provider-utils/amplify-provider-awscloudformation/appsync-schemas/single-relationship-schema.graphql rename to packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql From 3e4bd85e1e5ecc280a1e58b8689f0ccc25e948f2 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 5 Aug 2018 23:45:24 -0700 Subject: [PATCH 050/587] GraphQL Transformer + Amplify CLI integration --- packages/amplify-category-api/commands/api.js | 14 +- .../amplify-category-api/commands/api/add.js | 19 +- .../commands/api/console.js | 2 +- .../commands/api/gql-compile.js | 8 + .../commands/api/update.js | 29 ++ packages/amplify-category-api/index.js | 6 +- packages/amplify-category-api/package.json | 6 - .../appsync-schemas/basic-schema.graphql | 4 + .../default-values/appSync-defaults.js | 2 +- .../provider-utils/awscloudformation/index.js | 19 +- .../service-walkthroughs/apigw-walkthrough.js | 6 +- .../appSync-walkthrough.js | 346 ++++++++++++------ .../provider-utils/supported-services.json | 19 + 13 files changed, 322 insertions(+), 158 deletions(-) create mode 100644 packages/amplify-category-api/commands/api/gql-compile.js create mode 100644 packages/amplify-category-api/commands/api/update.js create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index 574f41bf2e..f8cd84a61c 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -3,13 +3,13 @@ const featureName = 'api'; module.exports = { name: featureName, run: async (context) => { - if(/^win/.test(process.platform)) { - try { - const {run} = require(`./${featureName}/${context.parameters.first}`); - return run(context); - } catch(e) { - context.print.error('Command not found'); - } + if (/^win/.test(process.platform)) { + try { + const { run } = require(`./${featureName}/${context.parameters.first}`); + return run(context); + } catch (e) { + context.print.error('Command not found'); + } } const header = `amplify ${featureName} `; const commands = [ diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 98178cb544..203230f18c 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -9,22 +9,6 @@ let options; module.exports = { name: subcommand, run: async (context) => { - - - /*const transformer = new GraphQLTransform({ - transformers: [ - new AppSyncTransformer('/Users/kaustavg/my-app'), - new AppSyncDynamoDBTransformer(), - new AppSyncAuthTransformer(), - - ] - }); - const cfdoc = transformer.transform(fs.readFileSync('/Users/kaustavg/my-app/schematransform.graphql', 'utf8')); - console.log(cfdoc); - - - return;*/ - const { amplify } = context; return amplify.serviceSelectionPrompt(context, category, servicesMetadata) .then((result) => { @@ -32,7 +16,8 @@ module.exports = { service: result.service, providerPlugin: result.providerName, }; - const providerController = require(`../../provider-utils/${result.providerName}/index`); + const providerController = + require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { context.print.error('Provider not configured for this category'); return; diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index 04392f5cbe..a3febfb5c8 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -4,6 +4,6 @@ const category = 'api'; module.exports = { name: subcommand, run: async (context) => { - context.print.info('to be implemented: ' + category + ' ' + subcommand); + context.print.info(`to be implemented: ${category} ${subcommand}`); }, }; diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js new file mode 100644 index 0000000000..3c1f0941b1 --- /dev/null +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -0,0 +1,8 @@ +const subcommand = 'gql-compile'; + +module.exports = { + name: subcommand, + run: async (context) => { + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); + }, +}; diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js new file mode 100644 index 0000000000..a1b4058590 --- /dev/null +++ b/packages/amplify-category-api/commands/api/update.js @@ -0,0 +1,29 @@ +const fs = require('fs'); + +const subcommand = 'update'; +const category = 'api'; +const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); + + +module.exports = { + name: subcommand, + alias: ['configure'], + run: async (context) => { + const { amplify } = context; + + return amplify.serviceSelectionPrompt(context, category, servicesMetadata) + .then((result) => { + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + return providerController.updateResource(context, category, result.service); + }) + .then(() => context.print.success('Successfully updated resource')) + .catch((err) => { + context.print.info(err.stack); + context.print.error('There was an error updating the API resource'); + }); + }, +}; diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 02921cef48..5766fe2f66 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -1,9 +1,9 @@ const category = 'api'; async function console(context) { - context.print.info('to be implemented: ' + category + ' console'); + context.print.info(`to be implemented: ${category} console`); } - + module.exports = { - console + console, }; diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 21577c37b7..e39a065fa6 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -12,12 +12,6 @@ "amplify-category-auth": "^0.1.0", "amplify-category-function": "^0.1.0", "amplify-category-storage": "^0.1.0", - "graphql-transform": "1.0", - "graphql-dynamodb-transformer": "1.0", - "graphql-elasticsearch-transformer": "1.0", - "graphql-auth-transformer": "1.0", - "graphql-transformer-common": "1.0", - "graphql-appsync-transformer": "1.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql new file mode 100644 index 0000000000..829ce71bff --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql @@ -0,0 +1,4 @@ +type Post @model { + id: ID! + title: String! +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js index e48476dcd4..37fe19beb4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js @@ -2,7 +2,7 @@ const uuid = require('uuid'); const getAllDefaults = (project) => { const name = project.projectConfig.projectName.toLowerCase(); - const region = project.amplifyMeta.providers['awscloudformation'].Region; + const region = project.amplifyMeta.providers.awscloudformation.Region; const [shortId] = uuid().split('-'); const defaults = { resourceName: `appsync${shortId}`, diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 1973c7f266..88de181b14 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -44,7 +44,7 @@ function addResource(context, category, service, options) { if (result.output) { options.output = result.output; } - if(!result.noCfnFile) { + if (!result.noCfnFile) { if (answers.customCfnFile) { cfnFilename = answers.customCfnFile; } @@ -59,4 +59,19 @@ function addResource(context, category, service, options) { }); } -module.exports = { addResource }; + +async function updateResource(context, category, service) { + serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { updateWalkthrough } = require(serviceWalkthroughSrc); + + if (!updateWalkthrough) { + context.print.error('Update functionaility not available for this option'); + return; + } + + return updateWalkthrough(context, defaultValuesFilename, serviceMetadata); +} + +module.exports = { addResource, updateResource }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index fcbcf99d8c..2d514873ad 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -21,11 +21,11 @@ async function serviceWalkthrough(context, defaultValuesFilename) { if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && context.amplify.getProjectDetails().amplifyMeta.providers && - context.amplify.getProjectDetails().amplifyMeta.providers['awscloudformation'] + context.amplify.getProjectDetails().amplifyMeta.providers.awscloudformation ) { // TODO: read from utility functions (Dustin PR) const { amplifyMeta } = context.amplify.getProjectDetails(); - const providerInfo = amplifyMeta.providers['awscloudformation']; + const providerInfo = amplifyMeta.providers.awscloudformation; answers.privacy.authRoleName = providerInfo.AuthRoleName; answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; @@ -312,4 +312,4 @@ function checkIfAuthExists(context) { } -module.exports = { serviceWalkthrough }; \ No newline at end of file +module.exports = { serviceWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 8593cef68b..6ef7480066 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,25 +1,23 @@ const inquirer = require('inquirer'); -const moment = require('moment'); const fs = require('fs-extra'); const path = require('path'); const openInEditor = require('open-in-editor'); -const GraphQLTransform = require('graphql-transform').default; -const AppSyncDynamoDBTransformer = require('graphql-dynamodb-transformer').default; -const AppSyncAuthTransformer = require('graphql-auth-transformer').default; -const AppSyncTransformer = require('graphql-appsync-transformer').default; + const category = 'api'; +const serviceName = 'AppSync'; const parametersFileName = 'parameters.json'; -const templateFileName = 'cloudformation-template.json'; const schemaFileName = 'schema.graphql'; -const securityTypeMapping = { - apiKey: 'API_KEY', - iam: 'AWS_IAM', - cognito: 'AMAZON_COGNITO_USER_POOLS', - openId: 'OPENID_CONNECT', -}; async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { + const resourceName = resourceAlreadyExists(context); + + if (resourceName) { + context.print.warning('You already have an appsync API in your project. Please use "amplify update api" command to update your existing AppSync API'); + process.exit(0); + } + + const { amplify } = context; const { inputs } = serviceMetadata; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; @@ -44,157 +42,269 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat validate: amplify.inputValidation(inputs[1]), default: answers => answers.resourceName, }, - { - type: inputs[2].type, - name: inputs[2].key, - message: inputs[2].question, - validate: amplify.inputValidation(inputs[2]), - default: () => { - const defaultValue = allDefaultValues[inputs[2].key]; - return defaultValue; - }, - }, ]; // Ask resource and API name question const resourceAnswers = await inquirer.prompt(resourceQuestions); - Object.assign(allDefaultValues, resourceAnswers); - const backendDir = amplify.pathManager.getBackendDirPath(); + const parameters = { + AppSyncApiName: resourceAnswers[inputs[1].key], + }; - const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; - const buildDir = `${resourceDir}/build`; + // Ask auth/security question - fs.ensureDirSync(buildDir); + const authType = await askSecurityQuestions(context, parameters); - const parametersFilePath = path.join(resourceDir, parametersFileName); + // Ask schema file question - const parameters = { - AppSyncApiName: resourceAnswers[inputs[1].key] + const schemaFileQuestion = { + type: inputs[2].type, + name: inputs[2].key, + message: inputs[2].question, + validate: amplify.inputValidation(inputs[2]), + default: () => { + const defaultValue = allDefaultValues[inputs[2].key]; + return defaultValue; + }, }; - const jsonString = JSON.stringify(parameters, null, 4); + const schemaFileAnswer = await inquirer.prompt(schemaFileQuestion); + + + const backendDir = amplify.pathManager.getBackendDirPath(); + + const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; + - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + if (schemaFileAnswer[inputs[2].key]) { + // User has an annotated schema file - if (resourceAnswers[inputs[2].key]) { - console.log('Yes I have a file'); const filePathQuestion = { type: inputs[3].type, name: inputs[3].key, message: inputs[3].question, - validate: amplify.inputValidation(inputs[3]) + validate: amplify.inputValidation(inputs[3]), }; const { schemaFilePath } = await inquirer.prompt(filePathQuestion); + fs.ensureDirSync(resourceDir); fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); - // Transformer compiler code + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + } + + // The user doesn't have an annotated schema file + + if (!await context.prompt.confirm('Do you want a guided schema creation?')) { + // Copy the most basic schema onto the users resource dir and transform that + const schemaFilePath = `${__dirname}/../appsync-schemas/basic-schema.graphql`; + const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; + + context.print.info('Creating a base schema for you...'); + + fs.ensureDirSync(resourceDir); + fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, noConfig: true }); + + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + } + // Guided creation of the transform schema + + const templateQuestions = [ + { + type: inputs[4].type, + name: inputs[4].key, + message: inputs[4].question, + choices: inputs[4].options, + validate: amplify.inputValidation(inputs[4]), + }, + { + type: inputs[5].type, + name: inputs[5].key, + message: inputs[5].question, + validate: amplify.inputValidation(inputs[5]), + default: () => { + const defaultValue = allDefaultValues[inputs[5].key]; + return defaultValue; + }, + }, + ]; + + const { templateSelection, editSchemaChoice } = await inquirer.prompt(templateQuestions); + const schemaFilePath = `${__dirname}/../appsync-schemas/${templateSelection}`; + const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; - const transformer = new GraphQLTransform({ - transformers: [ - new AppSyncTransformer(buildDir), - new AppSyncDynamoDBTransformer(), - new AppSyncAuthTransformer(), - ] + fs.ensureDirSync(resourceDir); + fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + + if (editSchemaChoice) { + const editorQuestion = { + type: inputs[6].type, + name: inputs[6].key, + message: inputs[6].question, + choices: inputs[6].options, + validate: amplify.inputValidation(inputs[6]), + }; + + const { editorSelection } = await inquirer.prompt(editorQuestion); + let editorOption = {}; + if (editorSelection !== 'none') { + editorOption = { + editor: editorSelection, + }; + } + const editor = openInEditor.configure(editorOption, (err) => { + console.error(`Editor not found in your machine. Please open your favorite editor and modify the file if needed: ${err}`); }); - - const cfdoc = transformer.transform(fs.readFileSync(schemaFilePath, 'utf8')); - fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); - return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; + return editor.open(targetSchemaFilePath) + .then(async () => { + const continueQuestion = { + type: 'input', + name: 'pressKey', + message: 'Press any key to continue', + }; + + await inquirer.prompt(continueQuestion); + }, (err) => { + context.print.error(`Something went wrong: ${err}. Please manually edit the graphql schema`); + }) + .then(async () => { + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + }); + } + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; +} +async function updateWalkthrough(context) { + const { allResources } = await context.amplify.getResourceStatus(); + let resourceDir; + let resourceName; + const resources = allResources.filter(resource => resource.service === 'AppSync'); + // There can only be one appsync resource + if (resources.length > 0) { + const resource = resources[0]; + ({ resourceName } = resource); + const backEndDir = context.amplify.pathManager.getBackendDirPath(); + resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); } else { + context.print.error('No appsync resource to update. Please use "amplify add api" command to update your existing AppSync API'); + process.exit(0); + return; + } + + const parametersFilePath = path.join(resourceDir, parametersFileName); + let parameters = {}; + + try { + parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + } catch (e) { + context.print.error('Paramters file not found'); + context.print.info(e.stack); + } + const authType = await askSecurityQuestions(context, parameters); - console.log('No I dont have a file'); + const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); + const amplifyMeta = JSON.parse(fs.readFileSync(amplifyMetaFilePath)); + + amplifyMeta[category][resourceName].output.securityType = authType; + const jsonString = JSON.stringify(amplifyMeta, null, '\t'); + fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); + + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); +} - const templateQuestions = [ +async function askSecurityQuestions(context, parameters) { + const securityTypeQuestion = { + type: 'list', + name: 'authType', + message: 'Choose an authorization type for the API', + choices: [ { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: inputs[4].options, - validate: amplify.inputValidation(inputs[4]) + name: 'API key', + value: 'API_KEY', }, { - type: inputs[5].type, - name: inputs[5].key, - message: inputs[5].question, - validate: amplify.inputValidation(inputs[5]), - default: () => { - const defaultValue = allDefaultValues[inputs[5].key]; - return defaultValue; - } - } - ]; + name: 'Amazon Cognito User Pool', + value: 'AMAZON_COGNITO_USER_POOLS', + }, + ], + }; - const {templateSelection, editSchemaChoice} = await inquirer.prompt(templateQuestions); - const schemaFilePath= `${__dirname}/../appsync-schemas/${templateSelection}`; - const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; + const { authType } = await inquirer.prompt([securityTypeQuestion]); - fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + if (authType === 'AMAZON_COGNITO_USER_POOLS') { + let authResourceName = checkIfAuthExists(context); - if(editSchemaChoice) { - const editorQuestion = { - type: inputs[6].type, - name: inputs[6].key, - message: inputs[6].question, - choices: inputs[6].options, - validate: amplify.inputValidation(inputs[6]) - }; + if (!authResourceName) { + try { + const { add } = require('amplify-category-auth'); - const {editorSelection} = await inquirer.prompt(editorQuestion); - let editorOption = {}; - if(editorSelection !== 'none') { - editorOption = { - editor: editorSelection - } + authResourceName = await add(context); + } catch (e) { + context.print.error('Auth plugin not installed in the CLI. Please install it to use this feature'); } - const editor = openInEditor.configure(editorOption, function(err) { - console.error('Editor not found in your machine. Please open your faviorite editor and modify the file if needed: ' + err); - }); - - return editor.open(targetSchemaFilePath) - .then(function() { - console.log('Success!'); - return context.amplify.pressEnterToContinue.run({ message: 'Press Enter to continue' }); - }, function(err) { - console.error('Something went wrong: ' + err); - }) - .then(() => { - const transformer = new GraphQLTransform({ - transformers: [ - new AppSyncTransformer(buildDir), - new AppSyncDynamoDBTransformer(), - new AppSyncAuthTransformer(), - ] - }); - const cfdoc = transformer.transform(fs.readFileSync(targetSchemaFilePath, 'utf8')); - fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); - - return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; - }); } else { + context.print.info('Using cognito user pool configured as a part of this project'); + } - const transformer = new GraphQLTransform({ - transformers: [ - new AppSyncTransformer(buildDir), - new AppSyncDynamoDBTransformer(), - new AppSyncAuthTransformer(), - ] - }); - const cfdoc = transformer.transform(fs.readFileSync(targetSchemaFilePath, 'utf8')); - fs.writeFileSync(`${resourceDir}/${templateFileName}`, JSON.stringify(cfdoc, null, 4), 'utf8'); - - - return { answers: resourceAnswers, output: { securityType: 'AWS_IAM' }, noCfnFile: true }; + parameters.AuthCognitoUserPoolId = { + 'Fn::GetAtt': [ + `auth${authResourceName}`, + 'Outputs.UserPoolId', + ], + }; + } else if (authType === 'API_KEY') { + if (parameters.AuthCognitoUserPoolId) { + delete parameters.AuthCognitoUserPoolId; } + } + + return authType; +} +function resourceAlreadyExists(context) { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); + let resourceName; + + if (amplifyMeta[category]) { + const categoryResources = amplifyMeta[category]; + Object.keys(categoryResources).forEach((resource) => { + if (categoryResources[resource].service === serviceName) { + resourceName = resource; + } + }); } + return resourceName; +} + + +function checkIfAuthExists(context) { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); + let authResourceName; + const authServiceName = 'Cognito'; + const authCategory = 'auth'; + + if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { + const categoryResources = amplifyMeta[authCategory]; + Object.keys(categoryResources).forEach((resource) => { + if (categoryResources[resource].service === authServiceName) { + authResourceName = resource; + } + }); + } + return authResourceName; } -module.exports = { serviceWalkthrough }; +module.exports = { serviceWalkthrough, updateWalkthrough }; diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index da1886f6bb..2859216103 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -96,6 +96,25 @@ ], "required": true + }, + { + + "key": "dynamoDbType", + "type": "list", + "question": "Choose a DynamoDB data source option", + "options": [{ + "name": "Use 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" + } + ] } ], "defaultValuesFilename": "appSync-defaults.js", From 74119ebd262447c3d061f9965626415199dfc785 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 6 Aug 2018 11:20:52 -0700 Subject: [PATCH 051/587] Make alias for service selection - GraphQL/REST --- .../provider-utils/supported-services.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 2859216103..2b615968e9 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -27,7 +27,7 @@ "key": "apiCreationChoice", "type": "confirm", - "question": "Do you have an annotated graphQL schema?", + "question": "Do you have an annotated GraphQL schema?", "required": true }, { @@ -117,6 +117,7 @@ ] } ], + "alias": "GraphQL", "defaultValuesFilename": "appSync-defaults.js", "serviceWalkthroughFilename": "appSync-walkthrough.js", "cfnFilename": "appSync-cloudformation-template-default.yml.ejs", @@ -143,6 +144,7 @@ "type": "input" } ], + "alias": "REST", "defaultValuesFilename": "apigw-defaults.js", "serviceWalkthroughFilename": "apigw-walkthrough.js", "cfnFilename": "apigw-cloudformation-template-default.json.ejs", From e80b02a553f3916b07cf88421558e45d4edbbde0 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 6 Aug 2018 12:04:48 -0700 Subject: [PATCH 052/587] Merge friendly name and resource name question for appsync --- .../provider-utils/awscloudformation/index.js | 2 +- .../service-walkthroughs/appSync-walkthrough.js | 13 ++----------- 2 files changed, 3 insertions(+), 12 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 88de181b14..869efe4626 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -68,7 +68,7 @@ async function updateResource(context, category, service) { if (!updateWalkthrough) { context.print.error('Update functionaility not available for this option'); - return; + process.exit(0); } return updateWalkthrough(context, defaultValuesFilename, serviceMetadata); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 6ef7480066..2a59f9e411 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -25,16 +25,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); const resourceQuestions = [ - { - type: inputs[0].type, - name: inputs[0].key, - message: inputs[0].question, - validate: amplify.inputValidation(inputs[0]), - default: () => { - const defaultValue = allDefaultValues[inputs[0].key]; - return defaultValue; - }, - }, { type: inputs[1].type, name: inputs[1].key, @@ -44,9 +34,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat }, ]; - // Ask resource and API name question + // API name question const resourceAnswers = await inquirer.prompt(resourceQuestions); + resourceAnswers[inputs[0].key] = resourceAnswers[inputs[1].key]; const parameters = { AppSyncApiName: resourceAnswers[inputs[1].key], From 621cbeca905c5dce76420b6a971943c7f54d281d Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 6 Aug 2018 13:59:44 -0700 Subject: [PATCH 053/587] Fix some typos in cli language --- .../provider-utils/awscloudformation/index.js | 2 +- .../service-walkthroughs/appSync-walkthrough.js | 2 +- .../amplify-category-api/provider-utils/supported-services.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 869efe4626..616d6a8853 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -67,7 +67,7 @@ async function updateResource(context, category, service) { const { updateWalkthrough } = require(serviceWalkthroughSrc); if (!updateWalkthrough) { - context.print.error('Update functionaility not available for this option'); + context.print.error('Update functionality not available for this option'); process.exit(0); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 2a59f9e411..822a3ada3c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -196,7 +196,7 @@ async function updateWalkthrough(context) { try { parameters = JSON.parse(fs.readFileSync(parametersFilePath)); } catch (e) { - context.print.error('Paramters file not found'); + context.print.error('Parameters file not found'); context.print.info(e.stack); } diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 2b615968e9..7025027920 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -64,7 +64,7 @@ "key": "editorSelection", "type": "list", - "question": "Chose the editor you would want to open the schema in:", + "question": "Choose the editor you would want to open the schema in:", "options": [{ "name": "Sublime Text", "value": "sublime" From bb3f0b520f64732835743afca2a297136d7f7eca Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 7 Aug 2018 12:53:11 -0700 Subject: [PATCH 054/587] Modularize opening up of editor to modify code, move choosing of default editor to init step and open lambda function code after addition of it --- packages/amplify-category-api/package.json | 1 - .../appSync-walkthrough.js | 33 +------------------ 2 files changed, 1 insertion(+), 33 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e39a065fa6..527aa58f36 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -16,7 +16,6 @@ "fs-extra": "^6.0.1", "inquirer": "^3.2.1", "moment": "^2.22.2", - "open-in-editor": "^2.2.0", "uuid": "^2.0.3" }, "devDependencies": { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 822a3ada3c..25b9e86753 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,7 +1,6 @@ const inquirer = require('inquirer'); const fs = require('fs-extra'); const path = require('path'); -const openInEditor = require('open-in-editor'); const category = 'api'; const serviceName = 'AppSync'; @@ -133,37 +132,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, targetSchemaFilePath); if (editSchemaChoice) { - const editorQuestion = { - type: inputs[6].type, - name: inputs[6].key, - message: inputs[6].question, - choices: inputs[6].options, - validate: amplify.inputValidation(inputs[6]), - }; - - const { editorSelection } = await inquirer.prompt(editorQuestion); - let editorOption = {}; - if (editorSelection !== 'none') { - editorOption = { - editor: editorSelection, - }; - } - const editor = openInEditor.configure(editorOption, (err) => { - console.error(`Editor not found in your machine. Please open your favorite editor and modify the file if needed: ${err}`); - }); - - return editor.open(targetSchemaFilePath) - .then(async () => { - const continueQuestion = { - type: 'input', - name: 'pressKey', - message: 'Press any key to continue', - }; - - await inquirer.prompt(continueQuestion); - }, (err) => { - context.print.error(`Something went wrong: ${err}. Please manually edit the graphql schema`); - }) + return context.amplify.openEditor(context, targetSchemaFilePath) .then(async () => { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; From cce6c1e56598ed6d62af4cc7029cf212df22b6d4 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 7 Aug 2018 22:44:44 -0700 Subject: [PATCH 055/587] Added validations for GraphQL-API category flow and added example annotated GraphQL schemas as a part of the CLI flow --- .../appsync-schemas/basic-schema.graphql | 4 -- .../appsync-schemas/basic-schema.graphql.ejs | 7 +++ .../many-relationship-schema.graphql | 16 +++++- .../single-object-auth-schema.graphql | 17 ++++++ .../single-object-schema.graphql | 5 ++ .../single-relationship-schema.graphql | 4 -- .../appSync-walkthrough.js | 54 +++++++++++++++++-- .../provider-utils/supported-services.json | 10 ++-- 8 files changed, 99 insertions(+), 18 deletions(-) delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql deleted file mode 100644 index 829ce71bff..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post @model { - id: ID! - title: String! -} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs new file mode 100644 index 0000000000..eeb1032c39 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs @@ -0,0 +1,7 @@ +type <%= props.typeName %> @model { + id: ID! + title: String! + content: String! + price: Int + rating: Float +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql index 829ce71bff..bb3c4c7d11 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql @@ -1,4 +1,16 @@ +type Blog @model { + id: ID! + name: String! + posts: [Post] @connection(name: "BlogPosts") +} type Post @model { - id: ID! - title: String! + id: ID! + title: String! + blog: Blog @connection(name: "BlogPosts") + comments: [Comment] @connection(name: "PostComments") +} +type Comment @model { + id: ID! + content: String + post: Post @connection(name: "PostComments") } \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql new file mode 100644 index 0000000000..5542b4825d --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql @@ -0,0 +1,17 @@ +type Task + @model + @auth(allow: groups, groups: ["Managers"], mutations: [create, update, delete]) + @auth(allow: groups, groups: ["Employees"], queries: [get, list]) +{ + id: ID! + title: String! + description: String + status: String +} +type PrivateNote + @model + @auth(allow: owner) +{ + id: ID! + content: String! +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql new file mode 100644 index 0000000000..1f5a301fbe --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql @@ -0,0 +1,5 @@ +type Todo @model { + id: ID! + name: String! + description: String +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql deleted file mode 100644 index 829ce71bff..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-relationship-schema.graphql +++ /dev/null @@ -1,4 +0,0 @@ -type Post @model { - id: ID! - title: String! -} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 25b9e86753..e41c3444ed 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -90,13 +90,37 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat if (!await context.prompt.confirm('Do you want a guided schema creation?')) { // Copy the most basic schema onto the users resource dir and transform that - const schemaFilePath = `${__dirname}/../appsync-schemas/basic-schema.graphql`; - const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; - context.print.info('Creating a base schema for you...'); + const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; + const typeNameQuestion = { + type: 'input', + name: 'typeName', + message: 'Provide a custom type name', + default: 'MyType', + validate: amplify.inputValidation({ + operator: 'regex', + value: '^[a-zA-Z0-9]+$', + onErrorMsg: 'Resource name should be alphanumeric', + }), + }; + const typeNameAnswer = await inquirer.prompt(typeNameQuestion); fs.ensureDirSync(resourceDir); - fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + // fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + const schemaDir = `${__dirname}/../appsync-schemas`; + + const copyJobs = [ + { + dir: schemaDir, + template: 'basic-schema.graphql.ejs', + target: targetSchemaFilePath, + }, + ]; + + // copy over the ejs file + await context.amplify.copyBatch(context, copyJobs, typeNameAnswer); + + context.print.info('Creating a base schema for you...'); await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, noConfig: true }); @@ -134,11 +158,31 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat if (editSchemaChoice) { return context.amplify.openEditor(context, targetSchemaFilePath) .then(async () => { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + let notCompiled = true; + while (notCompiled) { + try { + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + } catch (e) { + context.print.error('Failed compiling annotated GraphQL schema.'); + context.print.info(e.stack); + const continueQuestion = { + type: 'input', + name: 'pressKey', + message: 'Please correct the errors in the GraphQL annotated schema and press enter to re-compile', + }; + await inquirer.prompt(continueQuestion); + continue; + } + notCompiled = false; + } return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; }); } + + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; } diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 7025027920..0c9716887b 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -18,7 +18,7 @@ "question": "Provide API name:", "validation": { "operator": "regex", - "value": "^[a-zA-Z0-9._-]+$", + "value": "^[a-zA-Z0-9]+$", "onErrorMsg": "You can use the following characters: a-z A-Z 0-9 . - _" }, "required": true @@ -44,11 +44,15 @@ "question": "What best describes your project:", "options": [{ "name": "Single object with fields (e.g. “Todo” with ID, name, description)", - "value": "single-relationship-schema.graphql" + "value": "single-object-schema.graphql" }, { - "name": "One to many relationship (e.g. “Blogs” with “Comments”)", + "name": "One to many relationship (e.g. “Blogs” with “Posts” & “Comments”)", "value": "many-relationship-schema.graphql" + }, + { + "name": "Objects with fine-grained security (e.g. Project management app with owner based authorization)", + "value": "single-object-auth-schema.graphql" } ], "required": true From dbaab3d85612ec8169aa8efa708028db3b64e293 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 8 Aug 2018 10:39:25 -0700 Subject: [PATCH 056/587] Add filter to the graphql schema choices based on security selection --- .../service-walkthroughs/appSync-walkthrough.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index e41c3444ed..e2d709383a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -128,12 +128,17 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat } // Guided creation of the transform schema + let templateSchemaChoices = inputs[4].options; + if (authType === 'API_KEY') { + templateSchemaChoices = templateSchemaChoices.filter(schema => schema.value !== 'single-object-auth-schema.graphql'); + } + const templateQuestions = [ { type: inputs[4].type, name: inputs[4].key, message: inputs[4].question, - choices: inputs[4].options, + choices: templateSchemaChoices, validate: amplify.inputValidation(inputs[4]), }, { From d967511cb72a90992b1952eb2e7f6a6931f217cf Mon Sep 17 00:00:00 2001 From: Dustin Noyes Date: Mon, 6 Aug 2018 16:49:47 -0700 Subject: [PATCH 057/587] adding dependency checking --- .../service-walkthroughs/apigw-walkthrough.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 2d514873ad..cd6422d39b 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -16,7 +16,7 @@ async function serviceWalkthrough(context, defaultValuesFilename) { answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; ({ dependsOn } = pathsAnswer); - const privacy = await askPrivacy(context); + const privacy = await askPrivacy(context, answers); answers = { ...answers, privacy, dependsOn }; if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && @@ -59,7 +59,7 @@ async function askApiNames(context, defaults) { return answer; } -async function askPrivacy(context) { +async function askPrivacy(context, answers) { while (true) { const answer = await inquirer.prompt({ name: 'privacy', @@ -92,14 +92,14 @@ async function askPrivacy(context) { if (!checkIfAuthExists(context)) { if (await context.prompt.confirm('You need auth (Cognito) added to your project for adding storage for user files. Do you want to add auth now?')) { try { - const { add } = require('amplify-category-auth'); + const { checkRequirements } = require('amplify-category-auth'); context.api = { privacy: answer.privacy, }; - await add(context); + await checkRequirements({ authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }, context, 'api', answers.resourceName); return privacy; } catch (e) { - context.print.error('Auth plugin not installed in the CLI. Please install it to use this feature'); + context.print.error(e); } } } else { From 91bf3836c17ca7d767e0966f282aacf0fb2d90d5 Mon Sep 17 00:00:00 2001 From: Dustin Noyes Date: Wed, 8 Aug 2018 11:08:28 -0700 Subject: [PATCH 058/587] update auth and solo id pool --- .../service-walkthroughs/apigw-walkthrough.js | 56 ++++++++++--------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index cd6422d39b..7526fbb948 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -89,22 +89,28 @@ async function askPrivacy(context, answers) { if (answer.privacy === 'open') { return privacy; } - if (!checkIfAuthExists(context)) { + const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); + context.api = { + privacy: answer.privacy, + }; + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + if (foundUnmetRequirements) { if (await context.prompt.confirm('You need auth (Cognito) added to your project for adding storage for user files. Do you want to add auth now?')) { try { - const { checkRequirements } = require('amplify-category-auth'); - context.api = { - privacy: answer.privacy, - }; - await checkRequirements({ authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }, context, 'api', answers.resourceName); + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); return privacy; } catch (e) { context.print.error(e); } } - } else { - return privacy; } + return privacy; } } @@ -293,23 +299,23 @@ async function askLambdaArn(context) { return { lambdaArn: lambdaCloudOptionAnswer.lambdaChoice.Arn, lambdaFunction: lambdaCloudOptionAnswer.lambdaChoice.FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; } -function checkIfAuthExists(context) { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); - let authExists = false; - const authServiceName = 'Cognito'; - const authCategory = 'auth'; - - if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { - const categoryResources = amplifyMeta[authCategory]; - Object.keys(categoryResources).forEach((resource) => { - if (categoryResources[resource].service === authServiceName) { - authExists = true; - } - }); - } - return authExists; -} +// function checkIfAuthExists(context) { +// const { amplify } = context; +// const { amplifyMeta } = amplify.getProjectDetails(); +// let authExists = false; +// const authServiceName = 'Cognito'; +// const authCategory = 'auth'; + +// if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { +// const categoryResources = amplifyMeta[authCategory]; +// Object.keys(categoryResources).forEach((resource) => { +// if (categoryResources[resource].service === authServiceName) { +// authExists = true; +// } +// }); +// } +// return authExists; +// } module.exports = { serviceWalkthrough }; From 2afd68ec4783f7410b47c3977ddef167b843d735 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 8 Aug 2018 15:13:18 -0700 Subject: [PATCH 059/587] Modify auth for analytics and api --- .../service-walkthroughs/apigw-walkthrough.js | 62 ++++++++++++++----- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 7526fbb948..2b9c972d06 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -89,27 +89,57 @@ async function askPrivacy(context, answers) { if (answer.privacy === 'open') { return privacy; } + const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); context.api = { privacy: answer.privacy, }; - const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - if (foundUnmetRequirements) { - if (await context.prompt.confirm('You need auth (Cognito) added to your project for adding storage for user files. Do you want to add auth now?')) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - return privacy; - } catch (e) { - context.print.error(e); - } - } + + + if(answer.privacy === 'private') { + + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + return privacy; + } catch (e) { + context.print.error(e); + throw e; + } + } + } + + if(answer.privacy === 'protected') { + + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + return privacy; + } catch (e) { + context.print.error(e); + throw e; + } + } + + } + return privacy; } } From de71063e5a681f176c3f7d9d397b597093f9abec Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 9 Aug 2018 00:06:19 -0700 Subject: [PATCH 060/587] lint fixes --- .../service-walkthroughs/apigw-walkthrough.js | 74 +++++++++---------- 1 file changed, 35 insertions(+), 39 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 2b9c972d06..9990b97690 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -96,48 +96,44 @@ async function askPrivacy(context, answers) { }; - if(answer.privacy === 'private') { - - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - return privacy; - } catch (e) { - context.print.error(e); - throw e; - } - } - + if (answer.privacy === 'private') { + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + return privacy; + } catch (e) { + context.print.error(e); + throw e; + } + } } - if(answer.privacy === 'protected') { - + if (answer.privacy === 'protected') { const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - return privacy; - } catch (e) { - context.print.error(e); - throw e; - } - } - + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + return privacy; + } catch (e) { + context.print.error(e); + throw e; + } + } } return privacy; From 26e3787954eb3360664d1657476a867584134ad8 Mon Sep 17 00:00:00 2001 From: Paris Date: Thu, 9 Aug 2018 15:03:59 -0700 Subject: [PATCH 061/587] Adding transform tutorial and updated @auth sample model --- .../appsync-schemas/single-object-auth-schema.graphql | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql index 5542b4825d..c34b0e58d8 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql @@ -1,7 +1,9 @@ type Task @model - @auth(allow: groups, groups: ["Managers"], mutations: [create, update, delete]) - @auth(allow: groups, groups: ["Employees"], queries: [get, list]) + @auth(rules: [ + {allow: groups, groups: ["Managers"], mutations: [create, update, delete]}, + {allow: groups, groups: ["Employees"], queries: [get, list]} + ]) { id: ID! title: String! @@ -10,7 +12,7 @@ type Task } type PrivateNote @model - @auth(allow: owner) + @auth(rules: [{allow: owner}]) { id: ID! content: String! From e4519ddd73788c239d210acc81d789cd4c189da3 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Fri, 10 Aug 2018 10:37:13 -0700 Subject: [PATCH 062/587] Adding read write permissions to API (#198) --- ...w-cloudformation-template-default.json.ejs | 348 ++++++++++++++++-- .../service-walkthroughs/apigw-walkthrough.js | 56 ++- 2 files changed, 372 insertions(+), 32 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index cc74e0cbee..2926e0ee7d 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -15,18 +15,15 @@ }, <% } %> "Resources": { - <%if (!props.privacy.open) { %> - "PolicyAPIGW<%= props.apiName %>": { + <%if (props.privacy.auth) { %> + "PolicyAPIGW<%= props.apiName %>auth": { "DependsOn": [ "<%= props.apiName %>" ], "Type": "AWS::IAM::Policy", "Properties": { - "PolicyName": "PolicyAPIGW<%= props.apiName %>", + "PolicyName": "PolicyAPIGW<%= props.apiName %>auth", "Roles": [ - <%if (props.privacy.protected) { %> - "<%= props.privacy.unAuthRoleName %>", - <% } %> "<%= props.privacy.authRoleName %>" ], "PolicyDocument": { @@ -37,26 +34,327 @@ "Action": [ "execute-api:Invoke" ], - "Resource": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/Prod/*/*" + "Resource": [ + <%if (props.privacy.auth === 'rw') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/*/*" + ] ] - ] - } + } + <% } %> + <%if (props.privacy.auth === 'r') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/GET/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/HEAD/*" + ] + ] + } + <% } %> + <%if (props.privacy.auth === 'w') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/DELETE/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PATCH/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/POST/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT/*" + ] + ] + } + <% } %> + ] + } + ] + } + } + }, + <% } %> + <%if (props.privacy.unauth) { %> + "PolicyAPIGW<%= props.apiName %>unauth": { + "DependsOn": [ + "<%= props.apiName %>" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", + "Roles": [ + "<%= props.privacy.unAuthRoleName %>" + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "execute-api:Invoke" + ], + "Resource": [ + <%if (props.privacy.unauth === 'rw') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/*/*" + ] + ] + } + <% } %> + <%if (props.privacy.unauth === 'r') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/GET/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/HEAD/*" + ] + ] + } + <% } %> + <%if (props.privacy.unauth === 'w') { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/DELETE/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PATCH/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/POST/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT/*" + ] + ] + } + <% } %> + ] } ] } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 9990b97690..6675a9e44c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -61,21 +61,29 @@ async function askApiNames(context, defaults) { async function askPrivacy(context, answers) { while (true) { + + const apiAccess = await inquirer.prompt({ + name: 'restrict', + type: 'confirm', + default: true, + message: 'Restrict API access' + }); + + if (!apiAccess.restrict) { + return { open: true }; + } + const answer = await inquirer.prompt({ name: 'privacy', type: 'list', - message: 'Which kind of privacy your API should have?', + message: 'Who should have access?', choices: [ { - name: 'Open (No security)', - value: 'open', - }, - { - name: 'Authenticated - AWS IAM (Signature Version 4 signing)', + name: 'Authenticated users only', value: 'private', }, { - name: 'Authenticated and Guest users (AWS_IAM with Cognito Identity)', + name: 'Authenticated and Guest users', value: 'protected', }, ], @@ -97,6 +105,9 @@ async function askPrivacy(context, answers) { if (answer.privacy === 'private') { + + privacy.auth = await askReadWrite('Authenticated', context); + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; // getting requirement satisfaction map const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); @@ -117,6 +128,9 @@ async function askPrivacy(context, answers) { } if (answer.privacy === 'protected') { + privacy.auth = await askReadWrite('Authenticated', context); + privacy.unauth = await askReadWrite('Guest', context); + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; // getting requirement satisfaction map const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); @@ -140,6 +154,34 @@ async function askPrivacy(context, answers) { } } +async function askReadWrite(userType, context) { + while (true) { + const answer = await inquirer.prompt({ + name: 'permissions', + type: 'list', + message: 'What kind of access do you want for ' + userType + ' users', + choices: [ + { + name: 'read', + value: 'r', + }, + { + name: 'write', + value: 'w', + }, + { + name: 'read/write', + value: 'rw', + }, + ], + }); + + if (answer.permissions !== 'learn') { + return answer.permissions; + } + } +} + async function askPaths(context) { /* TODO: add spinner when checking if the account had From f29d424989e96d4e7e3fb1f0537804a7d9c5ebfd Mon Sep 17 00:00:00 2001 From: Paris Date: Mon, 13 Aug 2018 11:37:56 -0700 Subject: [PATCH 063/587] Adding path to schema.graphql after a failed compilation. --- .../service-walkthroughs/appSync-walkthrough.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index e2d709383a..e49527d06e 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -168,12 +168,12 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat try { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); } catch (e) { - context.print.error('Failed compiling annotated GraphQL schema.'); - context.print.info(e.stack); + context.print.error('Failed compiling GraphQL schema:'); + context.print.info(e.message); const continueQuestion = { type: 'input', name: 'pressKey', - message: 'Please correct the errors in the GraphQL annotated schema and press enter to re-compile', + message: `Please correct the errors in schema.graphql and press enter to re-compile.\nPath to schema.graphql: ${targetSchemaFilePath}`, }; await inquirer.prompt(continueQuestion); continue; From 43cc6619b3bd7681769251577eff82f38161bed7 Mon Sep 17 00:00:00 2001 From: Paris Date: Mon, 13 Aug 2018 11:54:50 -0700 Subject: [PATCH 064/587] updating messages --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index e49527d06e..a9967125bb 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -173,7 +173,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const continueQuestion = { type: 'input', name: 'pressKey', - message: `Please correct the errors in schema.graphql and press enter to re-compile.\nPath to schema.graphql: ${targetSchemaFilePath}`, + message: `Please correct the errors in schema.graphql and press enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, }; await inquirer.prompt(continueQuestion); continue; From 0f9135b498c69f60c311b4c8c4f1a32c546fe2a2 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 13 Aug 2018 16:23:27 -0700 Subject: [PATCH 065/587] Bug fixes Part #1 --- .../default-values/appSync-defaults.js | 2 +- .../service-walkthroughs/apigw-walkthrough.js | 14 ++++++-------- .../service-walkthroughs/appSync-walkthrough.js | 5 ++++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js index 37fe19beb4..5c535cb023 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js @@ -6,7 +6,7 @@ const getAllDefaults = (project) => { const [shortId] = uuid().split('-'); const defaults = { resourceName: `appsync${shortId}`, - apiName: `${name}${shortId}`, + apiName: `${name}`, serviceRoleName: `serviceRole${shortId}`, servicePolicyName: `servicePolicy${shortId}`, apiCreationChoice: false, diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 6675a9e44c..ea0dd4e742 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -61,18 +61,17 @@ async function askApiNames(context, defaults) { async function askPrivacy(context, answers) { while (true) { - const apiAccess = await inquirer.prompt({ name: 'restrict', type: 'confirm', default: true, - message: 'Restrict API access' + message: 'Restrict API access', }); if (!apiAccess.restrict) { return { open: true }; } - + const answer = await inquirer.prompt({ name: 'privacy', type: 'list', @@ -105,7 +104,6 @@ async function askPrivacy(context, answers) { if (answer.privacy === 'private') { - privacy.auth = await askReadWrite('Authenticated', context); const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; @@ -130,7 +128,7 @@ async function askPrivacy(context, answers) { if (answer.privacy === 'protected') { privacy.auth = await askReadWrite('Authenticated', context); privacy.unauth = await askReadWrite('Guest', context); - + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; // getting requirement satisfaction map const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); @@ -154,12 +152,12 @@ async function askPrivacy(context, answers) { } } -async function askReadWrite(userType, context) { +async function askReadWrite(userType) { while (true) { const answer = await inquirer.prompt({ name: 'permissions', type: 'list', - message: 'What kind of access do you want for ' + userType + ' users', + message: `What kind of access do you want for ${userType} users`, choices: [ { name: 'read', @@ -175,7 +173,7 @@ async function askReadWrite(userType, context) { }, ], }); - + if (answer.permissions !== 'learn') { return answer.permissions; } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index a9967125bb..03d8c6ef08 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -29,7 +29,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat name: inputs[1].key, message: inputs[1].question, validate: amplify.inputValidation(inputs[1]), - default: answers => answers.resourceName, + default: () => { + const defaultValue = allDefaultValues[inputs[1].key]; + return defaultValue; + }, }, ]; From 7b8651db9451751a5c99923551d733beb814bf3d Mon Sep 17 00:00:00 2001 From: elorzafe Date: Wed, 15 Aug 2018 13:28:52 -0700 Subject: [PATCH 066/587] Updating api category and read-write permissions per path (#224) * Updating api category and read-write permissions per path --- ...w-cloudformation-template-default.json.ejs | 388 ++++++++++++++++-- .../provider-utils/awscloudformation/index.js | 54 ++- .../service-walkthroughs/apigw-walkthrough.js | 220 ++++++++-- 3 files changed, 594 insertions(+), 68 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 2926e0ee7d..bc3b0660b2 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -1,5 +1,6 @@ { "AWSTemplateFormatVersion": "2010-09-09", + <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { @@ -16,6 +17,7 @@ <% } %> "Resources": { <%if (props.privacy.auth) { %> + <% cnt = 0 %> "PolicyAPIGW<%= props.apiName %>auth": { "DependsOn": [ "<%= props.apiName %>" @@ -35,7 +37,9 @@ "execute-api:Invoke" ], "Resource": [ - <%if (props.privacy.auth === 'rw') { %> + <% for(var i=0; i < props.paths.length; i++) { %> + <%if (props.paths[i].privacy.auth === 'rw') { %> + <% cnt++ %> { "Fn::Join": [ "", @@ -52,12 +56,80 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*/*" + "/Prod/*", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/*", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.auth !== cnt) { %> + , + <% }%> <% } %> - <%if (props.privacy.auth === 'r') { %> + <%if (props.paths[i].privacy.auth === 'r') { %> + <% cnt++ %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/GET", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/GET", + "<%= props.paths[i].name %>" + ] + ] + }, { "Fn::Join": [ "", @@ -74,7 +146,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET/*" + "/Prod/HEAD", + "<%= props.paths[i].name %>/*" ] ] }, @@ -94,12 +167,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD/*" + "/Prod/HEAD", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.auth !== cnt) { %> + , + <% }%> <% } %> - <%if (props.privacy.auth === 'w') { %> + <%if (props.paths[i].privacy.auth === 'w') { %> + <% cnt++ %> { "Fn::Join": [ "", @@ -116,7 +194,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE/*" + "/Prod/DELETE", + "<%= props.paths[i].name %>/*" ] ] }, @@ -136,7 +215,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH/*" + "/Prod/DELETE", + "<%= props.paths[i].name %>" ] ] }, @@ -156,7 +236,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST/*" + "/Prod/PATCH", + "<%= props.paths[i].name %>/*" ] ] }, @@ -176,10 +257,100 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT/*" + "/Prod/PATCH", + "<%= props.paths[i].name %>" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/POST", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/POST", + "<%= props.paths[i].name %>" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.auth !== cnt) { %> + , + <% }%> + <% } %> + <% } %> ] } @@ -189,6 +360,7 @@ }, <% } %> <%if (props.privacy.unauth) { %> + <% cnt = 0 %> "PolicyAPIGW<%= props.apiName %>unauth": { "DependsOn": [ "<%= props.apiName %>" @@ -208,7 +380,9 @@ "execute-api:Invoke" ], "Resource": [ - <%if (props.privacy.unauth === 'rw') { %> + <% for(var i=0; i < props.paths.length; i++) { %> + <%if (props.paths[i].privacy.unauth === 'rw') { %> + <% cnt++ %> { "Fn::Join": [ "", @@ -225,12 +399,38 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*/*" + "/Prod/*", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/*", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.unauth !== cnt) { %> + , + <% }%> <% } %> - <%if (props.privacy.unauth === 'r') { %> + <%if (props.paths[i].privacy.unauth === 'r') { %> + <% cnt++ %> { "Fn::Join": [ "", @@ -247,7 +447,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET/*" + "/Prod/GET", + "<%= props.paths[i].name %>/*" ] ] }, @@ -267,12 +468,101 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD/*" + "/Prod/GET", + "<%= props.paths[i].name %>" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/HEAD", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/HEAD", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.unauth !== cnt) { %> + , + <% }%> <% } %> - <%if (props.privacy.unauth === 'w') { %> + <%if (props.paths[i].privacy.unauth === 'w') { %> + <% cnt++ %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/DELETE", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/DELETE", + "<%= props.paths[i].name %>" + ] + ] + }, { "Fn::Join": [ "", @@ -289,7 +579,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE/*" + "/Prod/PATCH", + "<%= props.paths[i].name %>/*" ] ] }, @@ -309,7 +600,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH/*" + "/Prod/PATCH", + "<%= props.paths[i].name %>" ] ] }, @@ -329,7 +621,8 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST/*" + "/Prod/POST", + "<%= props.paths[i].name %>/*" ] ] }, @@ -349,10 +642,57 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT/*" + "/Prod/POST", + "<%= props.paths[i].name %>" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/Prod/PUT", + "<%= props.paths[i].name %>" ] ] } + <% if (props.privacy.unauth !== cnt) { %> + , + <% }%> + <% } %> <% } %> ] } @@ -457,7 +797,7 @@ } } }, - <%if (!props.privacy.open) { %> + <%if (!props.paths[i].privacy.open) { %> "security": [ { "sigv4": [] @@ -564,7 +904,7 @@ } } }, - <%if (!props.privacy.open) { %> + <%if (!props.paths[i].privacy.open) { %> "security": [ { "sigv4": [] @@ -603,7 +943,7 @@ "type": "aws_proxy" } } - } + }<% if (i !== props.paths.length - 1) { %>,<% } %> <% } %> }, "securityDefinitions": { @@ -685,7 +1025,7 @@ - "DeploymentAPIGW<%= props.apiName %>": { + "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "Description": "The Development stage deployment of your API.", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 616d6a8853..705cf473c0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -1,4 +1,7 @@ -const fs = require('fs'); +const path = require('path'); +const fs = require('fs-extra'); + +const parametersFileName = 'api-params.json'; let serviceMetadata; @@ -24,7 +27,7 @@ function copyCfnTemplate(context, category, options, cfnFilename) { ]; // copy over the files - return context.amplify.copyBatch(context, copyJobs, options); + return context.amplify.copyBatch(context, copyJobs, options, true, false); } function addResource(context, category, service, options) { @@ -32,6 +35,7 @@ function addResource(context, category, service, options) { serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; let { cfnFilename } = serviceMetadata; const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) .then((result) => { @@ -49,6 +53,13 @@ function addResource(context, category, service, options) { cfnFilename = answers.customCfnFile; } copyCfnTemplate(context, category, answers, cfnFilename); + + const parameters = { ...answers }; + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + const jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); } context.amplify.updateamplifyMetaAfterResourceAdd( category, @@ -61,17 +72,54 @@ function addResource(context, category, service, options) { async function updateResource(context, category, service) { + let answers; serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + let { cfnFilename } = serviceMetadata; const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; const { updateWalkthrough } = require(serviceWalkthroughSrc); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); if (!updateWalkthrough) { context.print.error('Update functionality not available for this option'); process.exit(0); } - return updateWalkthrough(context, defaultValuesFilename, serviceMetadata); + return updateWalkthrough(context, defaultValuesFilename, serviceMetadata) + .then((result) => { + const options = {}; + if (result) { + if (result.answers) { + ({ answers } = result); + options.dependsOn = result.dependsOn; + } else { + answers = result; + } + + if (!result.noCfnFile) { + if (answers.customCfnFile) { + cfnFilename = answers.customCfnFile; + } + copyCfnTemplate(context, category, answers, cfnFilename); + const parameters = { ...answers }; + const resourceDirPath = path.join( + projectBackendDirPath, + category, + parameters.resourceName, + ); + fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + const jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + context.amplify.updateamplifyMetaAfterResourceUpdate( + category, + answers.resourceName, + 'dependsOn', + answers.dependsOn, + ); + } + } + }); } module.exports = { addResource, updateResource }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index ea0dd4e742..4a6f0f0caa 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -1,4 +1,11 @@ const inquirer = require('inquirer'); +const pathLib = require('path'); +const fs = require('fs-extra'); + +const category = 'api'; +const serviceName = 'API Gateway'; +const parametersFileName = 'api-params.json'; +const uuid = require('uuid'); async function serviceWalkthrough(context, defaultValuesFilename) { const { amplify } = context; @@ -6,17 +13,123 @@ async function serviceWalkthrough(context, defaultValuesFilename) { const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - let answers = {}; - let dependsOn = {}; + let answers = { + paths: [], + }; const apiNames = await askApiNames(context, allDefaultValues); answers = { ...answers, ...apiNames }; - const pathsAnswer = await askPaths(context); + return pathFlow(context, answers); +} + +async function updateWalkthrough(context, defaultValuesFilename) { + const { amplify } = context; + const { allResources } = await context.amplify.getResourceStatus(); + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = require(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + const resources = allResources + .filter(resource => resource.service === serviceName) + .map(resource => resource.resourceName); + + // There can only be one appsync resource + if (resources.length === 0) { + context.print.error('No REST API resource to update. Please use "amplify add api" command to create a new REST API'); + process.exit(0); + return; + } + + let answers = { + paths: [], + }; + + const question = [{ + name: 'resourceName', + message: 'Please select the REST API you would want to update', + type: 'list', + choices: resources, + }, { + name: 'operation', + message: 'What would you like to do', + type: 'list', + choices: [ + { name: 'Add another path', value: 'add' }, + { name: 'Update path', value: 'update' }, + { name: 'Remove path', value: 'remove' }], + }]; + + const updateApi = await inquirer.prompt(question); + + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + const resourceDirPath = pathLib.join(projectBackendDirPath, category, updateApi.resourceName); + const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); + let parameters; + try { + parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + } catch (e) { + parameters = {}; + } + parameters.resourceName = updateApi.resourceName; + Object.assign(allDefaultValues, parameters); + answers = { ...answers, ...parameters }; + [answers.uuid] = uuid().split('-'); + const pathList = answers.paths.map(path => path.name); + let updatedResult = {}; + + switch (updateApi.operation) { + case 'add': { + updatedResult = pathFlow(context, answers); + break; + } + case 'remove': { + const pathToRemove = await inquirer.prompt({ + name: 'path', + message: 'Please select the path you would want to remove', + type: 'list', + choices: pathList, + }); + + answers.paths = answers.paths.filter(path => path.name !== pathToRemove.path); + + const { dependsOn, functionArns } = findDependsOn(answers.paths); + answers.dependsOn = dependsOn; + answers.functionArns = functionArns; + + updatedResult = { answers, dependsOn }; + break; + } + case 'update': { + const pathToEdit = await inquirer.prompt({ + name: 'path', + message: 'Please select the path you would want to edit', + type: 'list', + choices: pathList, + }); + + const currentPath = answers.paths.find(path => path.name === pathToEdit.path); + answers.paths = answers.paths.filter(path => path.name !== pathToEdit.path); + + updatedResult = pathFlow(context, answers, currentPath); + break; + } + default: { + updatedResult = {}; + } + } + + return updatedResult; +} + +async function pathFlow(context, answers, currentPath) { + const pathsAnswer = await askPaths(context, answers, currentPath); answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; - ({ dependsOn } = pathsAnswer); + const { dependsOn } = pathsAnswer; + + const privacy = {}; + privacy.auth = pathsAnswer.paths.filter(path => path.privacy.auth).length; + privacy.unauth = pathsAnswer.paths.filter(path => path.privacy.unauth).length; - const privacy = await askPrivacy(context, answers); answers = { ...answers, privacy, dependsOn }; if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && @@ -59,12 +172,12 @@ async function askApiNames(context, defaults) { return answer; } -async function askPrivacy(context, answers) { +async function askPrivacy(context, answers, currentPath) { while (true) { const apiAccess = await inquirer.prompt({ name: 'restrict', type: 'confirm', - default: true, + default: !((currentPath && currentPath.open)), message: 'Restrict API access', }); @@ -86,25 +199,24 @@ async function askPrivacy(context, answers) { value: 'protected', }, ], + default: (currentPath && currentPath.privacy && currentPath.privacy.protected) ? 'protected' : 'private', }); const privacy = {}; privacy[answer.privacy] = true; - const roles = { unAuthRoleName: 'unauth-role-name', authRoleName: 'auth-role-name' };// await context.amplify.executeProviderUtils(context, 'awscloudformation', 'staticRoles'); - privacy.unAuthRoleName = roles.unAuthRoleName; - privacy.authRoleName = roles.authRoleName; if (answer.privacy === 'open') { return privacy; } - const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); context.api = { privacy: answer.privacy, }; + const { privacy: { auth: authPrivacy } } = currentPath || { privacy: {} }; + const { privacy: { unauth: unauthPrivacy } } = currentPath || { privacy: {} }; if (answer.privacy === 'private') { - privacy.auth = await askReadWrite('Authenticated', context); + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; // getting requirement satisfaction map @@ -126,8 +238,8 @@ async function askPrivacy(context, answers) { } if (answer.privacy === 'protected') { - privacy.auth = await askReadWrite('Authenticated', context); - privacy.unauth = await askReadWrite('Guest', context); + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; // getting requirement satisfaction map @@ -152,7 +264,7 @@ async function askPrivacy(context, answers) { } } -async function askReadWrite(userType) { +async function askReadWrite(userType, context, privacy = 'r') { while (true) { const answer = await inquirer.prompt({ name: 'permissions', @@ -172,6 +284,7 @@ async function askReadWrite(userType) { value: 'rw', }, ], + default: privacy, }); if (answer.permissions !== 'learn') { @@ -180,10 +293,7 @@ async function askReadWrite(userType) { } } -async function askPaths(context) { - /* TODO: add spinner when - checking if the account had - functions deployed and hide the option from the menu */ +async function askPaths(context, answers, currentPath) { const existingLambdaArns = true; const existingFunctions = functionsExist(context); @@ -207,47 +317,46 @@ async function askPaths(context) { value: 'projectFunction', }); } + + let defaultFunctionType = 'newFunction'; + if (currentPath) { + defaultFunctionType = currentPath.lambdaArn ? 'arn' : 'projectFunction'; + } + const questions = [ { name: 'name', type: 'input', message: 'Please provide a path, e.g. /items', - default: '/items', + default: currentPath ? currentPath.name : '/items', }, { name: 'functionType', type: 'list', message: 'Please select lambda source', choices, + default: defaultFunctionType, }, ]; let addAnotherPath; - const paths = []; - const dependsOn = []; - const functionArns = []; + const paths = [...answers.paths]; do { const answer = await inquirer.prompt(questions); + // TODO: add path validation like awsmobile-cli does let path = { name: answer.name }; let lambda; do { - lambda = await askLambdaSource(context, answer.functionType, answer.name); + lambda = await askLambdaSource(context, answer.functionType, answer.name, currentPath); } while (!lambda); - path = { ...path, ...lambda }; + const privacy = await askPrivacy(context, answers, currentPath); + path = { ...path, ...lambda, privacy }; paths.push(path); - if (lambda.lambdaFunction && !lambda.lambdaArn) { - dependsOn.push({ - category: 'function', - resourceName: lambda.lambdaFunction, - attributes: ['Name', 'Arn'], - }); + if (currentPath) { + break; } - - functionArns.push(lambda); - - addAnotherPath = (await inquirer.prompt({ name: 'anotherPath', type: 'confirm', @@ -256,9 +365,35 @@ async function askPaths(context) { })).anotherPath; } while (addAnotherPath); + const { dependsOn, functionArns } = findDependsOn(paths); + return { paths, dependsOn, functionArns }; } +function findDependsOn(paths) { + // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely + const dependsOn = []; + const functionArns = []; + paths.forEach((path) => { + 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, + }); + } + }); + return { dependsOn, functionArns }; +} + function functionsExist(context) { if (!context.amplify.getProjectDetails().amplifyMeta.function) { return false; @@ -279,10 +414,10 @@ function functionsExist(context) { return true; } -async function askLambdaSource(context, functionType, path) { +async function askLambdaSource(context, functionType, path, currentPath) { switch (functionType) { - case 'arn': return askLambdaArn(context); - case 'projectFunction': return askLambdaFromProject(context); + case 'arn': return askLambdaArn(context, currentPath); + case 'projectFunction': return askLambdaFromProject(context, currentPath); case 'newFunction': return newLambdaFunction(context, path); default: throw new Error('Type not supported'); } @@ -306,7 +441,7 @@ function newLambdaFunction(context, path) { }); } -async function askLambdaFromProject(context) { +async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach((resourceName) => { @@ -320,12 +455,13 @@ async function askLambdaFromProject(context) { type: 'list', message: 'Please select lambda function to invoke by this path', choices: lambdaFunctions, + default: currentPath ? currentPath.lambdaFunction : lambdaFunctions[0], }); return { lambdaFunction: answer.lambdaFunction }; } -async function askLambdaArn(context) { +async function askLambdaArn(context, currentPath) { const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); const regionQuestion = { @@ -333,6 +469,7 @@ async function askLambdaArn(context) { name: 'region', message: 'Select lambda function region', choices: regions, + default: (currentPath && currentPath.lambdaArn) ? currentPath.lambdaArn.split(':')[3] : 'us-west-1', }; const regionAnswer = await inquirer.prompt([regionQuestion]); @@ -358,6 +495,7 @@ async function askLambdaArn(context) { name: 'lambdaChoice', message: 'Please select a Lambda function', choices: lambdaOptions, + default: (currentPath && currentPath.lambdaArn) ? currentPath.lambdaArn : lambdaOptions[0], }; const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); @@ -384,4 +522,4 @@ async function askLambdaArn(context) { // } -module.exports = { serviceWalkthrough }; +module.exports = { serviceWalkthrough, updateWalkthrough }; From a70eca3c390ef23d213ca6b832fa06733fddd138 Mon Sep 17 00:00:00 2001 From: kateglee Date: Wed, 15 Aug 2018 11:25:11 -0700 Subject: [PATCH 067/587] Edit pass complete Minor changes based on AWS style. --- .../provider-utils/supported-services.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index 0c9716887b..a82bb59d51 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -3,7 +3,7 @@ "inputs": [{ "key": "resourceName", "type": "input", - "question": "Provide a friendly name for your resource that will be used to label this category in the project:", + "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]+$", @@ -43,15 +43,15 @@ "type": "list", "question": "What best describes your project:", "options": [{ - "name": "Single object with fields (e.g. “Todo” with ID, name, description)", + "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” & “Comments”)", + "name": "One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)", "value": "many-relationship-schema.graphql" }, { - "name": "Objects with fine-grained security (e.g. Project management app with owner based authorization)", + "name": "Objects with fine-grained access control (e.g., a project management app with owner-based authorization)", "value": "single-object-auth-schema.graphql" } ], @@ -68,7 +68,7 @@ "key": "editorSelection", "type": "list", - "question": "Choose the editor you would want to open the schema in:", + "question": "Choose the editor you want to open the schema in:", "options": [{ "name": "Sublime Text", "value": "sublime" @@ -107,7 +107,7 @@ "type": "list", "question": "Choose a DynamoDB data source option", "options": [{ - "name": "Use DynamoDB table configured in the current Amplify project", + "name": "Use the DynamoDB table configured in the current Amplify project", "value": "currentProject" }, { @@ -131,7 +131,7 @@ "inputs": [ { "key": "apiName", - "question": "Please provide a friendly name for your api?", + "question": "Provide a friendly name for your API:", "required": true }, { @@ -143,7 +143,7 @@ { "key": "lambdaFunction", - "question": "Select lambda function", + "question": "Select the Lambda function", "required": true, "type": "input" } @@ -154,4 +154,4 @@ "cfnFilename": "apigw-cloudformation-template-default.json.ejs", "provider": "awscloudformation" } -} \ No newline at end of file +} From 89d11d5218d347f345e83470b2abedce66e65f30 Mon Sep 17 00:00:00 2001 From: kateglee Date: Wed, 15 Aug 2018 11:28:13 -0700 Subject: [PATCH 068/587] Edit pass complete One minor change based on AWS style. --- .../apigw-cloudformation-template-default.json.ejs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index bc3b0660b2..0a725d5cc0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -1042,8 +1042,8 @@ "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/Prod"]]} }, "ApiName": { - "Description": "Api Friendly name", + "Description": "API Friendly name", "Value": "<%= props.resourceName %>" } } - } \ No newline at end of file + } From 9e6031be8c731b10616a28c2bac8b1dffaa952bd Mon Sep 17 00:00:00 2001 From: kateglee Date: Wed, 15 Aug 2018 11:35:00 -0700 Subject: [PATCH 069/587] Edit pass complete Minor changes based on AWS style. --- .../service-walkthroughs/apigw-walkthrough.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 4a6f0f0caa..434788ea2a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -154,7 +154,7 @@ async function askApiNames(context, defaults) { { name: 'resourceName', type: 'input', - message: 'Please provide a friendly name for your resource that will be used to label this category in the project:', + message: 'Provide a friendly name for your resource to be used as a label for this category in the project:', default: defaults.resourceName, validate: amplify.inputValidation({ validation: { @@ -327,13 +327,13 @@ async function askPaths(context, answers, currentPath) { { name: 'name', type: 'input', - message: 'Please provide a path, e.g. /items', + message: 'Provide a path (e.g., /items)', default: currentPath ? currentPath.name : '/items', }, { name: 'functionType', type: 'list', - message: 'Please select lambda source', + message: 'Choose a Lambda source', choices, default: defaultFunctionType, }, @@ -428,7 +428,7 @@ function newLambdaFunction(context, path) { try { ({ add } = require('amplify-category-function')); } catch (e) { - throw new Error('Function plugin not installed in the CLI. Please install it to use this feature'); + throw new Error('Function plugin not installed in the CLI. You need to install it to use this feature.'); } context.api = { path, @@ -436,7 +436,7 @@ function newLambdaFunction(context, path) { }; return add(context, 'awscloudformation', 'Lambda') .then((resourceName) => { - context.print.success('Succesfully added Lambda function locally'); + context.print.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; }); } @@ -453,7 +453,7 @@ async function askLambdaFromProject(context, currentPath) { const answer = await inquirer.prompt({ name: 'lambdaFunction', type: 'list', - message: 'Please select lambda function to invoke by this path', + message: 'Choose the Lambda function to invoke by this path', choices: lambdaFunctions, default: currentPath ? currentPath.lambdaFunction : lambdaFunctions[0], }); @@ -467,7 +467,7 @@ async function askLambdaArn(context, currentPath) { const regionQuestion = { type: 'list', name: 'region', - message: 'Select lambda function region', + message: 'Specify the Lambda function Region', choices: regions, default: (currentPath && currentPath.lambdaArn) ? currentPath.lambdaArn.split(':')[3] : 'us-west-1', }; @@ -486,7 +486,7 @@ async function askLambdaArn(context, currentPath) { })); if (lambdaOptions.length === 0) { - context.print.error('You do not have any lambda functions configured for the selected region'); + context.print.error('You do not have any Lambda functions configured for the selected Region'); return null; } From 1ef23486ea9581b1701437a049d233dbe6136154 Mon Sep 17 00:00:00 2001 From: kateglee Date: Wed, 15 Aug 2018 11:41:20 -0700 Subject: [PATCH 070/587] Edit pass complete Minor changes based on AWS style. --- .../service-walkthroughs/appSync-walkthrough.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 03d8c6ef08..735e69f90f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -12,7 +12,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const resourceName = resourceAlreadyExists(context); if (resourceName) { - context.print.warning('You already have an appsync API in your project. Please use "amplify update api" command to update your existing AppSync API'); + context.print.warning('You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'); process.exit(0); } @@ -176,7 +176,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const continueQuestion = { type: 'input', name: 'pressKey', - message: `Please correct the errors in schema.graphql and press enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, + message: `Correct the errors in schema.graphql and press Enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, }; await inquirer.prompt(continueQuestion); continue; @@ -206,7 +206,7 @@ async function updateWalkthrough(context) { const backEndDir = context.amplify.pathManager.getBackendDirPath(); resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); } else { - context.print.error('No appsync resource to update. Please use "amplify add api" command to update your existing AppSync API'); + context.print.error('No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'); process.exit(0); return; } @@ -261,10 +261,10 @@ async function askSecurityQuestions(context, parameters) { authResourceName = await add(context); } catch (e) { - context.print.error('Auth plugin not installed in the CLI. Please install it to use this feature'); + context.print.error('Auth plugin not installed in the CLI. You need to install it to use this feature.'); } } else { - context.print.info('Using cognito user pool configured as a part of this project'); + context.print.info('Use a Cognito user pool configured as a part of this project'); } parameters.AuthCognitoUserPoolId = { From aca668296655a78ade965980a1b23c6ee6a91862 Mon Sep 17 00:00:00 2001 From: kateglee Date: Wed, 15 Aug 2018 11:45:52 -0700 Subject: [PATCH 071/587] Edit pass complete Minor changes based on AWS style. --- packages/amplify-category-api/Readme.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/Readme.md b/packages/amplify-category-api/Readme.md index 30ec473c10..035b79eacc 100644 --- a/packages/amplify-category-api/Readme.md +++ b/packages/amplify-category-api/Readme.md @@ -2,10 +2,10 @@ ## Commands Summary -The current set of commands supported by the Amplify API Category Plugin +The following table lists the current set of commands supported by the Amplify API Category Plugin. | Command | Description | | --- | --- | -| amplify api add | Takes you through a CLI flow to add an API resource to your backend | -| amplify api push | Provisions only API cloud resources with the latest local developments | -| amplify api remove | Removes API resource from your local backend which would be removed from the cloud on the next push command | +| amplify api add | Takes you through steps in the CLI to add an API resource to your backend. | +| 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. | From 7ba1a04eb95ae9c43b62aa3975a21de084a0b750 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 13 Aug 2018 16:23:27 -0700 Subject: [PATCH 072/587] Bug fixes Part #1 --- .../awscloudformation/service-walkthroughs/apigw-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 434788ea2a..a6c625cbcc 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -177,7 +177,7 @@ async function askPrivacy(context, answers, currentPath) { const apiAccess = await inquirer.prompt({ name: 'restrict', type: 'confirm', - default: !((currentPath && currentPath.open)), + default: !((currentPath && currentPath.open)) message: 'Restrict API access', }); From 8387da65af14dfe41768d5fe0c5752c7dfc934ec Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 14 Aug 2018 17:25:50 -0700 Subject: [PATCH 073/587] Remove success message from the plugin handlers --- packages/amplify-category-api/commands/api/remove.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index 0a820cb5b0..747cd02773 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -8,7 +8,6 @@ module.exports = { const resourceName = parameters.first; return amplify.removeResource(context, category, resourceName) - .then(() => context.print.success('Successfully removed resource')) .catch((err) => { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); From 323064fc68a6110194e052ef6a406288b510e676 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Wed, 15 Aug 2018 13:28:52 -0700 Subject: [PATCH 074/587] Updating api category and read-write permissions per path (#224) * Updating api category and read-write permissions per path --- .../awscloudformation/service-walkthroughs/apigw-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index a6c625cbcc..434788ea2a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -177,7 +177,7 @@ async function askPrivacy(context, answers, currentPath) { const apiAccess = await inquirer.prompt({ name: 'restrict', type: 'confirm', - default: !((currentPath && currentPath.open)) + default: !((currentPath && currentPath.open)), message: 'Restrict API access', }); From 080795ef40a771ce534884a66fa957e0b7f4f284 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Thu, 16 Aug 2018 13:45:53 -0700 Subject: [PATCH 075/587] Adding path validation (#278) * Adding path validation --- .../service-walkthroughs/apigw-walkthrough.js | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 434788ea2a..0d047f6492 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -107,6 +107,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { choices: pathList, }); + // removing path from paths list const currentPath = answers.paths.find(path => path.name === pathToEdit.path); answers.paths = answers.paths.filter(path => path.name !== pathToEdit.path); @@ -329,6 +330,13 @@ async function askPaths(context, answers, currentPath) { type: 'input', message: 'Provide a path (e.g., /items)', default: currentPath ? currentPath.name : '/items', + validate(value) { + const err = validatePathName(value, answers.paths); + if (err) { + return err; + } + return true; + }, }, { name: 'functionType', @@ -370,6 +378,56 @@ async function askPaths(context, answers, currentPath) { return { paths, dependsOn, functionArns }; } +function validatePathName(name, paths) { + const err = null; + + if (name.length === 0 || name.substring(name.length - 1) === '/') { + return 'Each sub-path must begin with a letter or number.'; + } + + // Set / as a first character of path name + if (name.substring(0, 1) !== '/') { + return 'Path must begin with / e.g. /items'; + } + if (/[^a-zA-Z0-9\-/]/.test(name)) { + return 'You can use the following characters: a-z A-Z 0-9 - /'; + } + + // If the are is something like /asasd//asa must be detected + // Splitting the string with / to find empty sub-path + const split = name.split('/'); + for (let i = 1; i < split.length; i += 1) { + const val = split[i]; + if (val.length === 0) { + return 'Each sub-path must begin with a letter or number'; + } + } + + // Checking if there is already that path created on the API + if (paths.find(path => path.name === name)) { + return 'Path name already exists'; + } + + // Create subpath from the beginning to find a match on existing paths + const findSubPath = (path, subpath) => path.name === subpath; + let subpath = ''; + split.forEach((sub) => { + subpath = `${subpath}/${sub}`; + const subpathFind = paths.find(path => findSubPath(path, subpath)); + if (subpathFind) { + return `A different path already matches this sub-path: ${subpath}`; + } + }); + + // Check if other paths are a subpath of the new path + subpath = paths.find(path => path.name.indexOf(name) === 0); + if (subpath) { + return `An existing path already match with the one provided: ${subpath.name}`; + } + + return err; +} + function findDependsOn(paths) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; From 0f09aedd3befa85332fdaf097fca2e364620dc85 Mon Sep 17 00:00:00 2001 From: elorzafe Date: Mon, 20 Aug 2018 15:20:40 -0700 Subject: [PATCH 076/587] Fix lambda functions limit displayed (#293) * Fix lambda functions limit displayed * Changing dynamo for project region scope for tables * Dynamo table list with paginated results and es lint small fixes --- ...w-cloudformation-template-default.json.ejs | 2 +- .../service-walkthroughs/apigw-walkthrough.js | 40 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 0a725d5cc0..6d01c281bd 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -988,7 +988,7 @@ <%if (props.functionArns) { %> <% for (var i=0; i < props.functionArns.length; i++) { %> - "function<%= props.functionArns[i].lambdaFunction %>Permission<%= props.apiName %>": { + "function<%= props.functionArns[i].lambdaFunction.replace(/[^0-9a-zA-Z]/gi, '') %>Permission<%= props.apiName %>": { "Type": "AWS::Lambda::Permission", "Properties": { "FunctionName": <% if (props.functionArns[i].lambdaArn) {%> "<%= props.functionArns[i].lambdaArn %>", <% } else { %> diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 0d047f6492..1dd46cc041 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -520,26 +520,10 @@ async function askLambdaFromProject(context, currentPath) { } async function askLambdaArn(context, currentPath) { - const regions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getRegions'); - - const regionQuestion = { - type: 'list', - name: 'region', - message: 'Specify the Lambda function Region', - choices: regions, - default: (currentPath && currentPath.lambdaArn) ? currentPath.lambdaArn.split(':')[3] : 'us-west-1', - }; - - const regionAnswer = await inquirer.prompt([regionQuestion]); - - const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions', { region: regionAnswer.region }); + const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions'); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ - value: { - resourceName: lambdaFunction.FunctionName.replace(/[^0-9a-zA-Z]/gi, ''), - Arn: lambdaFunction.FunctionArn, - FunctionName: lambdaFunction.FunctionName, - }, + value: lambdaFunction.FunctionArn, name: `${lambdaFunction.FunctionName} (${lambdaFunction.FunctionArn})`, })); @@ -553,12 +537,26 @@ async function askLambdaArn(context, currentPath) { name: 'lambdaChoice', message: 'Please select a Lambda function', choices: lambdaOptions, - default: (currentPath && currentPath.lambdaArn) ? currentPath.lambdaArn : lambdaOptions[0], + default: (currentPath && currentPath.lambdaArn) ? + `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, }; - const lambdaCloudOptionAnswer = await inquirer.prompt([lambdaCloudOptionQuestion]); + let lambdaOption; + while (!lambdaOption) { + try { + lambdaOption = await inquirer.prompt([lambdaCloudOptionQuestion]); + } catch (err) { + context.print.error('Select a Lambda Function'); + } + } - return { lambdaArn: lambdaCloudOptionAnswer.lambdaChoice.Arn, lambdaFunction: lambdaCloudOptionAnswer.lambdaChoice.FunctionName.replace(/[^0-9a-zA-Z]/gi, '') }; + const lambdaCloudOptionAnswer = + lambdaFunctions.find(lambda => lambda.FunctionArn === lambdaOption.lambdaChoice); + + return { + lambdaArn: lambdaCloudOptionAnswer.FunctionArn, + lambdaFunction: lambdaCloudOptionAnswer.FunctionName, + }; } // function checkIfAuthExists(context) { From 39962e0914fd232a5b246dff0931158112fb4418 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 20 Aug 2018 22:54:17 -0700 Subject: [PATCH 077/587] Implement delete command and improve some language/wordings in the CLI --- .../amplify-category-api/provider-utils/supported-services.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json index a82bb59d51..bc10d9a0c2 100644 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ b/packages/amplify-category-api/provider-utils/supported-services.json @@ -19,7 +19,7 @@ "validation": { "operator": "regex", "value": "^[a-zA-Z0-9]+$", - "onErrorMsg": "You can use the following characters: a-z A-Z 0-9 . - _" + "onErrorMsg": "You can use the following characters: a-z A-Z 0-9" }, "required": true }, From 8bf12156cf979cc0cb62e9bbdf12028e49c30791 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 21 Aug 2018 10:27:29 -0700 Subject: [PATCH 078/587] v0.1.1 --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 527aa58f36..21b88d0ecc 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.0", + "version": "0.1.1", "description": "amplify-cli api plugin", "main": "index.js", "license": "Apache-2.0", @@ -9,9 +9,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.0", - "amplify-category-function": "^0.1.0", - "amplify-category-storage": "^0.1.0", + "amplify-category-auth": "^0.1.1", + "amplify-category-function": "^0.1.1", + "amplify-category-storage": "^0.1.1", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 3d8de927075edcd3e45a14ae1b341c76b3853738 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Tue, 21 Aug 2018 14:31:29 -0700 Subject: [PATCH 079/587] Adding update on help command for api, amplify meta update fix --- packages/amplify-category-api/commands/api.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index f8cd84a61c..2286b94c5d 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -25,6 +25,10 @@ module.exports = { name: 'remove', description: `Removes ${featureName} 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 ${featureName} resource`, + }, ]; context.amplify.showHelp(header, commands); From 45f7299728e8a03fdb073b31fe93e97e1b150d91 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 21 Aug 2018 16:38:00 -0700 Subject: [PATCH 080/587] Add descriptions to the cloudformation stacks --- .../apigw-cloudformation-template-default.json.ejs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 6d01c281bd..d3f655eb10 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -1,5 +1,6 @@ { "AWSTemplateFormatVersion": "2010-09-09", + "Description": "API Gateway resource stack creation using Amplify CLI", <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { From 8933516600a92596f81b52fe51da256c7feadcf2 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Wed, 22 Aug 2018 11:49:07 -0700 Subject: [PATCH 081/587] revert lerna version changes --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 21b88d0ecc..f9eeaf88bf 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.1", + "version": "0.1.0", "description": "amplify-cli api plugin", "main": "index.js", "license": "Apache-2.0", @@ -9,9 +9,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.1", - "amplify-category-function": "^0.1.1", - "amplify-category-storage": "^0.1.1", + "amplify-category-auth": "^0.1.0", + "amplify-category-function": "^0.1.0", + "amplify-category-storage": "^0.1.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", @@ -22,4 +22,4 @@ "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" } -} +} \ No newline at end of file From e870d61a659ab7e205bee4d7115bb77cd45fa597 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 22 Aug 2018 21:14:19 -0700 Subject: [PATCH 082/587] Add licencing info and other relavent meta files to the repo --- packages/amplify-category-api/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f9eeaf88bf..be0a4ad0e7 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -3,6 +3,7 @@ "version": "0.1.0", "description": "amplify-cli api plugin", "main": "index.js", + "author": "Amazon Web Services", "license": "Apache-2.0", "scripts": { "lint": "eslint .", From ba8e2c1d902609eaacca73e0261547616f7f2aac Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 22 Aug 2018 23:34:51 -0700 Subject: [PATCH 083/587] Print schema file path after compilation of GQL schema + readme changes --- packages/amplify-category-api/Readme.md | 2 ++ packages/amplify-category-api/commands/api.js | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/packages/amplify-category-api/Readme.md b/packages/amplify-category-api/Readme.md index 035b79eacc..f0f038b80f 100644 --- a/packages/amplify-category-api/Readme.md +++ b/packages/amplify-category-api/Readme.md @@ -7,5 +7,7 @@ The following table lists the current set of commands supported by the Amplify A | Command | Description | | --- | --- | | amplify api add | Takes you through steps in the CLI to add an API resource to your backend. | +| 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/commands/api.js b/packages/amplify-category-api/commands/api.js index 2286b94c5d..ba661edfae 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -29,6 +29,10 @@ module.exports = { name: 'update', description: `Takes you through steps in the CLI to update an ${featureName} resource`, }, + { + name: 'gql-compile', + description: `Compiles your GraphQL schema and generates a corresponding cloudformation template`, + }, ]; context.amplify.showHelp(header, commands); From f8a0b609f18c8d062b939fc9d05c2651d8b8647b Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:17:39 -0700 Subject: [PATCH 084/587] Initial release - amplify-category-analytics@0.1.4 - amplify-category-api@0.1.4 - amplify-category-auth@0.1.4 - amplify-category-function@0.1.4 - amplify-category-hosting@0.1.4 - amplify-category-notifications@0.1.4 - amplify-category-storage@0.1.4 - @aws-amplify/cli@0.1.4 - amplify-codegen@0.1.4 - amplify-frontend-android@0.1.4 - amplify-frontend-ios@0.1.4 - amplify-frontend-javascript@0.1.4 - amplify-provider-awscloudformation@0.1.4 - graphql-appsync-transformer@1.0.4 - graphql-auth-transformer@1.0.4 - graphql-connection-transformer@1.0.4 - graphql-dynamodb-transformer@1.0.4 - graphql-elasticsearch-transformer@1.0.4 - graphql-mapping-template@1.0.4 - graphql-transformer-common@1.0.4 - graphql-transformer-core@1.0.4 - graphql-transformers-e2e-tests@1.0.4 - graphql-versioned-transformer@1.0.4 --- packages/amplify-category-api/CHANGELOG.md | 36 ++++++++++++++++++++++ packages/amplify-category-api/package.json | 10 +++--- 2 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 packages/amplify-category-api/CHANGELOG.md diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md new file mode 100644 index 0000000000..eb4f89bfca --- /dev/null +++ b/packages/amplify-category-api/CHANGELOG.md @@ -0,0 +1,36 @@ +# Change Log + +All notable changes to this project will be documented in this file. +See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + + +## 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 index be0a4ad0e7..a86f92dd44 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.0", + "version": "0.1.4", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.0", - "amplify-category-function": "^0.1.0", - "amplify-category-storage": "^0.1.0", + "amplify-category-auth": "^0.1.4", + "amplify-category-function": "^0.1.4", + "amplify-category-storage": "^0.1.4", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", @@ -23,4 +23,4 @@ "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" } -} \ No newline at end of file +} From 6909fece650a3c6c1cb87978c349770fa2aa99a2 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:23:51 -0700 Subject: [PATCH 085/587] Initial release - amplify-category-analytics@0.1.5 - amplify-category-api@0.1.5 - amplify-category-auth@0.1.5 - amplify-category-function@0.1.5 - amplify-category-hosting@0.1.5 - amplify-category-notifications@0.1.5 - amplify-category-storage@0.1.5 - @aws-amplify/cli@0.1.5 - amplify-codegen@0.1.5 - amplify-frontend-android@0.1.5 - amplify-frontend-ios@0.1.5 - amplify-frontend-javascript@0.1.5 - amplify-provider-awscloudformation@0.1.5 - graphql-appsync-transformer@1.0.5 - graphql-auth-transformer@1.0.5 - graphql-connection-transformer@1.0.5 - graphql-dynamodb-transformer@1.0.5 - graphql-elasticsearch-transformer@1.0.5 - graphql-mapping-template@1.0.5 - graphql-transformer-common@1.0.5 - graphql-transformer-core@1.0.5 - graphql-transformers-e2e-tests@1.0.5 - graphql-versioned-transformer@1.0.5 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index eb4f89bfca..5e104477b0 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a86f92dd44..846b6bf541 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.4", + "version": "0.1.5", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.4", - "amplify-category-function": "^0.1.4", - "amplify-category-storage": "^0.1.4", + "amplify-category-auth": "^0.1.5", + "amplify-category-function": "^0.1.5", + "amplify-category-storage": "^0.1.5", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From d7d3554f8787e8c29d9753a7f4a426463bd74a36 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:25:21 -0700 Subject: [PATCH 086/587] Initial release - amplify-category-analytics@0.1.6 - amplify-category-api@0.1.6 - amplify-category-auth@0.1.6 - amplify-category-function@0.1.6 - amplify-category-hosting@0.1.6 - amplify-category-notifications@0.1.6 - amplify-category-storage@0.1.6 - @aws-amplify/cli@0.1.6 - amplify-codegen@0.1.6 - amplify-frontend-android@0.1.6 - amplify-frontend-ios@0.1.6 - amplify-frontend-javascript@0.1.6 - amplify-provider-awscloudformation@0.1.6 - graphql-appsync-transformer@1.0.6 - graphql-auth-transformer@1.0.6 - graphql-connection-transformer@1.0.6 - graphql-dynamodb-transformer@1.0.6 - graphql-elasticsearch-transformer@1.0.6 - graphql-mapping-template@1.0.6 - graphql-transformer-common@1.0.6 - graphql-transformer-core@1.0.6 - graphql-transformers-e2e-tests@1.0.6 - graphql-versioned-transformer@1.0.6 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5e104477b0..1c4dba4df4 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 846b6bf541..92d19feb1a 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.5", + "version": "0.1.6", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.5", - "amplify-category-function": "^0.1.5", - "amplify-category-storage": "^0.1.5", + "amplify-category-auth": "^0.1.6", + "amplify-category-function": "^0.1.6", + "amplify-category-storage": "^0.1.6", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 0121353a08b59488e7d4c92588ee85016e812647 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:30:04 -0700 Subject: [PATCH 087/587] Initial release - amplify-category-analytics@0.1.7 - amplify-category-api@0.1.7 - amplify-category-auth@0.1.7 - amplify-category-function@0.1.7 - amplify-category-hosting@0.1.7 - amplify-category-notifications@0.1.7 - amplify-category-storage@0.1.7 - @aws-amplify/cli@0.1.7 - amplify-codegen@0.1.7 - amplify-frontend-android@0.1.7 - amplify-frontend-ios@0.1.7 - amplify-frontend-javascript@0.1.7 - amplify-provider-awscloudformation@0.1.7 - graphql-appsync-transformer@1.0.7 - graphql-auth-transformer@1.0.7 - graphql-connection-transformer@1.0.7 - graphql-dynamodb-transformer@1.0.7 - graphql-elasticsearch-transformer@1.0.7 - graphql-mapping-template@1.0.7 - graphql-transformer-common@1.0.7 - graphql-transformer-core@1.0.7 - graphql-transformers-e2e-tests@1.0.7 - graphql-versioned-transformer@1.0.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1c4dba4df4..f9da072af2 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 92d19feb1a..9d72deffae 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.6", + "version": "0.1.7", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.6", - "amplify-category-function": "^0.1.6", - "amplify-category-storage": "^0.1.6", + "amplify-category-auth": "^0.1.7", + "amplify-category-function": "^0.1.7", + "amplify-category-storage": "^0.1.7", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 9c42b5d9f1cd8ccd2bd5d8d13899a7613a990340 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:32:33 -0700 Subject: [PATCH 088/587] Initial release - amplify-category-analytics@0.1.8 - amplify-category-api@0.1.8 - amplify-category-auth@0.1.8 - amplify-category-function@0.1.8 - amplify-category-hosting@0.1.8 - amplify-category-notifications@0.1.8 - amplify-category-storage@0.1.8 - @aws-amplify/cli@0.1.8 - amplify-codegen@0.1.8 - amplify-frontend-android@0.1.8 - amplify-frontend-ios@0.1.8 - amplify-frontend-javascript@0.1.8 - amplify-provider-awscloudformation@0.1.8 - graphql-appsync-transformer@1.0.8 - graphql-auth-transformer@1.0.8 - graphql-connection-transformer@1.0.8 - graphql-dynamodb-transformer@1.0.8 - graphql-elasticsearch-transformer@1.0.8 - graphql-mapping-template@1.0.8 - graphql-transformer-common@1.0.8 - graphql-transformer-core@1.0.8 - graphql-transformers-e2e-tests@1.0.8 - graphql-versioned-transformer@1.0.8 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f9da072af2..710399c3c6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9d72deffae..9273fb74cb 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.7", + "version": "0.1.8", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.7", - "amplify-category-function": "^0.1.7", - "amplify-category-storage": "^0.1.7", + "amplify-category-auth": "^0.1.8", + "amplify-category-function": "^0.1.8", + "amplify-category-storage": "^0.1.8", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From a02984883e4df2deac99fd4dd5ce0c2b60d7dd75 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:34:32 -0700 Subject: [PATCH 089/587] Initial release - amplify-category-analytics@0.1.9 - amplify-category-api@0.1.9 - amplify-category-auth@0.1.9 - amplify-category-function@0.1.9 - amplify-category-hosting@0.1.9 - amplify-category-notifications@0.1.9 - amplify-category-storage@0.1.9 - @aws-amplify/cli@0.1.9 - amplify-codegen@0.1.9 - amplify-frontend-android@0.1.9 - amplify-frontend-ios@0.1.9 - amplify-frontend-javascript@0.1.9 - amplify-provider-awscloudformation@0.1.9 - graphql-appsync-transformer@1.0.9 - graphql-auth-transformer@1.0.9 - graphql-connection-transformer@1.0.9 - graphql-dynamodb-transformer@1.0.9 - graphql-elasticsearch-transformer@1.0.9 - graphql-mapping-template@1.0.9 - graphql-transformer-common@1.0.9 - graphql-transformer-core@1.0.9 - graphql-transformers-e2e-tests@1.0.9 - graphql-versioned-transformer@1.0.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 710399c3c6..03e90ec637 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9273fb74cb..ddf7b39707 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.8", + "version": "0.1.9", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.8", - "amplify-category-function": "^0.1.8", - "amplify-category-storage": "^0.1.8", + "amplify-category-auth": "^0.1.9", + "amplify-category-function": "^0.1.9", + "amplify-category-storage": "^0.1.9", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From b945a74adafcf00a9f932c886cce625a3a824032 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:38:11 -0700 Subject: [PATCH 090/587] Initial release - amplify-category-analytics@0.1.11 - amplify-category-api@0.1.11 - amplify-category-auth@0.1.11 - amplify-category-function@0.1.11 - amplify-category-hosting@0.1.11 - amplify-category-notifications@0.1.11 - amplify-category-storage@0.1.11 - @aws-amplify/cli@0.1.11 - amplify-codegen@0.1.11 - amplify-frontend-android@0.1.10 - amplify-frontend-ios@0.1.10 - amplify-frontend-javascript@0.1.10 - amplify-provider-awscloudformation@0.1.10 - graphql-appsync-transformer@1.0.10 - graphql-auth-transformer@1.0.10 - graphql-connection-transformer@1.0.10 - graphql-dynamodb-transformer@1.0.10 - graphql-elasticsearch-transformer@1.0.10 - graphql-mapping-template@1.0.10 - graphql-transformer-common@1.0.10 - graphql-transformer-core@1.0.10 - graphql-transformers-e2e-tests@1.0.10 - graphql-versioned-transformer@1.0.10 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 03e90ec637..427c8e3220 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ddf7b39707..ed244d62c1 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.9", + "version": "0.1.11", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.9", - "amplify-category-function": "^0.1.9", - "amplify-category-storage": "^0.1.9", + "amplify-category-auth": "^0.1.11", + "amplify-category-function": "^0.1.11", + "amplify-category-storage": "^0.1.11", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 96f04ff59bd6943867acbd5a5078bdf0cf707102 Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:43:09 -0700 Subject: [PATCH 091/587] Initial release - amplify-category-analytics@0.1.12 - amplify-category-api@0.1.12 - amplify-category-auth@0.1.12 - amplify-category-function@0.1.12 - amplify-category-hosting@0.1.12 - amplify-category-notifications@0.1.12 - amplify-category-storage@0.1.12 - @aws-amplify/cli@0.1.12 - amplify-codegen@0.1.12 - amplify-frontend-android@0.1.11 - amplify-frontend-ios@0.1.11 - amplify-frontend-javascript@0.1.11 - amplify-provider-awscloudformation@0.1.11 - graphql-appsync-transformer@1.0.11 - graphql-auth-transformer@1.0.11 - graphql-connection-transformer@1.0.11 - graphql-dynamodb-transformer@1.0.11 - graphql-elasticsearch-transformer@1.0.11 - graphql-mapping-template@1.0.11 - graphql-transformer-common@1.0.11 - graphql-transformer-core@1.0.11 - graphql-transformers-e2e-tests@1.0.11 - graphql-versioned-transformer@1.0.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 427c8e3220..3983eea721 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ed244d62c1..0bae300226 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.11", + "version": "0.1.12", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.11", - "amplify-category-function": "^0.1.11", - "amplify-category-storage": "^0.1.11", + "amplify-category-auth": "^0.1.12", + "amplify-category-function": "^0.1.12", + "amplify-category-storage": "^0.1.12", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 14ae5fc41586eab2c5ff842219d334695bb8c45b Mon Sep 17 00:00:00 2001 From: Rodriguez Elorza Date: Thu, 23 Aug 2018 12:45:32 -0700 Subject: [PATCH 092/587] Initial release - amplify-category-analytics@0.1.13 - amplify-category-api@0.1.13 - amplify-category-auth@0.1.13 - amplify-category-function@0.1.13 - amplify-category-hosting@0.1.13 - amplify-category-notifications@0.1.13 - amplify-category-storage@0.1.13 - @aws-amplify/cli@0.1.13 - amplify-codegen@0.1.13 - amplify-frontend-android@0.1.12 - amplify-frontend-ios@0.1.12 - amplify-frontend-javascript@0.1.12 - amplify-provider-awscloudformation@0.1.12 - graphql-appsync-transformer@1.0.12 - graphql-auth-transformer@1.0.12 - graphql-connection-transformer@1.0.12 - graphql-dynamodb-transformer@1.0.12 - graphql-elasticsearch-transformer@1.0.12 - graphql-mapping-template@1.0.12 - graphql-transformer-common@1.0.12 - graphql-transformer-core@1.0.12 - graphql-transformers-e2e-tests@1.0.12 - graphql-versioned-transformer@1.0.12 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3983eea721..3eeae05398 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0bae300226..a5510d4888 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.12", + "version": "0.1.13", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.12", - "amplify-category-function": "^0.1.12", - "amplify-category-storage": "^0.1.12", + "amplify-category-auth": "^0.1.13", + "amplify-category-function": "^0.1.13", + "amplify-category-storage": "^0.1.13", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From dd7e9deb6f523dcef693600d74aaf9f7d31f868e Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 24 Aug 2018 14:42:25 -0700 Subject: [PATCH 093/587] Fixes lambda invoke issue + better validation error if not working inside amplify project --- packages/amplify-category-api/commands/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index ba661edfae..eb8f48a5f2 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -31,7 +31,7 @@ module.exports = { }, { name: 'gql-compile', - description: `Compiles your GraphQL schema and generates a corresponding cloudformation template`, + description: 'Compiles your GraphQL schema and generates a corresponding cloudformation template', }, ]; From d51b313764f769eb6f1332de8ddd69b5305993f2 Mon Sep 17 00:00:00 2001 From: Paris Date: Thu, 6 Sep 2018 11:19:02 -0700 Subject: [PATCH 094/587] More user friendly gql-compile errors from cli --- packages/amplify-category-api/commands/api/gql-compile.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 3c1f0941b1..b6d7d6dd99 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -3,6 +3,11 @@ const subcommand = 'gql-compile'; module.exports = { name: subcommand, run: async (context) => { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); + try { + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); + } catch (err) { + context.print.info(err.stack); + context.print.error(err.message); + } }, }; From 204afeff2ee9e70412f5fe13c9ee3ad522e91f87 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Thu, 13 Sep 2018 11:30:57 -0700 Subject: [PATCH 095/587] circle ci fix --- packages/amplify-category-api/.eslintignore | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 packages/amplify-category-api/.eslintignore diff --git a/packages/amplify-category-api/.eslintignore b/packages/amplify-category-api/.eslintignore new file mode 100644 index 0000000000..1980e044ef --- /dev/null +++ b/packages/amplify-category-api/.eslintignore @@ -0,0 +1,4 @@ +node_modules +__tests__ +__mockes__ +coverage \ No newline at end of file From bfab1307849a95efe5316a39eb53e8dd01901b4b Mon Sep 17 00:00:00 2001 From: Paris Date: Wed, 12 Sep 2018 10:54:18 -0700 Subject: [PATCH 096/587] Updating @auth sample schema to not protect queries/mutations as expected --- .../appsync-schemas/single-object-auth-schema.graphql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql index c34b0e58d8..16a419d6f3 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql @@ -1,8 +1,8 @@ type Task @model @auth(rules: [ - {allow: groups, groups: ["Managers"], mutations: [create, update, delete]}, - {allow: groups, groups: ["Employees"], queries: [get, list]} + {allow: groups, groups: ["Managers"], queries: null, mutations: [create, update, delete]}, + {allow: groups, groups: ["Employees"], queries: [get, list], mutations: null} ]) { id: ID! From 24b7640fd3d6805610986c2bd034b6529d482d08 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 1 Oct 2018 16:08:29 -0700 Subject: [PATCH 097/587] Ability to add external AppSync API to an Amplify project as a part of the codegen add command --- .../amplify-category-api/commands/api/remove.js | 13 +++++++++++++ .../service-walkthroughs/appSync-walkthrough.js | 8 ++++++++ 2 files changed, 21 insertions(+) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index 747cd02773..cc861760cd 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -1,5 +1,7 @@ +const path = require('path'); const subcommand = 'remove'; const category = 'api'; +const gqlConfigFilename = '.graphqlconfig.yml'; module.exports = { name: subcommand, @@ -8,6 +10,17 @@ module.exports = { const resourceName = parameters.first; return amplify.removeResource(context, category, resourceName) + .then((resourceValues) => { + if(resourceValues.service === "AppSync") { + const {projectPath} = amplify.getProjectDetails().projectConfig; + + const gqlConfigFile = path.normalize(path.join( + projectPath, + gqlConfigFilename + )); + context.filesystem.remove(gqlConfigFile); + } + }) .catch((err) => { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 735e69f90f..b595063c1c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -6,6 +6,7 @@ const category = 'api'; const serviceName = 'AppSync'; const parametersFileName = 'parameters.json'; const schemaFileName = 'schema.graphql'; +const providerName = 'awscloudformation' async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { @@ -183,6 +184,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat } notCompiled = false; } + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; }); } @@ -199,9 +201,15 @@ async function updateWalkthrough(context) { let resourceDir; let resourceName; const resources = allResources.filter(resource => resource.service === 'AppSync'); + // There can only be one appsync resource if (resources.length > 0) { const resource = resources[0]; + if(resource.provider !== providerName) { + // TODO: Move message string to seperate file + context.print.error(`The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - ${resource.resourceName}`); + throw new Error("Error updating resource"); + } ({ resourceName } = resource); const backEndDir = context.amplify.pathManager.getBackendDirPath(); resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); From 6beaccc8dec1351c6ec2fec9d1e6c34fdd199a6f Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 1 Oct 2018 16:25:36 -0700 Subject: [PATCH 098/587] Fix lint errors --- packages/amplify-category-api/commands/api/remove.js | 7 ++++--- .../service-walkthroughs/appSync-walkthrough.js | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index cc861760cd..ed6d3abfd2 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -1,4 +1,5 @@ const path = require('path'); + const subcommand = 'remove'; const category = 'api'; const gqlConfigFilename = '.graphqlconfig.yml'; @@ -11,12 +12,12 @@ module.exports = { return amplify.removeResource(context, category, resourceName) .then((resourceValues) => { - if(resourceValues.service === "AppSync") { - const {projectPath} = amplify.getProjectDetails().projectConfig; + if (resourceValues.service === 'AppSync') { + const { projectPath } = amplify.getProjectDetails().projectConfig; const gqlConfigFile = path.normalize(path.join( projectPath, - gqlConfigFilename + gqlConfigFilename, )); context.filesystem.remove(gqlConfigFile); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b595063c1c..8a17ee9c82 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -6,7 +6,7 @@ const category = 'api'; const serviceName = 'AppSync'; const parametersFileName = 'parameters.json'; const schemaFileName = 'schema.graphql'; -const providerName = 'awscloudformation' +const providerName = 'awscloudformation'; async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { @@ -184,7 +184,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat } notCompiled = false; } - + return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; }); } @@ -205,10 +205,10 @@ async function updateWalkthrough(context) { // There can only be one appsync resource if (resources.length > 0) { const resource = resources[0]; - if(resource.provider !== providerName) { + if (resource.provider !== providerName) { // TODO: Move message string to seperate file context.print.error(`The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - ${resource.resourceName}`); - throw new Error("Error updating resource"); + throw new Error('Error updating resource'); } ({ resourceName } = resource); const backEndDir = context.amplify.pathManager.getBackendDirPath(); From 5bf66945b9ed43a1df4552fc71d165d7ed85ae64 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 2 Oct 2018 10:49:42 -0700 Subject: [PATCH 099/587] Fix provider check when compiling GraphQL schema --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 8a17ee9c82..d4261677c9 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -205,7 +205,7 @@ async function updateWalkthrough(context) { // There can only be one appsync resource if (resources.length > 0) { const resource = resources[0]; - if (resource.provider !== providerName) { + if (resource.providerPlugin !== providerName) { // TODO: Move message string to seperate file context.print.error(`The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - ${resource.resourceName}`); throw new Error('Error updating resource'); From aa1cc0fa1f6b8339a41fcc9a4cd4666f08264178 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 2 Oct 2018 11:07:15 -0700 Subject: [PATCH 100/587] Fix error messages --- packages/amplify-category-api/commands/api/update.js | 3 +-- .../service-walkthroughs/appSync-walkthrough.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index a1b4058590..27585e1fa7 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -22,8 +22,7 @@ module.exports = { }) .then(() => context.print.success('Successfully updated resource')) .catch((err) => { - context.print.info(err.stack); - context.print.error('There was an error updating the API resource'); + context.print.error(err.message); }); }, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index d4261677c9..03fe8e0a27 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -207,8 +207,7 @@ async function updateWalkthrough(context) { const resource = resources[0]; if (resource.providerPlugin !== providerName) { // TODO: Move message string to seperate file - context.print.error(`The selected resource is not managed using AWS Cloudformation. Please use the AWS AppSync Console to make updates to your API - ${resource.resourceName}`); - throw new Error('Error updating resource'); + 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); const backEndDir = context.amplify.pathManager.getBackendDirPath(); From c524adfbc17130e62f71dcd30bca70fef68a2f98 Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Fri, 5 Oct 2018 11:45:22 -0700 Subject: [PATCH 101/587] chore: version bumps (#265) Bumped the versions of packages in monorepo to reflect the current versions in npm --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a5510d4888..1d0c7f66bd 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.13", + "version": "0.1.27", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.13", - "amplify-category-function": "^0.1.13", - "amplify-category-storage": "^0.1.13", + "amplify-category-auth": "^0.1.27", + "amplify-category-function": "^0.1.27", + "amplify-category-storage": "^0.1.27", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 69f9fac2df751fde6ef06bc08b2481831058edbb Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 12 Oct 2018 21:55:27 +0000 Subject: [PATCH 102/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.28-beta.0 - amplify-category-api@0.1.28-beta.0 - amplify-category-auth@0.1.28-beta.0 - amplify-category-function@0.1.28-beta.0 - amplify-category-hosting@0.1.28-beta.0 - amplify-category-interactions@0.1.28-beta.0 - amplify-category-notifications@0.1.28-beta.0 - amplify-category-storage@0.1.28-beta.0 - @aws-amplify/cli@0.1.28-beta.0 - amplify-codegen@0.1.28-beta.0 - amplify-frontend-android@0.1.28-beta.0 - amplify-frontend-ios@0.1.28-beta.0 - amplify-frontend-javascript@0.1.28-beta.0 - amplify-graphql-docs-generator@0.1.28-beta.0 - amplify-provider-awscloudformation@0.1.28-beta.0 - graphql-appsync-transformer@1.0.28-beta.0 - graphql-auth-transformer@1.0.28-beta.0 - graphql-connection-transformer@1.0.28-beta.0 - graphql-dynamodb-transformer@1.0.28-beta.0 - graphql-elasticsearch-transformer@1.0.28-beta.0 - graphql-mapping-template@1.0.28-beta.0 - graphql-transformer-common@1.0.28-beta.0 - graphql-transformer-core@1.0.28-beta.0 - graphql-transformers-e2e-tests@1.0.28-beta.0 - graphql-versioned-transformer@1.0.28-beta.0 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3eeae05398..f41d7058a1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1d0c7f66bd..cd6cd2e2d4 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.27", + "version": "0.1.28-beta.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.27", - "amplify-category-function": "^0.1.27", - "amplify-category-storage": "^0.1.27", + "amplify-category-auth": "^0.1.28-beta.0", + "amplify-category-function": "^0.1.28-beta.0", + "amplify-category-storage": "^0.1.28-beta.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 28cb82e6e70760d0fa88a45fa082d17c7603865c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 18 Oct 2018 23:05:23 +0000 Subject: [PATCH 103/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.28 - amplify-category-api@0.1.28 - amplify-category-auth@0.1.28 - amplify-category-function@0.1.28 - amplify-category-hosting@0.1.28 - amplify-category-interactions@0.1.28 - amplify-category-notifications@0.1.28 - amplify-category-storage@0.1.28 - @aws-amplify/cli@0.1.28 - amplify-codegen@0.1.28 - amplify-frontend-android@0.1.28 - amplify-frontend-ios@0.1.28 - amplify-frontend-javascript@0.1.28 - amplify-graphql-docs-generator@0.1.28 - amplify-provider-awscloudformation@0.1.28 - graphql-appsync-transformer@1.0.28 - graphql-auth-transformer@1.0.28 - graphql-connection-transformer@1.0.28 - graphql-dynamodb-transformer@1.0.28 - graphql-elasticsearch-transformer@1.0.28 - graphql-mapping-template@1.0.28 - graphql-transformer-common@1.0.28 - graphql-transformer-core@1.0.28 - graphql-transformers-e2e-tests@1.0.28 - graphql-versioned-transformer@1.0.28 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f41d7058a1..965e82efc6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index cd6cd2e2d4..a8cd3f7eb9 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.28-beta.0", + "version": "0.1.28", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.28-beta.0", - "amplify-category-function": "^0.1.28-beta.0", - "amplify-category-storage": "^0.1.28-beta.0", + "amplify-category-auth": "^0.1.28", + "amplify-category-function": "^0.1.28", + "amplify-category-storage": "^0.1.28", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From d6c7bef7e37293c76552eda9193d22c17e3aec90 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 23 Oct 2018 18:47:29 +0000 Subject: [PATCH 104/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.29-beta.0 - amplify-category-api@0.1.29-beta.0 - amplify-category-auth@0.1.29-beta.0 - amplify-category-function@0.1.29-beta.0 - amplify-category-hosting@0.1.29-beta.0 - amplify-category-interactions@0.1.29-beta.0 - amplify-category-notifications@0.1.29-beta.0 - amplify-category-storage@0.1.29-beta.0 - @aws-amplify/cli@0.1.29-beta.0 - amplify-codegen@0.1.29-beta.0 - amplify-frontend-android@0.1.29-beta.0 - amplify-frontend-ios@0.1.29-beta.0 - amplify-frontend-javascript@0.1.29-beta.0 - amplify-graphql-docs-generator@0.1.29-beta.0 - amplify-provider-awscloudformation@0.1.29-beta.0 - graphql-appsync-transformer@1.0.29-beta.0 - graphql-auth-transformer@1.0.29-beta.0 - graphql-connection-transformer@1.0.29-beta.0 - graphql-dynamodb-transformer@1.0.29-beta.0 - graphql-elasticsearch-transformer@1.0.29-beta.0 - graphql-http-transformer@1.0.13-beta.0 - graphql-mapping-template@1.0.29-beta.0 - graphql-transformer-common@1.0.29-beta.0 - graphql-transformer-core@1.0.29-beta.0 - graphql-transformers-e2e-tests@1.0.29-beta.0 - graphql-versioned-transformer@1.0.29-beta.0 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 965e82efc6..74633c4c19 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a8cd3f7eb9..ee09b74ea3 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.28", + "version": "0.1.29-beta.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.28", - "amplify-category-function": "^0.1.28", - "amplify-category-storage": "^0.1.28", + "amplify-category-auth": "^0.1.29-beta.0", + "amplify-category-function": "^0.1.29-beta.0", + "amplify-category-storage": "^0.1.29-beta.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 2bb161ceb08ec83973748df51da800c300fdf48c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 23 Oct 2018 23:42:22 +0000 Subject: [PATCH 105/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.29 - amplify-category-api@0.1.29 - amplify-category-auth@0.1.29 - amplify-category-function@0.1.29 - amplify-category-hosting@0.1.29 - amplify-category-interactions@0.1.29 - amplify-category-notifications@0.1.29 - amplify-category-storage@0.1.29 - @aws-amplify/cli@0.1.29 - amplify-codegen@0.1.29 - amplify-frontend-android@0.1.29 - amplify-frontend-ios@0.1.29 - amplify-frontend-javascript@0.1.29 - amplify-graphql-docs-generator@0.1.29 - amplify-provider-awscloudformation@0.1.29 - graphql-appsync-transformer@1.0.29 - graphql-auth-transformer@1.0.29 - graphql-connection-transformer@1.0.29 - graphql-dynamodb-transformer@1.0.29 - graphql-elasticsearch-transformer@1.0.29 - graphql-http-transformer@1.0.13 - graphql-mapping-template@1.0.29 - graphql-transformer-common@1.0.29 - graphql-transformer-core@1.0.29 - graphql-transformers-e2e-tests@1.0.29 - graphql-versioned-transformer@1.0.29 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 74633c4c19..a340114dbc 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ee09b74ea3..08628aa963 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.29-beta.0", + "version": "0.1.29", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.29-beta.0", - "amplify-category-function": "^0.1.29-beta.0", - "amplify-category-storage": "^0.1.29-beta.0", + "amplify-category-auth": "^0.1.29", + "amplify-category-function": "^0.1.29", + "amplify-category-storage": "^0.1.29", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From a0011e61f15fecadae7dbb6fb2acee2a6ebb39dc Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 29 Oct 2018 11:44:06 -0700 Subject: [PATCH 106/587] change cloudfront viewProtocolPolicy --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a8cd3f7eb9..af7ab43770 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -15,7 +15,7 @@ "amplify-category-storage": "^0.1.28", "eslint": "^4.9.0", "fs-extra": "^6.0.1", - "inquirer": "^3.2.1", + "inquirer": "^6.0.0", "moment": "^2.22.2", "uuid": "^2.0.3" }, From a13b19ab66cc7cff5044ca495214408f322d3bd9 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 2 Nov 2018 10:49:35 -0700 Subject: [PATCH 107/587] feat: add option to open AppSync console using the CLI (#386) * feat: add option to open AppSync console using the CLI * fix: fixes based on PR comments --- .../commands/api/console.js | 20 +++++++++++++- packages/amplify-category-api/index.js | 5 ++-- packages/amplify-category-api/package.json | 3 ++- .../provider-utils/awscloudformation/index.js | 17 +++++++++++- .../appSync-walkthrough.js | 26 ++++++++++++++++++- 5 files changed, 65 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index a3febfb5c8..2942741c43 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -1,9 +1,27 @@ +const fs = require('fs'); + const subcommand = 'console'; const category = 'api'; +const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); module.exports = { name: subcommand, run: async (context) => { - context.print.info(`to be implemented: ${category} ${subcommand}`); + const { amplify } = context; + return amplify.serviceSelectionPrompt(context, category, servicesMetadata) + .then((result) => { + const providerController = + require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + + return providerController.console(context, result.service); + }) + .catch((err) => { + context.print.error('Error opening console.'); + context.print.info(err.message); + }); }, }; diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 5766fe2f66..64bc2bfe8f 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -1,7 +1,8 @@ -const category = 'api'; +const { run } = require('./commands/api/console'); + async function console(context) { - context.print.info(`to be implemented: ${category} console`); + await run(context); } module.exports = { diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 08628aa963..6f49809820 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,7 +17,8 @@ "fs-extra": "^6.0.1", "inquirer": "^3.2.1", "moment": "^2.22.2", - "uuid": "^2.0.3" + "uuid": "^2.0.3", + "opn": "^5.3.0" }, "devDependencies": { "eslint-config-airbnb-base": "^12.1.0", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 705cf473c0..dd6ff02dd6 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -30,6 +30,21 @@ function copyCfnTemplate(context, category, options, cfnFilename) { return context.amplify.copyBatch(context, copyJobs, options, true, false); } + +function console(context, service) { + serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + const { serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { openConsole } = require(serviceWalkthroughSrc); + + if (!openConsole) { + context.print.error('Opening console functionality not available for this option'); + process.exit(0); + } + + return openConsole(context); +} + function addResource(context, category, service, options) { let answers; serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; @@ -122,4 +137,4 @@ async function updateResource(context, category, service) { }); } -module.exports = { addResource, updateResource }; +module.exports = { addResource, updateResource, console }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 03fe8e0a27..4462d937b9 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,6 +1,7 @@ const inquirer = require('inquirer'); const fs = require('fs-extra'); const path = require('path'); +const opn = require('opn'); const category = 'api'; const serviceName = 'AppSync'; @@ -8,6 +9,29 @@ const parametersFileName = 'parameters.json'; const schemaFileName = 'schema.graphql'; const providerName = 'awscloudformation'; +function openConsole(context) { + const amplifyMeta = context.amplify.getProjectMeta(); + const categoryAmplifyMeta = amplifyMeta[category]; + let appSyncMeta; + Object.keys((categoryAmplifyMeta)).forEach((resourceName) => { + if (categoryAmplifyMeta[resourceName].service === serviceName && + categoryAmplifyMeta[resourceName].output) { + appSyncMeta = categoryAmplifyMeta[resourceName].output; + } + }); + + + if (appSyncMeta) { + const { GraphQLAPIIdOutput } = appSyncMeta; + const { Region } = amplifyMeta.providers[providerName]; + + const consoleUrl = + `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; + opn(consoleUrl, { wait: false }); + } else { + context.print.error('AppSync API is not pushed in the cloud.'); + } +} async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { const resourceName = resourceAlreadyExists(context); @@ -326,4 +350,4 @@ function checkIfAuthExists(context) { } -module.exports = { serviceWalkthrough, updateWalkthrough }; +module.exports = { serviceWalkthrough, updateWalkthrough, openConsole }; From de0aae6acddfe0e1a4c6384f3f0dd5cdfa9bc31d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 2 Nov 2018 19:41:34 +0000 Subject: [PATCH 108/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.30-beta.0 - amplify-category-api@0.1.30-beta.0 - amplify-category-auth@0.1.30-beta.0 - amplify-category-function@0.1.30-beta.0 - amplify-category-hosting@0.1.30-beta.0 - amplify-category-interactions@0.1.30-beta.0 - amplify-category-notifications@0.1.30-beta.0 - amplify-category-storage@0.1.30-beta.0 - @aws-amplify/cli@0.1.30-beta.0 - amplify-codegen@0.1.30-beta.0 - amplify-frontend-android@0.1.30-beta.0 - amplify-frontend-ios@0.1.30-beta.0 - amplify-frontend-javascript@0.1.30-beta.0 - amplify-graphql-docs-generator@0.1.30-beta.0 - amplify-provider-awscloudformation@0.1.30-beta.0 - graphql-appsync-transformer@1.0.30-beta.0 - graphql-auth-transformer@1.0.30-beta.0 - graphql-connection-transformer@1.0.30-beta.0 - graphql-dynamodb-transformer@1.0.30-beta.0 - graphql-elasticsearch-transformer@1.0.30-beta.0 - graphql-http-transformer@1.0.14-beta.0 - graphql-mapping-template@1.0.30-beta.0 - graphql-transformer-common@1.0.30-beta.0 - graphql-transformer-core@1.0.30-beta.0 - graphql-transformers-e2e-tests@1.0.30-beta.0 - graphql-versioned-transformer@1.0.30-beta.0 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a340114dbc..3cdb0e22bd 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 6f49809820..cd415c8355 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.29", + "version": "0.1.30-beta.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.29", - "amplify-category-function": "^0.1.29", - "amplify-category-storage": "^0.1.29", + "amplify-category-auth": "^0.1.30-beta.0", + "amplify-category-function": "^0.1.30-beta.0", + "amplify-category-storage": "^0.1.30-beta.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", "moment": "^2.22.2", - "uuid": "^2.0.3", - "opn": "^5.3.0" + "opn": "^5.3.0", + "uuid": "^2.0.3" }, "devDependencies": { "eslint-config-airbnb-base": "^12.1.0", From 5fd59518b75a15b948684d337d36a55c500d3be9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 2 Nov 2018 22:42:59 +0000 Subject: [PATCH 109/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.30 - amplify-category-api@0.1.30 - amplify-category-auth@0.1.30 - amplify-category-function@0.1.30 - amplify-category-hosting@0.1.30 - amplify-category-interactions@0.1.30 - amplify-category-notifications@0.1.30 - amplify-category-storage@0.1.30 - @aws-amplify/cli@0.1.30 - amplify-codegen@0.1.30 - amplify-frontend-android@0.1.30 - amplify-frontend-ios@0.1.30 - amplify-frontend-javascript@0.1.30 - amplify-graphql-docs-generator@0.1.30 - amplify-provider-awscloudformation@0.1.30 - graphql-appsync-transformer@1.0.30 - graphql-auth-transformer@1.0.30 - graphql-connection-transformer@1.0.30 - graphql-dynamodb-transformer@1.0.30 - graphql-elasticsearch-transformer@1.0.30 - graphql-http-transformer@1.0.14 - graphql-mapping-template@1.0.30 - graphql-transformer-common@1.0.30 - graphql-transformer-core@1.0.30 - graphql-transformers-e2e-tests@1.0.30 - graphql-versioned-transformer@1.0.30 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3cdb0e22bd..189d58c4ca 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index cd415c8355..c161ac0d9c 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.30-beta.0", + "version": "0.1.30", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.30-beta.0", - "amplify-category-function": "^0.1.30-beta.0", - "amplify-category-storage": "^0.1.30-beta.0", + "amplify-category-auth": "^0.1.30", + "amplify-category-function": "^0.1.30", + "amplify-category-storage": "^0.1.30", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^3.2.1", From 335feab3ac3aa4ac45426f73411005496f9ed0c0 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Sun, 4 Nov 2018 19:40:53 +0000 Subject: [PATCH 110/587] Fix #355 by consolidating enquirer package versions to ^6.0.0, since inquirer <5.0.0 is not functioning properly under windows. (#390) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c161ac0d9c..b967ea623a 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -15,7 +15,7 @@ "amplify-category-storage": "^0.1.30", "eslint": "^4.9.0", "fs-extra": "^6.0.1", - "inquirer": "^3.2.1", + "inquirer": "^6.0.0", "moment": "^2.22.2", "opn": "^5.3.0", "uuid": "^2.0.3" From 26f201c7ba31dd0fcdf8484b3b41271ffe9c1cfd Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Sun, 4 Nov 2018 17:45:38 -0800 Subject: [PATCH 111/587] chore(release): Publish [ci skip] (#393) - amplify-category-analytics@0.1.31 - amplify-category-api@0.1.31 - amplify-category-auth@0.1.31 - amplify-category-function@0.1.31 - amplify-category-hosting@0.1.31 - amplify-category-interactions@0.1.31 - amplify-category-notifications@0.1.31 - amplify-category-storage@0.1.31 - @aws-amplify/cli@0.1.31 - amplify-codegen@0.1.31 - amplify-frontend-android@0.1.31 - amplify-frontend-ios@0.1.31 - amplify-frontend-javascript@0.1.31 - amplify-graphql-docs-generator@0.1.31 - amplify-provider-awscloudformation@0.1.31 - graphql-appsync-transformer@1.0.31 - graphql-auth-transformer@1.0.31 - graphql-connection-transformer@1.0.31 - graphql-dynamodb-transformer@1.0.31 - graphql-elasticsearch-transformer@1.0.31 - graphql-http-transformer@1.0.15 - graphql-mapping-template@1.0.31 - graphql-transformer-common@1.0.31 - graphql-transformer-core@1.0.31 - graphql-transformers-e2e-tests@1.0.31 - graphql-versioned-transformer@1.0.31 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 189d58c4ca..6c918eb0d6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b967ea623a..9c10a90cf9 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.30", + "version": "0.1.31", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.30", - "amplify-category-function": "^0.1.30", - "amplify-category-storage": "^0.1.30", + "amplify-category-auth": "^0.1.31", + "amplify-category-function": "^0.1.31", + "amplify-category-storage": "^0.1.31", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^6.0.0", From 9ef3ef6d1470394d5c39b564847d472f971fd2a2 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 5 Nov 2018 13:35:05 -0800 Subject: [PATCH 112/587] [Part 1] Support for multiple environments/stages as a part of the Amplify CLI (#378) * Support for multiple environments as a part of the Amplify CLI * feat: amplify push accepts an env param/flag in the CLI * feat: ability to recrete local files when initing a new environment * feat: add env commands to amplify * feat: add amplify env add/get/remove commands * fix: fixing auth issues with acccessing S3 deployment bucket * feat: passing env name as a headless param in init flow * feat: add appropriate amplify generated files in gitignore file --- packages/amplify-category-api/commands/api/remove.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index ed6d3abfd2..0ad4814a14 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -13,7 +13,7 @@ module.exports = { return amplify.removeResource(context, category, resourceName) .then((resourceValues) => { if (resourceValues.service === 'AppSync') { - const { projectPath } = amplify.getProjectDetails().projectConfig; + const { projectPath } = amplify.getEnvInfo(); const gqlConfigFile = path.normalize(path.join( projectPath, From 7f69ae872ee1b9fad42c3f9676bd52f1f5781048 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 5 Nov 2018 18:20:08 -0800 Subject: [PATCH 113/587] headless setup for Push and Publish (#398) --- packages/amplify-category-api/commands/api/push.js | 2 +- packages/amplify-category-api/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index a30bd83351..fcb5573123 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -6,7 +6,7 @@ module.exports = { run: async (context) => { const { amplify, parameters } = context; const resourceName = parameters.first; - + context.amplify.constructExeInfo(context); return amplify.pushResources(context, category, resourceName) .catch((err) => { context.print.info(err.stack); diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9c10a90cf9..5260382edf 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -14,7 +14,7 @@ "amplify-category-function": "^0.1.31", "amplify-category-storage": "^0.1.31", "eslint": "^4.9.0", - "fs-extra": "^6.0.1", + "fs-extra": "^7.0.0", "inquirer": "^6.0.0", "moment": "^2.22.2", "opn": "^5.3.0", From c4df92fd7e708f5cb68e329cc91fdbabd31eb350 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 7 Nov 2018 13:35:40 -0800 Subject: [PATCH 114/587] Release (#400) * chore(release): Publish [ci skip] - amplify-category-analytics@0.1.32-beta.0 - amplify-category-api@0.1.32-beta.0 - amplify-category-auth@0.1.32-beta.0 - amplify-category-function@0.1.32-beta.0 - amplify-category-hosting@0.1.32-beta.0 - amplify-category-interactions@0.1.32-beta.0 - amplify-category-notifications@0.1.32-beta.0 - amplify-category-storage@0.1.32-beta.0 - @aws-amplify/cli@0.1.32-beta.0 - amplify-codegen@0.1.32-beta.0 - amplify-frontend-android@0.1.32-beta.0 - amplify-frontend-ios@0.1.32-beta.0 - amplify-frontend-javascript@0.1.32-beta.0 - amplify-graphql-docs-generator@0.1.32-beta.0 - amplify-provider-awscloudformation@0.1.32-beta.0 - graphql-appsync-transformer@1.0.32-beta.0 - graphql-auth-transformer@1.0.32-beta.0 - graphql-connection-transformer@1.0.32-beta.0 - graphql-dynamodb-transformer@1.0.32-beta.0 - graphql-elasticsearch-transformer@1.0.32-beta.0 - graphql-http-transformer@1.0.16-beta.0 - graphql-mapping-template@1.0.32-beta.0 - graphql-transformer-common@1.0.32-beta.0 - graphql-transformer-core@1.0.32-beta.0 - graphql-transformers-e2e-tests@1.0.32-beta.0 - graphql-versioned-transformer@1.0.32-beta.0 * chore(release): Publish [ci skip] - amplify-category-analytics@0.1.32 - amplify-category-api@0.1.32 - amplify-category-auth@0.1.32 - amplify-category-function@0.1.32 - amplify-category-hosting@0.1.32 - amplify-category-interactions@0.1.32 - amplify-category-notifications@0.1.32 - amplify-category-storage@0.1.32 - @aws-amplify/cli@0.1.32 - amplify-codegen@0.1.32 - amplify-frontend-android@0.1.32 - amplify-frontend-ios@0.1.32 - amplify-frontend-javascript@0.1.32 - amplify-graphql-docs-generator@0.1.32 - amplify-provider-awscloudformation@0.1.32 - graphql-appsync-transformer@1.0.32 - graphql-auth-transformer@1.0.32 - graphql-connection-transformer@1.0.32 - graphql-dynamodb-transformer@1.0.32 - graphql-elasticsearch-transformer@1.0.32 - graphql-http-transformer@1.0.16 - graphql-mapping-template@1.0.32 - graphql-transformer-common@1.0.32 - graphql-transformer-core@1.0.32 - graphql-transformers-e2e-tests@1.0.32 - graphql-versioned-transformer@1.0.32 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6c918eb0d6..e32eacffa1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9c10a90cf9..eee4b7cbae 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.31", + "version": "0.1.32", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.31", - "amplify-category-function": "^0.1.31", - "amplify-category-storage": "^0.1.31", + "amplify-category-auth": "^0.1.32", + "amplify-category-function": "^0.1.32", + "amplify-category-storage": "^0.1.32", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^6.0.0", From e35468ff532beaa65dbaa50ab82b37b83715f1d3 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Thu, 8 Nov 2018 13:11:29 -0800 Subject: [PATCH 115/587] feat: multi-environment support for API Gateway (#418) * feat: multi-environment support for API Gateway * fix: fixes based on PR comments --- ...w-cloudformation-template-default.json.ejs | 384 ++++++++++++++++-- .../service-walkthroughs/apigw-walkthrough.js | 11 +- 2 files changed, 358 insertions(+), 37 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index d3f655eb10..26ac66dcd0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -4,7 +4,9 @@ <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { - + "env": { + "Type": "String" + }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> <% 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] %>": { @@ -14,8 +16,18 @@ <% } %> <% } %> - }, <% } %> + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, "Resources": { <%if (props.privacy.auth) { %> <% cnt = 0 %> @@ -57,7 +69,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>/*" ] ] @@ -78,7 +100,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>" ] ] @@ -105,7 +137,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>/*" ] ] @@ -126,7 +168,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>" ] ] @@ -147,7 +199,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>/*" ] ] @@ -168,7 +230,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>" ] ] @@ -195,7 +267,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>/*" ] ] @@ -216,7 +298,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>" ] ] @@ -237,7 +329,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>/*" ] ] @@ -258,7 +360,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>" ] ] @@ -279,7 +391,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>/*" ] ] @@ -300,7 +422,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>" ] ] @@ -321,7 +453,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>/*" ] ] @@ -342,7 +484,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>" ] ] @@ -400,7 +552,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>/*" ] ] @@ -421,7 +583,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>" ] ] @@ -448,7 +620,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>/*" ] ] @@ -469,7 +651,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>" ] ] @@ -490,7 +682,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>/*" ] ] @@ -511,7 +713,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>" ] ] @@ -538,7 +750,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>/*" ] ] @@ -559,7 +781,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>" ] ] @@ -580,7 +812,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>/*" ] ] @@ -601,7 +843,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>" ] ] @@ -622,7 +874,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>/*" ] ] @@ -643,7 +905,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>" ] ] @@ -664,7 +936,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>/*" ] ] @@ -685,7 +967,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>" ] ] @@ -725,7 +1017,23 @@ ] ] }, - "basePath": "/Prod", + "basePath": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "/Prod", + { + "Fn::Join": [ + "", + [ + "/", + { + "Ref": "env" + } + ] + ] + } + ] + }, "schemes": [ "https" ], @@ -1024,13 +1332,19 @@ <% } %> <% } %> - - "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "Description": "The Development stage deployment of your API.", - "StageName": "Prod", + "StageName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, "RestApiId": { "Ref": "<%= props.apiName %>" } @@ -1040,7 +1354,7 @@ "Outputs": { "RootUrl": { "Description": "Root URL of the API gateway", - "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/Prod"]]} + "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} }, "ApiName": { "Description": "API Friendly name", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 1dd46cc041..a2ecdfe792 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -168,7 +168,7 @@ async function askApiNames(context, defaults) { }, ]); - answer.apiName = defaults.apiName; + answer.apiName = answer.resourceName; return answer; } @@ -295,7 +295,7 @@ async function askReadWrite(userType, context, privacy = 'r') { } async function askPaths(context, answers, currentPath) { - const existingLambdaArns = true; + // const existingLambdaArns = true; const existingFunctions = functionsExist(context); const choices = [ @@ -305,6 +305,11 @@ async function askPaths(context, answers, currentPath) { }, ]; + /* + + Removing this option for now in favor of multi-env support + - NOT CRITICAL + if (existingLambdaArns) { choices.push({ name: 'Use a Lambda function already deployed on AWS', @@ -312,6 +317,8 @@ async function askPaths(context, answers, currentPath) { }); } + */ + if (existingFunctions) { choices.push({ name: 'Use a Lambda function already added in the current Amplify project', From 7dabec77625403d1923f1ad30c6ec142aee21ff7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 9 Nov 2018 17:35:11 +0000 Subject: [PATCH 116/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.33-beta.0 - amplify-category-api@0.1.33-beta.0 - amplify-category-auth@0.1.33-beta.0 - amplify-category-function@0.1.33-beta.0 - amplify-category-hosting@0.1.33-beta.0 - amplify-category-interactions@0.1.33-beta.0 - amplify-category-notifications@0.1.33-beta.0 - amplify-category-storage@0.1.33-beta.0 - @aws-amplify/cli@0.1.33-beta.0 - amplify-codegen@0.1.33-beta.0 - amplify-frontend-android@0.1.33-beta.0 - amplify-frontend-ios@0.1.33-beta.0 - amplify-frontend-javascript@0.1.33-beta.0 - amplify-graphql-docs-generator@0.1.33-beta.0 - amplify-graphql-types-generator@0.1.1-beta.0 - amplify-provider-awscloudformation@0.1.33-beta.0 - graphql-appsync-transformer@1.0.33-beta.0 - graphql-auth-transformer@1.0.33-beta.0 - graphql-connection-transformer@1.0.33-beta.0 - graphql-dynamodb-transformer@1.0.33-beta.0 - graphql-elasticsearch-transformer@1.0.33-beta.0 - graphql-http-transformer@1.0.17-beta.0 - graphql-mapping-template@1.0.33-beta.0 - graphql-transformer-common@1.0.33-beta.0 - graphql-transformer-core@1.0.33-beta.0 - graphql-transformers-e2e-tests@1.0.33-beta.0 - graphql-versioned-transformer@1.0.33-beta.0 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e32eacffa1..4d3f4d2906 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index eee4b7cbae..07211bf8f1 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.32", + "version": "0.1.33-beta.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.32", - "amplify-category-function": "^0.1.32", - "amplify-category-storage": "^0.1.32", + "amplify-category-auth": "^0.1.33-beta.0", + "amplify-category-function": "^0.1.33-beta.0", + "amplify-category-storage": "^0.1.33-beta.0", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^6.0.0", From 8ed60955db82c91dcd2a2bee1fa718ee78065577 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Fri, 9 Nov 2018 09:54:46 -0800 Subject: [PATCH 117/587] CI: release to prod From f6a1c62441ce78ffa47673d5dde0bf0593239f96 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 9 Nov 2018 18:18:31 +0000 Subject: [PATCH 118/587] chore(release): Publish [ci skip] - amplify-category-analytics@0.1.33 - amplify-category-api@0.1.33 - amplify-category-auth@0.1.33 - amplify-category-function@0.1.33 - amplify-category-hosting@0.1.33 - amplify-category-interactions@0.1.33 - amplify-category-notifications@0.1.33 - amplify-category-storage@0.1.33 - @aws-amplify/cli@0.1.33 - amplify-codegen@0.1.33 - amplify-frontend-android@0.1.33 - amplify-frontend-ios@0.1.33 - amplify-frontend-javascript@0.1.33 - amplify-graphql-docs-generator@0.1.33 - amplify-graphql-types-generator@0.1.1 - amplify-provider-awscloudformation@0.1.33 - graphql-appsync-transformer@1.0.33 - graphql-auth-transformer@1.0.33 - graphql-connection-transformer@1.0.33 - graphql-dynamodb-transformer@1.0.33 - graphql-elasticsearch-transformer@1.0.33 - graphql-http-transformer@1.0.17 - graphql-mapping-template@1.0.33 - graphql-transformer-common@1.0.33 - graphql-transformer-core@1.0.33 - graphql-transformers-e2e-tests@1.0.33 - graphql-versioned-transformer@1.0.33 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4d3f4d2906..e63f24720f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 07211bf8f1..bccca568f9 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.33-beta.0", + "version": "0.1.33", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.33-beta.0", - "amplify-category-function": "^0.1.33-beta.0", - "amplify-category-storage": "^0.1.33-beta.0", + "amplify-category-auth": "^0.1.33", + "amplify-category-function": "^0.1.33", + "amplify-category-storage": "^0.1.33", "eslint": "^4.9.0", "fs-extra": "^6.0.1", "inquirer": "^6.0.0", From f0e11b6b9a27e2d5fdc47e017fc6d4d114a73ca5 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 11 Nov 2018 20:55:39 -0800 Subject: [PATCH 119/587] feat: multi-environment support for interactions category --- ...pigw-cloudformation-template-default.json.ejs | 10 ++++++++-- .../provider-utils/awscloudformation/index.js | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 26ac66dcd0..e062029478 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -4,6 +4,12 @@ <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { + "authRoleName": { + "Type": "String" + }, + "unauthRoleName": { + "Type": "String" + }, "env": { "Type": "String" }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> @@ -39,7 +45,7 @@ "Properties": { "PolicyName": "PolicyAPIGW<%= props.apiName %>auth", "Roles": [ - "<%= props.privacy.authRoleName %>" + {"Ref": "authRoleName"} ], "PolicyDocument": { "Version": "2012-10-17", @@ -522,7 +528,7 @@ "Properties": { "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", "Roles": [ - "<%= props.privacy.unAuthRoleName %>" + {"Ref": "unauthRoleName"} ], "PolicyDocument": { "Version": "2012-10-17", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index dd6ff02dd6..da5be48215 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -2,6 +2,7 @@ const path = require('path'); const fs = require('fs-extra'); const parametersFileName = 'api-params.json'; +const cfnParametersFilename = 'parameters.json'; let serviceMetadata; @@ -70,11 +71,24 @@ function addResource(context, category, service, options) { copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); - const jsonString = JSON.stringify(parameters, null, 4); + let jsonString = JSON.stringify(parameters, null, 4); fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); + jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); } context.amplify.updateamplifyMetaAfterResourceAdd( category, From d284283665a8ec773f6fb3ec804a51f2ed628aa2 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 5 Nov 2018 13:35:05 -0800 Subject: [PATCH 120/587] [Part 1] Support for multiple environments/stages as a part of the Amplify CLI (#378) * Support for multiple environments as a part of the Amplify CLI * feat: amplify push accepts an env param/flag in the CLI * feat: ability to recrete local files when initing a new environment * feat: add env commands to amplify * feat: add amplify env add/get/remove commands * fix: fixing auth issues with acccessing S3 deployment bucket * feat: passing env name as a headless param in init flow * feat: add appropriate amplify generated files in gitignore file --- packages/amplify-category-api/commands/api/remove.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index ed6d3abfd2..0ad4814a14 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -13,7 +13,7 @@ module.exports = { return amplify.removeResource(context, category, resourceName) .then((resourceValues) => { if (resourceValues.service === 'AppSync') { - const { projectPath } = amplify.getProjectDetails().projectConfig; + const { projectPath } = amplify.getEnvInfo(); const gqlConfigFile = path.normalize(path.join( projectPath, From f6943bb3455295f695868fe9151025ea6a343fb3 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 5 Nov 2018 18:20:08 -0800 Subject: [PATCH 121/587] headless setup for Push and Publish (#398) --- packages/amplify-category-api/commands/api/push.js | 2 +- packages/amplify-category-api/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index a30bd83351..fcb5573123 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -6,7 +6,7 @@ module.exports = { run: async (context) => { const { amplify, parameters } = context; const resourceName = parameters.first; - + context.amplify.constructExeInfo(context); return amplify.pushResources(context, category, resourceName) .catch((err) => { context.print.info(err.stack); diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index bccca568f9..40491fba5b 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -14,7 +14,7 @@ "amplify-category-function": "^0.1.33", "amplify-category-storage": "^0.1.33", "eslint": "^4.9.0", - "fs-extra": "^6.0.1", + "fs-extra": "^7.0.0", "inquirer": "^6.0.0", "moment": "^2.22.2", "opn": "^5.3.0", From 848e28a4eeefb9db83847c1c046cba13866cf147 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Thu, 8 Nov 2018 13:11:29 -0800 Subject: [PATCH 122/587] feat: multi-environment support for API Gateway (#418) * feat: multi-environment support for API Gateway * fix: fixes based on PR comments --- ...w-cloudformation-template-default.json.ejs | 384 ++++++++++++++++-- .../service-walkthroughs/apigw-walkthrough.js | 11 +- 2 files changed, 358 insertions(+), 37 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index d3f655eb10..26ac66dcd0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -4,7 +4,9 @@ <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { - + "env": { + "Type": "String" + }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> <% 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] %>": { @@ -14,8 +16,18 @@ <% } %> <% } %> - }, <% } %> + }, + "Conditions": { + "ShouldNotCreateEnvResources": { + "Fn::Equals": [ + { + "Ref": "env" + }, + "NONE" + ] + } + }, "Resources": { <%if (props.privacy.auth) { %> <% cnt = 0 %> @@ -57,7 +69,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>/*" ] ] @@ -78,7 +100,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>" ] ] @@ -105,7 +137,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>/*" ] ] @@ -126,7 +168,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>" ] ] @@ -147,7 +199,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>/*" ] ] @@ -168,7 +230,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>" ] ] @@ -195,7 +267,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>/*" ] ] @@ -216,7 +298,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>" ] ] @@ -237,7 +329,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>/*" ] ] @@ -258,7 +360,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>" ] ] @@ -279,7 +391,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>/*" ] ] @@ -300,7 +422,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>" ] ] @@ -321,7 +453,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>/*" ] ] @@ -342,7 +484,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>" ] ] @@ -400,7 +552,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>/*" ] ] @@ -421,7 +583,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/*", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/*", "<%= props.paths[i].name %>" ] ] @@ -448,7 +620,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>/*" ] ] @@ -469,7 +651,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/GET", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/GET", "<%= props.paths[i].name %>" ] ] @@ -490,7 +682,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>/*" ] ] @@ -511,7 +713,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/HEAD", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/HEAD", "<%= props.paths[i].name %>" ] ] @@ -538,7 +750,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>/*" ] ] @@ -559,7 +781,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/DELETE", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/DELETE", "<%= props.paths[i].name %>" ] ] @@ -580,7 +812,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>/*" ] ] @@ -601,7 +843,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PATCH", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PATCH", "<%= props.paths[i].name %>" ] ] @@ -622,7 +874,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>/*" ] ] @@ -643,7 +905,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/POST", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/POST", "<%= props.paths[i].name %>" ] ] @@ -664,7 +936,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>/*" ] ] @@ -685,7 +967,17 @@ { "Ref": "<%= props.apiName %>" }, - "/Prod/PUT", + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "/PUT", "<%= props.paths[i].name %>" ] ] @@ -725,7 +1017,23 @@ ] ] }, - "basePath": "/Prod", + "basePath": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "/Prod", + { + "Fn::Join": [ + "", + [ + "/", + { + "Ref": "env" + } + ] + ] + } + ] + }, "schemes": [ "https" ], @@ -1024,13 +1332,19 @@ <% } %> <% } %> - - "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { "Type": "AWS::ApiGateway::Deployment", "Properties": { "Description": "The Development stage deployment of your API.", - "StageName": "Prod", + "StageName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, "RestApiId": { "Ref": "<%= props.apiName %>" } @@ -1040,7 +1354,7 @@ "Outputs": { "RootUrl": { "Description": "Root URL of the API gateway", - "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/Prod"]]} + "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} }, "ApiName": { "Description": "API Friendly name", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 1dd46cc041..a2ecdfe792 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -168,7 +168,7 @@ async function askApiNames(context, defaults) { }, ]); - answer.apiName = defaults.apiName; + answer.apiName = answer.resourceName; return answer; } @@ -295,7 +295,7 @@ async function askReadWrite(userType, context, privacy = 'r') { } async function askPaths(context, answers, currentPath) { - const existingLambdaArns = true; + // const existingLambdaArns = true; const existingFunctions = functionsExist(context); const choices = [ @@ -305,6 +305,11 @@ async function askPaths(context, answers, currentPath) { }, ]; + /* + + Removing this option for now in favor of multi-env support + - NOT CRITICAL + if (existingLambdaArns) { choices.push({ name: 'Use a Lambda function already deployed on AWS', @@ -312,6 +317,8 @@ async function askPaths(context, answers, currentPath) { }); } + */ + if (existingFunctions) { choices.push({ name: 'Use a Lambda function already added in the current Amplify project', From 83cf76eec1a8a7b5ad78ba4620100e9c31d2ae0b Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 11 Nov 2018 20:55:39 -0800 Subject: [PATCH 123/587] feat: multi-environment support for interactions category --- ...pigw-cloudformation-template-default.json.ejs | 10 ++++++++-- .../provider-utils/awscloudformation/index.js | 16 +++++++++++++++- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 26ac66dcd0..e062029478 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -4,6 +4,12 @@ <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { + "authRoleName": { + "Type": "String" + }, + "unauthRoleName": { + "Type": "String" + }, "env": { "Type": "String" }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> @@ -39,7 +45,7 @@ "Properties": { "PolicyName": "PolicyAPIGW<%= props.apiName %>auth", "Roles": [ - "<%= props.privacy.authRoleName %>" + {"Ref": "authRoleName"} ], "PolicyDocument": { "Version": "2012-10-17", @@ -522,7 +528,7 @@ "Properties": { "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", "Roles": [ - "<%= props.privacy.unAuthRoleName %>" + {"Ref": "unauthRoleName"} ], "PolicyDocument": { "Version": "2012-10-17", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index dd6ff02dd6..da5be48215 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -2,6 +2,7 @@ const path = require('path'); const fs = require('fs-extra'); const parametersFileName = 'api-params.json'; +const cfnParametersFilename = 'parameters.json'; let serviceMetadata; @@ -70,11 +71,24 @@ function addResource(context, category, service, options) { copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); - const jsonString = JSON.stringify(parameters, null, 4); + let jsonString = JSON.stringify(parameters, null, 4); fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); + jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); } context.amplify.updateamplifyMetaAfterResourceAdd( category, From 2c904bfbbc751b2a65ca83abaad8dcb5cab577af Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 16 Nov 2018 21:24:25 +0000 Subject: [PATCH 124/587] Publish - amplify-category-analytics@0.1.34-multienv.0 - amplify-category-api@0.1.34-multienv.0 - amplify-category-auth@0.1.34-multienv.0 - amplify-category-function@0.1.34-multienv.0 - amplify-category-hosting@0.1.34-multienv.0 - amplify-category-interactions@0.1.34-multienv.0 - amplify-category-notifications@0.1.34-multienv.0 - amplify-category-storage@0.1.34-multienv.0 - @aws-amplify/cli@0.1.35-multienv.0 - amplify-codegen@0.1.35-multienv.0 - amplify-frontend-android@0.1.34-multienv.0 - amplify-frontend-ios@0.1.34-multienv.0 - amplify-frontend-javascript@0.1.34-multienv.0 - amplify-graphql-types-generator@0.1.2-multienv.0 - amplify-provider-awscloudformation@0.1.35-multienv.0 - graphql-appsync-transformer@1.0.34-multienv.0 - graphql-auth-transformer@1.0.34-multienv.0 - graphql-connection-transformer@1.0.34-multienv.0 - graphql-dynamodb-transformer@1.0.34-multienv.0 - graphql-elasticsearch-transformer@1.0.34-multienv.0 - graphql-http-transformer@1.0.18-multienv.0 - graphql-transformer-common@1.0.34-multienv.0 - graphql-transformers-e2e-tests@1.0.34-multienv.0 - graphql-versioned-transformer@1.0.34-multienv.0 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e63f24720f..32507173e3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 40491fba5b..23ab654e96 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.33", + "version": "0.1.34-multienv.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.33", - "amplify-category-function": "^0.1.33", - "amplify-category-storage": "^0.1.33", + "amplify-category-auth": "^0.1.34-multienv.0", + "amplify-category-function": "^0.1.34-multienv.0", + "amplify-category-storage": "^0.1.34-multienv.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From bc2d68f4e8838bd34b612a61e2346dacbd77df8d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 19 Nov 2018 19:25:00 +0000 Subject: [PATCH 125/587] Publish - amplify-category-analytics@0.1.34-multienv.1 - amplify-category-api@0.1.34-multienv.1 - amplify-category-auth@0.1.34-multienv.1 - amplify-category-function@0.1.34-multienv.1 - amplify-category-interactions@0.1.34-multienv.1 - amplify-category-notifications@0.1.34-multienv.2 - amplify-category-storage@0.1.34-multienv.1 - @aws-amplify/cli@0.1.35-multienv.2 - amplify-provider-awscloudformation@0.1.35-multienv.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 32507173e3..969da91251 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 23ab654e96..195d7f187c 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.34-multienv.0", + "version": "0.1.34-multienv.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.34-multienv.0", - "amplify-category-function": "^0.1.34-multienv.0", - "amplify-category-storage": "^0.1.34-multienv.0", + "amplify-category-auth": "^0.1.34-multienv.1", + "amplify-category-function": "^0.1.34-multienv.1", + "amplify-category-storage": "^0.1.34-multienv.1", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From c5ff4136c448089c70e8e99bc0b915fca3dfd04a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 19 Nov 2018 19:48:44 +0000 Subject: [PATCH 126/587] Publish - amplify-category-analytics@0.1.34-multienv.2 - amplify-category-api@0.1.34-multienv.2 - amplify-category-auth@0.1.34-multienv.2 - amplify-category-function@0.1.34-multienv.2 - amplify-category-interactions@0.1.34-multienv.2 - amplify-category-notifications@0.1.34-multienv.3 - amplify-category-storage@0.1.34-multienv.2 - @aws-amplify/cli@0.1.35-multienv.3 - amplify-provider-awscloudformation@0.1.35-multienv.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 969da91251..a14e112b0f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 195d7f187c..c750b440d5 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.34-multienv.1", + "version": "0.1.34-multienv.2", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.34-multienv.1", - "amplify-category-function": "^0.1.34-multienv.1", - "amplify-category-storage": "^0.1.34-multienv.1", + "amplify-category-auth": "^0.1.34-multienv.2", + "amplify-category-function": "^0.1.34-multienv.2", + "amplify-category-storage": "^0.1.34-multienv.2", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 95667055d46a453c369f506ba9e253c938324515 Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Wed, 21 Nov 2018 12:32:44 -0800 Subject: [PATCH 127/587] chore: Bump package versions to 0.2.0 (#488) * chore: bump minor package versions for multienv * revert graphql-* package versions back * add missing file --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c750b440d5..70b81eb640 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.1.34-multienv.2", + "version": "0.2.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.1.34-multienv.2", - "amplify-category-function": "^0.1.34-multienv.2", - "amplify-category-storage": "^0.1.34-multienv.2", + "amplify-category-auth": "^0.2.0", + "amplify-category-function": "^0.2.0", + "amplify-category-storage": "^0.2.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 70b09fe69d0cbcb190e831f700cfbe694f7e84c5 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 21 Nov 2018 20:35:20 +0000 Subject: [PATCH 128/587] Publish - amplify-category-analytics@0.2.1-multienv.0 - amplify-category-api@0.2.1-multienv.0 - amplify-category-auth@0.2.1-multienv.0 - amplify-category-function@0.2.1-multienv.0 - amplify-category-hosting@0.2.1-multienv.0 - amplify-category-interactions@0.2.1-multienv.0 - amplify-category-notifications@0.2.1-multienv.0 - amplify-category-storage@0.2.1-multienv.0 - @aws-amplify/cli@0.2.1-multienv.0 - amplify-codegen@0.2.1-multienv.0 - amplify-frontend-android@0.2.1-multienv.0 - amplify-frontend-ios@0.2.1-multienv.0 - amplify-frontend-javascript@0.2.1-multienv.0 - amplify-graphql-docs-generator@0.2.1-multienv.0 - amplify-graphql-types-generator@0.2.1-multienv.0 - amplify-provider-awscloudformation@0.2.1-multienv.0 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a14e112b0f..dc1a50d635 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 70b81eb640..5182541a83 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.0", + "version": "0.2.1-multienv.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.0", - "amplify-category-function": "^0.2.0", - "amplify-category-storage": "^0.2.0", + "amplify-category-auth": "^0.2.1-multienv.0", + "amplify-category-function": "^0.2.1-multienv.0", + "amplify-category-storage": "^0.2.1-multienv.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 2e36f3d719e83c87904eac20c9bcfe815f62f473 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Sun, 25 Nov 2018 09:14:28 -0800 Subject: [PATCH 129/587] feat: migration of categories - s3,dynamo,lambda,appsync (#495) * feat: migration of categories - s3,dynamo,appsync,apigw,function * delete constant from top level * Remove migrateproject redundant call * Added appsync migration * PR reviews --- packages/amplify-category-api/index.js | 31 +++++++++++++++++++ .../provider-utils/awscloudformation/index.js | 18 ++++++++++- .../appSync-walkthrough.js | 8 ++++- 3 files changed, 55 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 64bc2bfe8f..661886052e 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -1,10 +1,41 @@ const { run } = require('./commands/api/console'); +const category = 'api'; + async function console(context) { await run(context); } +async function migrate(context) { + const { projectPath, amplifyMeta } = context.migrationInfo; + const migrateResourcePromises = []; + Object.keys(amplifyMeta).forEach((categoryName) => { + if (categoryName === category) { + Object.keys(amplifyMeta[category]).forEach((resourceName) => { + try { + const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + if (providerController) { + migrateResourcePromises.push(providerController.migrateResource( + context, + projectPath, + amplifyMeta[category][resourceName].service, + resourceName, + )); + } else { + context.print.error(`Provider not configured for ${category}: ${resourceName}`); + } + } catch (e) { + context.print.warning(`Could not run migration for ${category} category`); + } + }); + } + }); + + await Promise.all(migrateResourcePromises); +} + module.exports = { console, + migrate, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index da5be48215..7ec077f67f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -151,4 +151,20 @@ async function updateResource(context, category, service) { }); } -module.exports = { addResource, updateResource, console }; +async function migrateResource(context, projectPath, service, resourceName) { + serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + const { serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { migrate } = require(serviceWalkthroughSrc); + + if (!migrate) { + context.print.info(`No migration required for ${resourceName}`); + return; + } + + return await migrate(context, projectPath, resourceName); +} + +module.exports = { + addResource, updateResource, console, migrateResource, +}; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 4462d937b9..07807aa36f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -349,5 +349,11 @@ function checkIfAuthExists(context) { return authResourceName; } +async function migrate(context) { + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); +} + -module.exports = { serviceWalkthrough, updateWalkthrough, openConsole }; +module.exports = { + serviceWalkthrough, updateWalkthrough, openConsole, migrate, +}; From b0077dca5599ec1d0e0d5ac06671d788ca6165cf Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 25 Nov 2018 11:12:41 -0800 Subject: [PATCH 130/587] feat: migration of API GW and Interactions --- packages/amplify-category-api/index.js | 3 +- .../service-walkthroughs/apigw-walkthrough.js | 43 ++++++++++++++++++- 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 661886052e..5101d48716 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -26,7 +26,8 @@ async function migrate(context) { context.print.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - context.print.warning(`Could not run migration for ${category} category`); + context.print.warning(`Could not run migration for ${category}: ${resourceName}`); + throw e; } }); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index a2ecdfe792..7b56d5327c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -5,6 +5,7 @@ const fs = require('fs-extra'); const category = 'api'; const serviceName = 'API Gateway'; const parametersFileName = 'api-params.json'; +const cfnParametersFilename = 'parameters.json'; const uuid = require('uuid'); async function serviceWalkthrough(context, defaultValuesFilename) { @@ -566,6 +567,46 @@ async function askLambdaArn(context, currentPath) { }; } +async function migrate(context, projectPath, resourceName) { + const { amplify } = context; + + const targetDir = amplify.pathManager.getBackendDirPath(); + const resourceDirPath = pathLib.join(targetDir, category, resourceName); + const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); + let parameters; + try { + parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + } catch (e) { + context.print.error(`Error reading api-params.json file for ${resourceName} resource`); + throw e; + } + const pluginDir = `${__dirname}/../`; + const copyJobs = [ + { + dir: pluginDir, + template: 'cloudformation-templates/apigw-cloudformation-template-default.json.ejs', + target: `${targetDir}/${category}/${resourceName}/${resourceName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + await context.amplify.copyBatch(context, copyJobs, parameters, true, false); + + // Create parameters.json file + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; + + const cfnParametersFilePath = pathLib.join(resourceDirPath, cfnParametersFilename); + const jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); +} + // function checkIfAuthExists(context) { // const { amplify } = context; // const { amplifyMeta } = amplify.getProjectDetails(); @@ -585,4 +626,4 @@ async function askLambdaArn(context, currentPath) { // } -module.exports = { serviceWalkthrough, updateWalkthrough }; +module.exports = { serviceWalkthrough, updateWalkthrough, migrate }; From 6ad5da2fe809d6db4d00671b3a88dbacdec1747c Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 26 Nov 2018 00:36:32 -0800 Subject: [PATCH 131/587] forceful compilation of annotated gql schema for migration --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 07807aa36f..d94aa9f17c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -350,7 +350,7 @@ function checkIfAuthExists(context) { } async function migrate(context) { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); } From 6ee1d2a3a80c98a09ea50d69a7ff8989d57b572a Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 27 Nov 2018 17:27:53 -0800 Subject: [PATCH 132/587] feat: add a warning on migration and force compile gql schema --- packages/amplify-category-api/commands/api/gql-compile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index b6d7d6dd99..6542155aa4 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -4,7 +4,7 @@ module.exports = { name: subcommand, run: async (context) => { try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); } catch (err) { context.print.info(err.stack); context.print.error(err.message); From 4d18965edcfc1f7742b312bda854a292a6731530 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 28 Nov 2018 21:59:43 +0000 Subject: [PATCH 133/587] Publish - amplify-category-analytics@0.2.1-multienv.1 - amplify-category-api@0.2.1-multienv.1 - amplify-category-auth@0.2.1-multienv.1 - amplify-category-function@0.2.1-multienv.1 - amplify-category-hosting@0.2.1-multienv.1 - amplify-category-interactions@0.2.1-multienv.1 - amplify-category-notifications@0.2.1-multienv.1 - amplify-category-storage@0.2.1-multienv.1 - @aws-amplify/cli@0.2.1-multienv.2 - amplify-provider-awscloudformation@0.2.1-multienv.1 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index dc1a50d635..e564c78098 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5182541a83..f063bb5995 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.0", + "version": "0.2.1-multienv.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.1-multienv.0", - "amplify-category-function": "^0.2.1-multienv.0", - "amplify-category-storage": "^0.2.1-multienv.0", + "amplify-category-auth": "^0.2.1-multienv.1", + "amplify-category-function": "^0.2.1-multienv.1", + "amplify-category-storage": "^0.2.1-multienv.1", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 2f126f012b391b917bffc82fd1fa311764319737 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 4 Dec 2018 00:13:34 +0000 Subject: [PATCH 134/587] Publish - amplify-category-api@0.2.1-multienv.2 - amplify-category-function@0.2.1-multienv.2 - amplify-category-interactions@0.2.1-multienv.2 - amplify-category-storage@0.2.1-multienv.2 - @aws-amplify/cli@0.2.1-multienv.5 - amplify-provider-awscloudformation@0.2.1-multienv.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e564c78098..d55d313e11 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f063bb5995..fae8e2b03d 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.1", + "version": "0.2.1-multienv.2", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,8 +11,8 @@ }, "dependencies": { "amplify-category-auth": "^0.2.1-multienv.1", - "amplify-category-function": "^0.2.1-multienv.1", - "amplify-category-storage": "^0.2.1-multienv.1", + "amplify-category-function": "^0.2.1-multienv.2", + "amplify-category-storage": "^0.2.1-multienv.2", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 3e9e924f131682390e738eee955cda0143e97c6d Mon Sep 17 00:00:00 2001 From: Zach Jullion Date: Wed, 5 Dec 2018 11:44:40 -0700 Subject: [PATCH 135/587] fix(cli): remove calls to gluegun's prompt.confirm (#546) prompt.confirm is unreliable and sometimes fails to take user input create a confirm prompt helper that uses inquirer prompt instead refactor helper defined in dynamoDb-walkthrough.js https://github.com/aws-amplify/amplify-cli/issues/528 --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index d94aa9f17c..b30abee7c8 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -116,7 +116,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // The user doesn't have an annotated schema file - if (!await context.prompt.confirm('Do you want a guided schema creation?')) { + if (!await amplify.confirmPrompt.run('Do you want a guided schema creation?')) { // Copy the most basic schema onto the users resource dir and transform that const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; From d0e00d17deb8587772480830e3073a9895f10e23 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 5 Dec 2018 18:47:43 +0000 Subject: [PATCH 136/587] Publish - amplify-category-analytics@0.2.1-multienv.2 - amplify-category-api@0.2.1-multienv.3 - amplify-category-function@0.2.1-multienv.3 - amplify-category-interactions@0.2.1-multienv.3 - amplify-category-notifications@0.2.1-multienv.2 - amplify-category-storage@0.2.1-multienv.3 - @aws-amplify/cli@0.2.1-multienv.8 - amplify-frontend-android@0.2.1-multienv.1 - amplify-frontend-ios@0.2.1-multienv.1 - amplify-frontend-javascript@0.2.1-multienv.1 - amplify-provider-awscloudformation@0.2.1-multienv.6 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d55d313e11..f5101d6a8d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index fae8e2b03d..181c40132f 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.2", + "version": "0.2.1-multienv.3", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,8 +11,8 @@ }, "dependencies": { "amplify-category-auth": "^0.2.1-multienv.1", - "amplify-category-function": "^0.2.1-multienv.2", - "amplify-category-storage": "^0.2.1-multienv.2", + "amplify-category-function": "^0.2.1-multienv.3", + "amplify-category-storage": "^0.2.1-multienv.3", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 425576a2a73769a77b4633c82a2f8a6ae821ae2a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 21 Dec 2018 22:32:51 +0000 Subject: [PATCH 137/587] Publish - amplify-category-analytics@0.2.1-multienv.3 - amplify-category-api@0.2.1-multienv.4 - amplify-category-auth@0.2.1-multienv.2 - amplify-category-function@0.2.1-multienv.4 - amplify-category-interactions@0.2.1-multienv.5 - amplify-category-notifications@0.2.1-multienv.4 - amplify-category-storage@0.2.1-multienv.4 - @aws-amplify/cli@0.2.1-multienv.15 - amplify-provider-awscloudformation@0.2.1-multienv.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f5101d6a8d..5d2a72bf50 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 181c40132f..bee446afda 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.3", + "version": "0.2.1-multienv.4", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.1-multienv.1", - "amplify-category-function": "^0.2.1-multienv.3", - "amplify-category-storage": "^0.2.1-multienv.3", + "amplify-category-auth": "^0.2.1-multienv.2", + "amplify-category-function": "^0.2.1-multienv.4", + "amplify-category-storage": "^0.2.1-multienv.4", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 7b1b8d7279fa7ca599517fee8bc400929354c2cf Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 28 Dec 2018 22:12:19 +0000 Subject: [PATCH 138/587] Publish - amplify-category-analytics@0.2.1-multienv.4 - amplify-category-api@0.2.1-multienv.5 - amplify-category-auth@0.2.1-multienv.3 - amplify-category-function@0.2.1-multienv.5 - amplify-category-interactions@0.2.1-multienv.6 - amplify-category-notifications@0.2.1-multienv.5 - amplify-category-storage@0.2.1-multienv.5 - @aws-amplify/cli@0.2.1-multienv.18 - amplify-provider-awscloudformation@0.2.1-multienv.14 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5d2a72bf50..2b93d61e42 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index bee446afda..c5c3213c9a 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.4", + "version": "0.2.1-multienv.5", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.1-multienv.2", - "amplify-category-function": "^0.2.1-multienv.4", - "amplify-category-storage": "^0.2.1-multienv.4", + "amplify-category-auth": "^0.2.1-multienv.3", + "amplify-category-function": "^0.2.1-multienv.5", + "amplify-category-storage": "^0.2.1-multienv.5", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 7cabebc8948d17340d915fe57e38ebc9f8f23d91 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 16 Jan 2019 21:52:12 +0000 Subject: [PATCH 139/587] Publish - amplify-category-api@0.2.1-multienv.6 - amplify-category-function@0.2.1-multienv.6 - amplify-category-hosting@0.2.1-multienv.4 - amplify-category-interactions@0.2.1-multienv.7 - @aws-amplify/cli@0.2.1-multienv.28 - amplify-frontend-javascript@0.2.1-multienv.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2b93d61e42..1ebc38a426 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c5c3213c9a..9f56c2d441 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.5", + "version": "0.2.1-multienv.6", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,7 +11,7 @@ }, "dependencies": { "amplify-category-auth": "^0.2.1-multienv.3", - "amplify-category-function": "^0.2.1-multienv.5", + "amplify-category-function": "^0.2.1-multienv.6", "amplify-category-storage": "^0.2.1-multienv.5", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From e149b8ebcea7a192967249d3142a7b505e7411f6 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 30 Jan 2019 17:45:32 +0000 Subject: [PATCH 140/587] Publish - amplify-category-analytics@0.2.1-multienv.6 - amplify-category-api@0.2.1-multienv.7 - amplify-category-auth@0.2.1-multienv.4 - amplify-category-function@0.2.1-multienv.7 - amplify-category-interactions@0.2.1-multienv.8 - amplify-category-notifications@0.2.1-multienv.8 - amplify-category-storage@0.2.1-multienv.6 - @aws-amplify/cli@0.2.1-multienv.40 - amplify-provider-awscloudformation@0.2.1-multienv.30 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1ebc38a426..badd9bb5cb 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9f56c2d441..87f5be29a0 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.6", + "version": "0.2.1-multienv.7", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.1-multienv.3", - "amplify-category-function": "^0.2.1-multienv.6", - "amplify-category-storage": "^0.2.1-multienv.5", + "amplify-category-auth": "^0.2.1-multienv.4", + "amplify-category-function": "^0.2.1-multienv.7", + "amplify-category-storage": "^0.2.1-multienv.6", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From c77b48dc2ecde0f48adc91c02da9148f621828f1 Mon Sep 17 00:00:00 2001 From: Paris Date: Fri, 14 Dec 2018 17:20:33 -0800 Subject: [PATCH 141/587] Updating CLI to use nested stacks --- .../service-walkthroughs/appSync-walkthrough.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b30abee7c8..856f298c8e 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -8,6 +8,8 @@ const serviceName = 'AppSync'; const parametersFileName = 'parameters.json'; const schemaFileName = 'schema.graphql'; const providerName = 'awscloudformation'; +const resolversDirName = 'resolvers'; +const stacksDirName = 'stacks'; function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); @@ -94,6 +96,11 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; + // Ensure the project directory exists and create the stacks & resolvers directories. + fs.ensureDirSync(resourceDir); + fs.mkdirSync(`${resourceDir}/${resolversDirName}`) + fs.mkdirSync(`${resourceDir}/${stacksDirName}`) + if (schemaFileAnswer[inputs[2].key]) { // User has an annotated schema file @@ -106,7 +113,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat }; const { schemaFilePath } = await inquirer.prompt(filePathQuestion); - fs.ensureDirSync(resourceDir); fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); @@ -133,7 +139,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat }; const typeNameAnswer = await inquirer.prompt(typeNameQuestion); - fs.ensureDirSync(resourceDir); // fs.copyFileSync(schemaFilePath, targetSchemaFilePath); const schemaDir = `${__dirname}/../appsync-schemas`; @@ -185,7 +190,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const schemaFilePath = `${__dirname}/../appsync-schemas/${templateSelection}`; const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; - fs.ensureDirSync(resourceDir); fs.copyFileSync(schemaFilePath, targetSchemaFilePath); if (editSchemaChoice) { From 7e2a51e87249cb7fc98f62ab3b919112685c97a0 Mon Sep 17 00:00:00 2001 From: Paris Date: Fri, 11 Jan 2019 16:06:08 -0800 Subject: [PATCH 142/587] Fixing lint issues --- .../service-walkthroughs/appSync-walkthrough.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 856f298c8e..b21400a255 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -98,8 +98,8 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Ensure the project directory exists and create the stacks & resolvers directories. fs.ensureDirSync(resourceDir); - fs.mkdirSync(`${resourceDir}/${resolversDirName}`) - fs.mkdirSync(`${resourceDir}/${stacksDirName}`) + fs.mkdirSync(`${resourceDir}/${resolversDirName}`); + fs.mkdirSync(`${resourceDir}/${stacksDirName}`); if (schemaFileAnswer[inputs[2].key]) { From d873b2ee5e057deb1c8680361e7e918c0b84b91c Mon Sep 17 00:00:00 2001 From: Paris Date: Wed, 16 Jan 2019 11:16:40 -0800 Subject: [PATCH 143/587] Creating CustomResources.yml by default --- .../appSync-walkthrough.js | 4 ++ .../defaultCustomResources.yml | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b21400a255..5ae4e629ac 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -10,6 +10,7 @@ const schemaFileName = 'schema.graphql'; const providerName = 'awscloudformation'; const resolversDirName = 'resolvers'; const stacksDirName = 'stacks'; +const defaultStackName = 'CustomResources.yml'; function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); @@ -101,6 +102,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.mkdirSync(`${resourceDir}/${resolversDirName}`); fs.mkdirSync(`${resourceDir}/${stacksDirName}`); + // Write the default custom resources stack out to disk. + const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.yml`); + fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); if (schemaFileAnswer[inputs[2].key]) { // User has an annotated schema file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml new file mode 100644 index 0000000000..251e93086b --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml @@ -0,0 +1,66 @@ +--- +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 + of the deployment directory. +Resources: + # This will not deploy anything to your AWS account but satisfies CloudFormation's validator. + # You may remove this after adding a resource of your own. + EmptyResource: + Type: 'Custom::EmptyResource' + Condition: AlwaysFalse + # The resource below shows how to add a custom resolver. + # All the files in the /resolvers will be uploaded as part of push and you may + # reference them using the S3DeploymentBucket and S3DeploymentRootKey parameters. +# CustomGetTodoResolver: +# Type: AWS::AppSync::Resolver +# Properties: +# ApiId: +# Ref: AppSyncApiId +# DataSourceName: TodoTable +# FieldName: customGetTodo +# TypeName: Query +# RequestMappingTemplateS3Location: +# Fn::Sub: +# - s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.customGetTodo.req.vtl +# - S3DeploymentBucket: +# Ref: S3DeploymentBucket +# S3DeploymentRootKey: +# Ref: S3DeploymentRootKey +# ResponseMappingTemplateS3Location: +# Fn::Sub: +# - s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.customGetTodo.res.vtl +# - S3DeploymentBucket: +# Ref: S3DeploymentBucket +# S3DeploymentRootKey: +# Ref: S3DeploymentRootKey +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: "" \ No newline at end of file From 027ef717e15a39159da2049a8b965f0b9952e7f9 Mon Sep 17 00:00:00 2001 From: Paris Date: Mon, 21 Jan 2019 14:54:53 -0800 Subject: [PATCH 144/587] Updating typos. Changing default custom stack resources. updating appsync walkthrough --- .../appSync-walkthrough.js | 2 +- .../defaultCustomResources.json | 61 +++++++++++++++++ .../defaultCustomResources.yml | 66 ------------------- 3 files changed, 62 insertions(+), 67 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 5ae4e629ac..a45b3476f3 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -103,7 +103,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.mkdirSync(`${resourceDir}/${stacksDirName}`); // Write the default custom resources stack out to disk. - const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.yml`); + const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); if (schemaFileAnswer[inputs[2].key]) { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json new file mode 100644 index 0000000000..2d8cf0a922 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json @@ -0,0 +1,61 @@ +{ + "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": "" + } + } +} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml deleted file mode 100644 index 251e93086b..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.yml +++ /dev/null @@ -1,66 +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 - of the deployment directory. -Resources: - # This will not deploy anything to your AWS account but satisfies CloudFormation's validator. - # You may remove this after adding a resource of your own. - EmptyResource: - Type: 'Custom::EmptyResource' - Condition: AlwaysFalse - # The resource below shows how to add a custom resolver. - # All the files in the /resolvers will be uploaded as part of push and you may - # reference them using the S3DeploymentBucket and S3DeploymentRootKey parameters. -# CustomGetTodoResolver: -# Type: AWS::AppSync::Resolver -# Properties: -# ApiId: -# Ref: AppSyncApiId -# DataSourceName: TodoTable -# FieldName: customGetTodo -# TypeName: Query -# RequestMappingTemplateS3Location: -# Fn::Sub: -# - s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.customGetTodo.req.vtl -# - S3DeploymentBucket: -# Ref: S3DeploymentBucket -# S3DeploymentRootKey: -# Ref: S3DeploymentRootKey -# ResponseMappingTemplateS3Location: -# Fn::Sub: -# - s3://${S3DeploymentBucket}/${S3DeploymentRootKey}/resolvers/Query.customGetTodo.res.vtl -# - S3DeploymentBucket: -# Ref: S3DeploymentBucket -# S3DeploymentRootKey: -# Ref: S3DeploymentRootKey -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: "" \ No newline at end of file From 2fbd648cabc312003ee1451274a6cddb841c7e86 Mon Sep 17 00:00:00 2001 From: Paris Date: Thu, 24 Jan 2019 20:28:44 -0800 Subject: [PATCH 145/587] Fixes to the migration api migration script --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index a45b3476f3..304fc00f9b 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -358,7 +358,7 @@ function checkIfAuthExists(context) { } async function migrate(context) { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true, migrate: true }); } From 60d64b6e5ef17dfa2f1c43a7436655e21cd9d2e1 Mon Sep 17 00:00:00 2001 From: Paris Date: Tue, 29 Jan 2019 15:27:24 -0800 Subject: [PATCH 146/587] updating default stack to be .json instead of .yml --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 304fc00f9b..c0f9055ac4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -10,7 +10,7 @@ const schemaFileName = 'schema.graphql'; const providerName = 'awscloudformation'; const resolversDirName = 'resolvers'; const stacksDirName = 'stacks'; -const defaultStackName = 'CustomResources.yml'; +const defaultStackName = 'CustomResources.json'; function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); From fab4698fcc6797e631f4ccc4b8c739d33b930453 Mon Sep 17 00:00:00 2001 From: Paris Date: Tue, 29 Jan 2019 15:30:43 -0800 Subject: [PATCH 147/587] Checking that resolver & stack directory dne before trying to create them --- .../service-walkthroughs/appSync-walkthrough.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index c0f9055ac4..b1580406d4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -99,8 +99,14 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Ensure the project directory exists and create the stacks & resolvers directories. fs.ensureDirSync(resourceDir); - fs.mkdirSync(`${resourceDir}/${resolversDirName}`); - fs.mkdirSync(`${resourceDir}/${stacksDirName}`); + 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); + } // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); From 6838e45a3f7b5dbc8118700747f710b1773ac6b1 Mon Sep 17 00:00:00 2001 From: Paris Date: Wed, 30 Jan 2019 12:39:39 -0800 Subject: [PATCH 148/587] 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. --- .../service-walkthroughs/appSync-walkthrough.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b1580406d4..e734ee36a9 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -71,6 +71,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const parameters = { AppSyncApiName: resourceAnswers[inputs[1].key], + UsePayPerRequestBilling: 'true', }; // Ask auth/security question From b591f1bdf3c40ad28ccba5acdfe642956a9308b7 Mon Sep 17 00:00:00 2001 From: Paris Date: Wed, 30 Jan 2019 20:33:50 -0800 Subject: [PATCH 149/587] 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." This reverts commit cec80a698463d2c0a1c833047caf66eb78b29d53. --- .../service-walkthroughs/appSync-walkthrough.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index e734ee36a9..b1580406d4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -71,7 +71,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const parameters = { AppSyncApiName: resourceAnswers[inputs[1].key], - UsePayPerRequestBilling: 'true', }; // Ask auth/security question From 6ef5267dd9ca435d9507fb6ac917e134fa732ec0 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 6 Feb 2019 10:49:13 -0800 Subject: [PATCH 150/587] update appsync security type in backend config on an update --- .../service-walkthroughs/appSync-walkthrough.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b1580406d4..753653275a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -272,9 +272,16 @@ async function updateWalkthrough(context) { const amplifyMeta = JSON.parse(fs.readFileSync(amplifyMetaFilePath)); amplifyMeta[category][resourceName].output.securityType = authType; - const jsonString = JSON.stringify(amplifyMeta, null, '\t'); + let jsonString = JSON.stringify(amplifyMeta, null, '\t'); fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); + const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); + const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + + backendConfig[category][resourceName].output.securityType = authType; + jsonString = JSON.stringify(backendConfig, null, '\t'); + fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); } From 3325254ce5eee31a2feeaf3db634f62c1b9f6eb5 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Wed, 6 Feb 2019 19:48:04 -0800 Subject: [PATCH 151/587] Fix CFN error when resources are of the same name --- packages/amplify-category-api/index.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 5101d48716..39e86076b5 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -7,7 +7,7 @@ async function console(context) { await run(context); } -async function migrate(context) { +async function migrate(context, serviceName) { const { projectPath, amplifyMeta } = context.migrationInfo; const migrateResourcePromises = []; Object.keys(amplifyMeta).forEach((categoryName) => { @@ -16,12 +16,14 @@ async function migrate(context) { try { const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); if (providerController) { - migrateResourcePromises.push(providerController.migrateResource( - context, - projectPath, - amplifyMeta[category][resourceName].service, - resourceName, - )); + if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { + migrateResourcePromises.push(providerController.migrateResource( + context, + projectPath, + amplifyMeta[category][resourceName].service, + resourceName, + )); + } } else { context.print.error(`Provider not configured for ${category}: ${resourceName}`); } From e9aeed2d4aa0242fc5a25e2b94988f7f15036357 Mon Sep 17 00:00:00 2001 From: Paris Date: Thu, 7 Feb 2019 01:13:12 -0800 Subject: [PATCH 152/587] Fixing PER_REQUEST_BILLINGgit add .! Also fixing rollback behavior with updated CLI migration --- .../service-walkthroughs/appSync-walkthrough.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 753653275a..d7a84cffb0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -71,6 +71,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const parameters = { AppSyncApiName: resourceAnswers[inputs[1].key], + DynamoDBBillingMode: 'PAY_PER_REQUEST', }; // Ask auth/security question From e4670d89c877cf49853df94e7eb9afcda23c7c6e Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Mon, 11 Feb 2019 11:44:15 -0800 Subject: [PATCH 153/587] chore: bumppackage version to 1.0 --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 87f5be29a0..7e48397b92 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "0.2.1-multienv.7", + "version": "1.0.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^0.2.1-multienv.4", - "amplify-category-function": "^0.2.1-multienv.7", - "amplify-category-storage": "^0.2.1-multienv.6", + "amplify-category-auth": "^1.0.0", + "amplify-category-function": "^1.0.0", + "amplify-category-storage": "^1.0.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 5d02279828194f109540a0c99462464e94cd1119 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 11 Feb 2019 13:46:34 -0800 Subject: [PATCH 154/587] Publish - amplify-category-analytics@1.0.1 - amplify-category-api@1.0.1 - amplify-category-auth@1.0.1 - amplify-category-function@1.0.1 - amplify-category-hosting@1.0.1 - amplify-category-interactions@1.0.1 - amplify-category-notifications@1.0.1 - amplify-category-storage@1.0.1 - @aws-amplify/cli@1.0.1 - amplify-codegen@1.0.1 - amplify-frontend-android@1.0.1 - amplify-frontend-ios@1.0.1 - amplify-frontend-javascript@1.0.1 - amplify-graphql-docs-generator@1.0.1 - amplify-graphql-types-generator@1.0.1 - amplify-provider-awscloudformation@1.0.1 - graphql-auth-transformer@3.0.1 - graphql-connection-transformer@3.0.1 - graphql-dynamodb-transformer@3.0.1 - graphql-elasticsearch-transformer@3.0.1 - graphql-http-transformer@3.0.1 - graphql-mapping-template@3.0.1 - graphql-transformer-common@3.0.1 - graphql-transformer-core@3.0.1 - graphql-transformers-e2e-tests@3.0.1 - graphql-versioned-transformer@3.0.1 --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7e48397b92..050bc6ce5e 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.0", + "version": "1.0.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.0", - "amplify-category-function": "^1.0.0", - "amplify-category-storage": "^1.0.0", + "amplify-category-auth": "^1.0.1", + "amplify-category-function": "^1.0.1", + "amplify-category-storage": "^1.0.1", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 31a9afb638830a1549249bf7eb45ba54a8806220 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 11 Feb 2019 13:49:27 -0800 Subject: [PATCH 155/587] Publish - amplify-category-analytics@1.0.2 - amplify-category-api@1.0.2 - amplify-category-auth@1.0.2 - amplify-category-function@1.0.2 - amplify-category-hosting@1.0.2 - amplify-category-interactions@1.0.2 - amplify-category-notifications@1.0.2 - amplify-category-storage@1.0.2 - @aws-amplify/cli@1.0.2 - amplify-codegen@1.0.2 - amplify-frontend-android@1.0.2 - amplify-frontend-ios@1.0.2 - amplify-frontend-javascript@1.0.2 - amplify-graphql-docs-generator@1.0.2 - amplify-graphql-types-generator@1.0.2 - amplify-provider-awscloudformation@1.0.2 - graphql-auth-transformer@3.0.2 - graphql-connection-transformer@3.0.2 - graphql-dynamodb-transformer@3.0.2 - graphql-elasticsearch-transformer@3.0.2 - graphql-http-transformer@3.0.2 - graphql-mapping-template@3.0.2 - graphql-transformer-common@3.0.2 - graphql-transformer-core@3.0.2 - graphql-transformers-e2e-tests@3.0.2 - graphql-versioned-transformer@3.0.2 --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 050bc6ce5e..d48a0af2b2 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.1", + "version": "1.0.2", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.1", - "amplify-category-function": "^1.0.1", - "amplify-category-storage": "^1.0.1", + "amplify-category-auth": "^1.0.2", + "amplify-category-function": "^1.0.2", + "amplify-category-storage": "^1.0.2", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 23f1018e80709bc2a5006d8690f3362913225ae8 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Feb 2019 22:20:31 +0000 Subject: [PATCH 156/587] force publish From e9a7aee7b7f94ed946bf96a8686132285c06e7ff Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Feb 2019 22:20:36 +0000 Subject: [PATCH 157/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.0.3-beta.0 - amplify-category-api@1.0.3-beta.0 - amplify-category-auth@1.0.3-beta.0 - amplify-category-function@1.0.3-beta.0 - amplify-category-hosting@1.0.3-beta.0 - amplify-category-interactions@1.0.3-beta.0 - amplify-category-notifications@1.0.3-beta.0 - amplify-category-storage@1.0.3-beta.0 - @aws-amplify/cli@1.0.3-beta.0 - amplify-codegen@1.0.3-beta.0 - amplify-frontend-android@1.0.3-beta.0 - amplify-frontend-ios@1.0.3-beta.0 - amplify-frontend-javascript@1.0.3-beta.0 - amplify-graphql-docs-generator@1.0.3-beta.0 - amplify-graphql-types-generator@1.0.3-beta.0 - amplify-provider-awscloudformation@1.0.3-beta.0 - graphql-auth-transformer@3.0.3-beta.0 - graphql-connection-transformer@3.0.3-beta.0 - graphql-dynamodb-transformer@3.0.3-beta.0 - graphql-elasticsearch-transformer@3.0.3-beta.0 - graphql-http-transformer@3.0.3-beta.0 - graphql-mapping-template@3.0.3-beta.0 - graphql-transformer-common@3.0.3-beta.0 - graphql-transformer-core@3.0.3-beta.0 - graphql-transformers-e2e-tests@3.0.3-beta.0 - graphql-versioned-transformer@3.0.3-beta.0 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index badd9bb5cb..48bcbba05c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d48a0af2b2..f8355e3d12 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.2", + "version": "1.0.3-beta.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.2", - "amplify-category-function": "^1.0.2", - "amplify-category-storage": "^1.0.2", + "amplify-category-auth": "^1.0.3-beta.0", + "amplify-category-function": "^1.0.3-beta.0", + "amplify-category-storage": "^1.0.3-beta.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 754b30959667785a02e8f8a48a39b84ec63d4761 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Mon, 11 Feb 2019 14:55:14 -0800 Subject: [PATCH 158/587] force publish to release From cdd76835057edd0fce42de2d22241cc719e89075 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Feb 2019 23:22:36 +0000 Subject: [PATCH 159/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.0.3 - amplify-category-api@1.0.3 - amplify-category-auth@1.0.3 - amplify-category-function@1.0.3 - amplify-category-hosting@1.0.3 - amplify-category-interactions@1.0.3 - amplify-category-notifications@1.0.3 - amplify-category-storage@1.0.3 - @aws-amplify/cli@1.0.3 - amplify-codegen@1.0.3 - amplify-frontend-android@1.0.3 - amplify-frontend-ios@1.0.3 - amplify-frontend-javascript@1.0.3 - amplify-graphql-docs-generator@1.0.3 - amplify-graphql-types-generator@1.0.3 - amplify-provider-awscloudformation@1.0.3 - graphql-auth-transformer@3.0.3 - graphql-connection-transformer@3.0.3 - graphql-dynamodb-transformer@3.0.3 - graphql-elasticsearch-transformer@3.0.3 - graphql-http-transformer@3.0.3 - graphql-mapping-template@3.0.3 - graphql-transformer-common@3.0.3 - graphql-transformer-core@3.0.3 - graphql-transformers-e2e-tests@3.0.3 - graphql-versioned-transformer@3.0.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 48bcbba05c..fba5bce3bf 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f8355e3d12..5049008ae1 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.3-beta.0", + "version": "1.0.3", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.3-beta.0", - "amplify-category-function": "^1.0.3-beta.0", - "amplify-category-storage": "^1.0.3-beta.0", + "amplify-category-auth": "^1.0.3", + "amplify-category-function": "^1.0.3", + "amplify-category-storage": "^1.0.3", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From d50a656b12d33c9356dff5ea684e01c9d6abc15d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Feb 2019 23:25:43 +0000 Subject: [PATCH 160/587] chore: bump package version --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5049008ae1..0d5ac56845 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.3", + "version": "1.0.4", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.3", - "amplify-category-function": "^1.0.3", - "amplify-category-storage": "^1.0.3", + "amplify-category-auth": "^1.0.4", + "amplify-category-function": "^1.0.4", + "amplify-category-storage": "^1.0.4", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 6f6ec0a347bd35b37ec2f7d506dfa53b8ce7597e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Feb 2019 23:25:52 +0000 Subject: [PATCH 161/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.0.5 - amplify-category-api@1.0.5 - amplify-category-auth@1.0.5 - amplify-category-function@1.0.5 - amplify-category-hosting@1.0.5 - amplify-category-interactions@1.0.5 - amplify-category-notifications@1.0.5 - amplify-category-storage@1.0.5 - @aws-amplify/cli@1.0.5 - amplify-codegen@1.0.5 - amplify-frontend-android@1.0.5 - amplify-frontend-ios@1.0.5 - amplify-frontend-javascript@1.0.5 - amplify-graphql-docs-generator@1.0.5 - amplify-graphql-types-generator@1.0.5 - amplify-provider-awscloudformation@1.0.5 - graphql-auth-transformer@3.0.5 - graphql-connection-transformer@3.0.5 - graphql-dynamodb-transformer@3.0.5 - graphql-elasticsearch-transformer@3.0.5 - graphql-http-transformer@3.0.5 - graphql-mapping-template@3.0.5 - graphql-transformer-common@3.0.5 - graphql-transformer-core@3.0.5 - graphql-transformers-e2e-tests@3.0.5 - graphql-versioned-transformer@3.0.5 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fba5bce3bf..27500e7a42 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0d5ac56845..00749bf3c8 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.4", + "version": "1.0.5", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.4", - "amplify-category-function": "^1.0.4", - "amplify-category-storage": "^1.0.4", + "amplify-category-auth": "^1.0.5", + "amplify-category-function": "^1.0.5", + "amplify-category-storage": "^1.0.5", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 52abb85b3781c1c773245780daa02c696455297a Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 21 Feb 2019 15:25:59 -0800 Subject: [PATCH 162/587] fix(amplify-category-api): add check for provider during migration #918 --- packages/amplify-category-api/index.js | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 39e86076b5..f25f4cc462 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -14,15 +14,17 @@ async function migrate(context, serviceName) { if (categoryName === category) { Object.keys(amplifyMeta[category]).forEach((resourceName) => { try { - const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); - if (providerController) { - if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { - migrateResourcePromises.push(providerController.migrateResource( - context, - projectPath, - amplifyMeta[category][resourceName].service, - resourceName, - )); + if (amplifyMeta[category][resourceName].providerPlugin) { + const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + if (providerController) { + if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { + migrateResourcePromises.push(providerController.migrateResource( + context, + projectPath, + amplifyMeta[category][resourceName].service, + resourceName, + )); + } } } else { context.print.error(`Provider not configured for ${category}: ${resourceName}`); From b3d70750de2fb8c581f65de1444645380f9aa1f6 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 22 Feb 2019 01:31:59 +0000 Subject: [PATCH 163/587] chore(release): Publish [ci skip] - amplify-category-api@1.0.6 - amplify-category-function@1.0.6 - amplify-category-interactions@1.0.6 - amplify-category-storage@1.1.0 - @aws-amplify/cli@1.1.4 - amplify-provider-awscloudformation@1.0.10 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 27500e7a42..6b84009a2a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 00749bf3c8..913a6ffd88 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.5", + "version": "1.0.6", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,8 +11,8 @@ }, "dependencies": { "amplify-category-auth": "^1.0.5", - "amplify-category-function": "^1.0.5", - "amplify-category-storage": "^1.0.5", + "amplify-category-function": "^1.0.6", + "amplify-category-storage": "^1.1.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 9da284d06c2a7e62bb4f1a9d07dcb1daa1cd48a6 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 26 Feb 2019 03:04:58 +0000 Subject: [PATCH 164/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.0.6 - amplify-category-api@1.0.7 - amplify-category-auth@1.0.6 - amplify-category-function@1.0.7 - amplify-category-interactions@1.0.7 - amplify-category-notifications@1.0.6 - amplify-category-storage@1.1.1 - @aws-amplify/cli@1.1.6 - amplify-provider-awscloudformation@1.1.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6b84009a2a..55aca3990e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 913a6ffd88..8cf769b726 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.6", + "version": "1.0.7", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.5", - "amplify-category-function": "^1.0.6", - "amplify-category-storage": "^1.1.0", + "amplify-category-auth": "^1.0.6", + "amplify-category-function": "^1.0.7", + "amplify-category-storage": "^1.1.1", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 47c69e0c1e2bb6ec6b27210245972d3f99cc011d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 22 Mar 2019 01:13:44 +0000 Subject: [PATCH 165/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.0.7 - amplify-category-api@1.0.8 - amplify-category-auth@1.0.7 - amplify-category-function@1.0.8 - amplify-category-interactions@1.0.8 - amplify-category-notifications@1.0.7 - amplify-category-storage@1.1.2 - @aws-amplify/cli@1.1.8 - amplify-e2e-tests@1.1.5 - amplify-provider-awscloudformation@1.1.3 - graphql-auth-transformer@3.0.9 - graphql-connection-transformer@3.0.9 - graphql-dynamodb-transformer@3.0.9 - graphql-elasticsearch-transformer@3.0.9 - graphql-http-transformer@3.0.9 - graphql-transformer-common@3.0.6 - graphql-transformer-core@3.0.9 - graphql-transformers-e2e-tests@3.0.9 - graphql-versioned-transformer@3.0.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 55aca3990e..a9a5092e17 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8cf769b726..69c21bd5e0 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.7", + "version": "1.0.8", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.6", - "amplify-category-function": "^1.0.7", - "amplify-category-storage": "^1.1.1", + "amplify-category-auth": "^1.0.7", + "amplify-category-function": "^1.0.8", + "amplify-category-storage": "^1.1.2", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 4e3c6be407d991bbfcdac3e6cc03314455af7362 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 1 Apr 2019 18:16:29 -0700 Subject: [PATCH 166/587] feat: support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories CLI support for provisioning Cognito Hosted UI and support CRUD operations in Storage and API categories --- ...w-cloudformation-template-default.json.ejs | 885 +----------------- .../service-walkthroughs/apigw-walkthrough.js | 75 +- 2 files changed, 88 insertions(+), 872 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index e062029478..e227b47022 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -1,7 +1,6 @@ { "AWSTemplateFormatVersion": "2010-09-09", "Description": "API Gateway resource stack creation using Amplify CLI", - <% let cnt = 0 %> <% if (props.dependsOn) { %> "Parameters": { "authRoleName": { @@ -36,7 +35,6 @@ }, "Resources": { <%if (props.privacy.auth) { %> - <% cnt = 0 %> "PolicyAPIGW<%= props.apiName %>auth": { "DependsOn": [ "<%= props.apiName %>" @@ -57,8 +55,8 @@ ], "Resource": [ <% for(var i=0; i < props.paths.length; i++) { %> - <%if (props.paths[i].privacy.auth === 'rw') { %> - <% cnt++ %> + <% if (props.paths[i].privacy && props.paths[i].privacy.auth) { %> + <% for(var x=0; x < props.paths[i].privacy.auth.length; x++) { %> { "Fn::Join": [ "", @@ -85,12 +83,12 @@ } ] }, - "/*", + "<%= props.paths[i].privacy.auth[x] %>", "<%= props.paths[i].name %>/*" ] ] }, - { + { "Fn::Join": [ "", [ @@ -116,79 +114,50 @@ } ] }, - "/*", + "<%= props.paths[i].privacy.auth[x] %>", "<%= props.paths[i].name %>" ] ] } - <% if (props.privacy.auth !== cnt) { %> + <% if (x !== props.paths[i].privacy.auth.length - 1) { %> , - <% }%> <% } %> - <%if (props.paths[i].privacy.auth === 'r') { %> - <% cnt++ %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/GET", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/GET", - "<%= props.paths[i].name %>" - ] - ] - }, + <% } %> + <% if (i !== props.paths.length - 1) { %> + , + <% } %> + <% } %> + <% } %> + ] + } + ] + } + } + }, + <% } %> + <%if (props.privacy.unauth) { %> + "PolicyAPIGW<%= props.apiName %>unauth": { + "DependsOn": [ + "<%= props.apiName %>" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", + "Roles": [ + {"Ref": "unauthRoleName"} + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "execute-api:Invoke" + ], + "Resource": [ + <% for(var i=0; i < props.paths.length; i++) { %> + <% if (props.paths[i].privacy && props.paths[i].privacy.unauth) { %> + <% for(var x=0; x < props.paths[i].privacy.unauth.length; x++) { %> { "Fn::Join": [ "", @@ -215,782 +184,18 @@ } ] }, - "/HEAD", + "<%= props.paths[i].privacy.unauth[x] %>", "<%= props.paths[i].name %>/*" ] ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/HEAD", - "<%= props.paths[i].name %>" - ] - ] } - <% if (props.privacy.auth !== cnt) { %> + <% if (x !== props.paths[i].privacy.unauth.length - 1) { %> , - <% }%> <% } %> - <%if (props.paths[i].privacy.auth === 'w') { %> - <% cnt++ %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/DELETE", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/DELETE", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PATCH", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PATCH", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/POST", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/POST", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PUT", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PUT", - "<%= props.paths[i].name %>" - ] - ] - } - <% if (props.privacy.auth !== cnt) { %> - , - <% }%> <% } %> - - <% } %> - ] - } - ] - } - } - }, - <% } %> - <%if (props.privacy.unauth) { %> - <% cnt = 0 %> - "PolicyAPIGW<%= props.apiName %>unauth": { - "DependsOn": [ - "<%= props.apiName %>" - ], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", - "Roles": [ - {"Ref": "unauthRoleName"} - ], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "execute-api:Invoke" - ], - "Resource": [ - <% for(var i=0; i < props.paths.length; i++) { %> - <%if (props.paths[i].privacy.unauth === 'rw') { %> - <% cnt++ %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/*", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/*", - "<%= props.paths[i].name %>" - ] - ] - } - <% if (props.privacy.unauth !== cnt) { %> + <% if (i !== props.paths.length - 1) { %> , - <% }%> <% } %> - <%if (props.paths[i].privacy.unauth === 'r') { %> - <% cnt++ %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/GET", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/GET", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/HEAD", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/HEAD", - "<%= props.paths[i].name %>" - ] - ] - } - <% if (props.privacy.unauth !== cnt) { %> - , - <% }%> - <% } %> - <%if (props.paths[i].privacy.unauth === 'w') { %> - <% cnt++ %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/DELETE", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/DELETE", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PATCH", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PATCH", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/POST", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/POST", - "<%= props.paths[i].name %>" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PUT", - "<%= props.paths[i].name %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "/PUT", - "<%= props.paths[i].name %>" - ] - ] - } - <% if (props.privacy.unauth !== cnt) { %> - , - <% }%> <% } %> <% } %> ] diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 7b56d5327c..59e8ace10e 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -72,6 +72,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { parameters = {}; } parameters.resourceName = updateApi.resourceName; + Object.assign(allDefaultValues, parameters); answers = { ...answers, ...parameters }; [answers.uuid] = uuid().split('-'); @@ -129,8 +130,10 @@ async function pathFlow(context, answers, currentPath) { const { dependsOn } = pathsAnswer; const privacy = {}; - privacy.auth = pathsAnswer.paths.filter(path => path.privacy.auth).length; - privacy.unauth = pathsAnswer.paths.filter(path => path.privacy.unauth).length; + privacy.auth = pathsAnswer.paths + .filter(path => path.privacy.auth && path.privacy.auth.length > 0).length; + privacy.unauth = pathsAnswer.paths + .filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length; answers = { ...answers, privacy, dependsOn }; @@ -214,8 +217,16 @@ async function askPrivacy(context, answers, currentPath) { privacy: answer.privacy, }; - const { privacy: { auth: authPrivacy } } = currentPath || { privacy: {} }; - const { privacy: { unauth: unauthPrivacy } } = currentPath || { privacy: {} }; + let { privacy: { auth: authPrivacy } } = currentPath || { privacy: {} }; + let { privacy: { unauth: unauthPrivacy } } = currentPath || { privacy: {} }; + + // convert legacy permissions to CRUD structure + if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { + authPrivacy = convertToCRUD(authPrivacy); + } + if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { + unauthPrivacy = convertToCRUD(unauthPrivacy); + } if (answer.privacy === 'private') { privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); @@ -266,33 +277,28 @@ async function askPrivacy(context, answers, currentPath) { } } -async function askReadWrite(userType, context, privacy = 'r') { - while (true) { - const answer = await inquirer.prompt({ - name: 'permissions', - type: 'list', - message: `What kind of access do you want for ${userType} users`, - choices: [ - { - name: 'read', - value: 'r', - }, - { - name: 'write', - value: 'w', - }, - { - name: 'read/write', - value: 'rw', - }, - ], - default: privacy, - }); +async function askReadWrite(userType, context, privacy) { + const permissionMap = { + create: ['/POST'], + read: ['/GET'], + update: ['/PUT', '/PATCH'], + delete: ['/DELETE'], + }; - if (answer.permissions !== 'learn') { - return answer.permissions; - } + const defaults = []; + if (privacy) { + Object.values(permissionMap).forEach((el, index) => { + if (el.every(i => privacy.includes(i))) { + defaults.push(Object.keys(permissionMap)[index]); + } + }); } + + return await context.amplify.crudFlow( + userType, + permissionMap, + defaults, + ); } async function askPaths(context, answers, currentPath) { @@ -307,17 +313,14 @@ async function askPaths(context, answers, currentPath) { ]; /* - Removing this option for now in favor of multi-env support - NOT CRITICAL - if (existingLambdaArns) { choices.push({ name: 'Use a Lambda function already deployed on AWS', value: 'arn', }); } - */ if (existingFunctions) { @@ -624,6 +627,14 @@ async function migrate(context, projectPath, resourceName) { // } // return authExists; // } +function convertToCRUD(privacy) { + if (privacy === 'r') { + privacy = ['/GET']; + } else if (privacy === 'rw') { + privacy = ['/POST', '/GET', '/PUT', '/PATCH', '/DELETE']; + } + return privacy; +} module.exports = { serviceWalkthrough, updateWalkthrough, migrate }; From e03748ef889eba7cb5457d5b8d68dbbdf36118b0 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 2 Apr 2019 10:06:42 -0700 Subject: [PATCH 167/587] hosted ui release --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 69c21bd5e0..32ef729eff 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.0.8", + "version": "1.1.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.0.7", - "amplify-category-function": "^1.0.8", - "amplify-category-storage": "^1.1.2", + "amplify-category-auth": "^1.1.0", + "amplify-category-function": "^1.1.0", + "amplify-category-storage": "^1.2.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 30fbb6d5f8dc91520bad43c11e5b41f8faa156ad Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 2 Apr 2019 10:15:26 -0700 Subject: [PATCH 168/587] v1.2.0 release --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 32ef729eff..3b6448e69c 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.1.0", + "version": "1.2.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.1.0", - "amplify-category-function": "^1.1.0", - "amplify-category-storage": "^1.2.0", + "amplify-category-auth": "^1.2.0", + "amplify-category-function": "^1.2.0", + "amplify-category-storage": "^1.3.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From ccf1c410d8ebd94461e91bee0da90a647391c44b Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 2 Apr 2019 22:04:51 -0700 Subject: [PATCH 169/587] v1.5 release --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3b6448e69c..babc0822a1 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.2.0", + "version": "1.3.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.2.0", - "amplify-category-function": "^1.2.0", - "amplify-category-storage": "^1.3.0", + "amplify-category-auth": "^1.3.0", + "amplify-category-function": "^1.3.0", + "amplify-category-storage": "^1.4.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 395e3659e1efe506bddbc781d998fe69d82872c8 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 3 Apr 2019 05:55:34 +0000 Subject: [PATCH 170/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.3.1 - amplify-category-api@1.4.0 - amplify-category-auth@1.4.0 - amplify-category-function@1.3.1 - amplify-category-interactions@1.3.1 - amplify-category-notifications@1.3.1 - amplify-category-storage@1.5.0 - amplify-category-xr@1.4.0 - @aws-amplify/cli@1.5.0 - amplify-codegen@1.3.1 - amplify-e2e-tests@1.4.1 - amplify-frontend-android@1.4.0 - amplify-frontend-ios@1.4.0 - amplify-frontend-javascript@1.4.0 - amplify-graphql-docs-generator@1.3.1 - amplify-provider-awscloudformation@1.5.0 - graphql-auth-transformer@3.4.0 - graphql-connection-transformer@3.3.1 - graphql-dynamodb-transformer@3.3.1 - graphql-elasticsearch-transformer@3.4.0 - graphql-http-transformer@3.3.1 - graphql-transformer-common@3.4.0 - graphql-transformer-core@3.4.0 - graphql-transformers-e2e-tests@3.3.1 - graphql-versioned-transformer@3.3.1 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a9a5092e17..d722fd1ca2 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index babc0822a1..7c9bb04b73 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.3.0", + "version": "1.4.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.3.0", - "amplify-category-function": "^1.3.0", - "amplify-category-storage": "^1.4.0", + "amplify-category-auth": "^1.4.0", + "amplify-category-function": "^1.3.1", + "amplify-category-storage": "^1.5.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 859d1c9b85ca00522325988dc11eb90fb5632926 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Tue, 9 Apr 2019 15:26:54 -0700 Subject: [PATCH 171/587] CLI v1.6 release --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7c9bb04b73..76b5dd97c6 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.4.0", + "version": "1.5.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.4.0", - "amplify-category-function": "^1.3.1", - "amplify-category-storage": "^1.5.0", + "amplify-category-auth": "^1.5.0", + "amplify-category-function": "^1.4.0", + "amplify-category-storage": "^1.6.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From 629a45ad8161339f9c6f46ca0244a1ab36734df1 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 9 Apr 2019 23:38:55 +0000 Subject: [PATCH 172/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.1 - amplify-category-api@1.5.1 - amplify-category-auth@1.5.1 - amplify-category-function@1.4.1 - amplify-category-interactions@1.4.1 - amplify-category-notifications@1.4.1 - amplify-category-storage@1.6.1 - amplify-category-xr@1.5.1 - @aws-amplify/cli@1.6.1 - amplify-codegen@1.4.1 - amplify-e2e-tests@1.5.1 - amplify-frontend-android@1.5.1 - amplify-frontend-ios@1.5.1 - amplify-frontend-javascript@1.5.1 - amplify-graphql-docs-generator@1.4.1 - amplify-provider-awscloudformation@1.6.1 - graphql-auth-transformer@3.5.1 - graphql-connection-transformer@3.4.1 - graphql-dynamodb-transformer@3.4.1 - graphql-elasticsearch-transformer@3.5.1 - graphql-http-transformer@3.4.1 - graphql-transformer-common@3.5.1 - graphql-transformer-core@3.5.1 - graphql-transformers-e2e-tests@3.4.1 - graphql-versioned-transformer@3.4.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d722fd1ca2..e9787f7cf6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 76b5dd97c6..1d4ea35874 100755 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.0", + "version": "1.5.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.5.0", - "amplify-category-function": "^1.4.0", - "amplify-category-storage": "^1.6.0", + "amplify-category-auth": "^1.5.1", + "amplify-category-function": "^1.4.1", + "amplify-category-storage": "^1.6.1", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "inquirer": "^6.0.0", From a8901562146f680a53d997ad7a1dbd5053e8340c Mon Sep 17 00:00:00 2001 From: Ashwin Devendran Date: Mon, 15 Apr 2019 16:28:20 -0700 Subject: [PATCH 173/587] =?UTF-8?q?feat('add-graphql-datasource'=20command?= =?UTF-8?q?)=20+=20graphql-relational-schema-t=E2=80=A6=20(#1213)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Adding 'add-graphql-datasource' command --- packages/amplify-category-api/Readme.md | 1 + packages/amplify-category-api/commands/api.js | 4 + .../commands/api/add-datasource.js | 194 ++++++++++++++++++ packages/amplify-category-api/index.js | 96 ++++++++- packages/amplify-category-api/package.json | 5 + .../provider-utils/awscloudformation/index.js | 9 +- .../appSync-rds-walkthrough.js | 183 +++++++++++++++++ .../provider-utils/supported-datasources.json | 39 ++++ 8 files changed, 528 insertions(+), 3 deletions(-) create mode 100644 packages/amplify-category-api/commands/api/add-datasource.js mode change 100755 => 100644 packages/amplify-category-api/package.json create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js create mode 100644 packages/amplify-category-api/provider-utils/supported-datasources.json diff --git a/packages/amplify-category-api/Readme.md b/packages/amplify-category-api/Readme.md index f0f038b80f..3fa520a15e 100644 --- a/packages/amplify-category-api/Readme.md +++ b/packages/amplify-category-api/Readme.md @@ -7,6 +7,7 @@ The following table lists the current set of commands supported by the Amplify A | 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. | diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index eb8f48a5f2..2202629d00 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -33,6 +33,10 @@ module.exports = { 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', + }, ]; context.amplify.showHelp(header, commands); diff --git a/packages/amplify-category-api/commands/api/add-datasource.js b/packages/amplify-category-api/commands/api/add-datasource.js new file mode 100644 index 0000000000..5a12ec1b62 --- /dev/null +++ b/packages/amplify-category-api/commands/api/add-datasource.js @@ -0,0 +1,194 @@ +const fs = require('fs-extra'); +const inquirer = require('inquirer'); +const graphql = require('graphql'); +const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); +const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); +const { mergeTypes } = require('merge-graphql-schemas'); + +const subcommand = 'add-graphql-datasource'; +const categories = 'categories'; +const category = 'api'; +const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-datasources.json`)); + +const rdsRegion = 'rdsRegion'; +const rdsIdentifier = 'rdsClusterIdentifier'; +const rdsSecretStoreArn = 'rdsSecretStoreArn'; +const rdsDatabaseName = 'rdsDatabaseName'; +const rdsResourceName = 'rdsResourceName'; +const rdsDatasource = 'rdsDatasource'; +const rdsInit = 'rdsInit'; + +module.exports = { + name: subcommand, + run: async (context) => { + const { amplify } = context; + let resourceName; + let datasource; + let databaseName; + return datasourceSelectionPrompt(context, servicesMetadata) + .then((result) => { + datasource = result.datasource; // eslint-disable-line prefer-destructuring + + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + + return providerController.addDatasource(context, category, result.datasource); + }) + .then((answers) => { + resourceName = answers.resourceName; // eslint-disable-line prefer-destructuring + databaseName = answers.databaseName; // eslint-disable-line prefer-destructuring + + /** + * Write the new env specific datasource information into + * the team-provider-info file + */ + const currEnv = amplify.getEnvInfo().envName; + const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); + const teamProviderInfo = JSON.parse(fs.readFileSync(teamProviderInfoFilePath)); + + if (!teamProviderInfo[currEnv][categories]) { + teamProviderInfo[currEnv][categories] = {}; + } + + if (!teamProviderInfo[currEnv][categories][category]) { + teamProviderInfo[currEnv][categories][category] = {}; + } + + if (!teamProviderInfo[currEnv][categories][category][resourceName]) { + teamProviderInfo[currEnv][categories][category][resourceName] = {}; + } + + teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] + = answers.region; + teamProviderInfo[currEnv][categories][category][resourceName][rdsIdentifier] + = answers.dbClusterArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] + = answers.secretStoreArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] + = answers.databaseName; + + fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); + + const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); + const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + + backendConfig[category][resourceName][rdsInit] = true; + + fs.writeFileSync(backendConfigFilePath, JSON.stringify(backendConfig, null, 4)); + + /** + * Load the MySqlRelationalDBReader + */ + // eslint-disable-next-line max-len + const dbReader = new AuroraServerlessMySQLDatabaseReader(answers.region, answers.secretStoreArn, answers.dbClusterArn, answers.databaseName); + + + /** + * Instantiate a new Relational Schema Transformer and perform + * the db instrospection to get the GraphQL Schema and Template Context + */ + const relationalSchemaTransformer = + new RelationalDBSchemaTransformer(dbReader, answers.databaseName); + return relationalSchemaTransformer.introspectDatabaseSchema(); + }).then((graphqlSchemaContext) => { + const projectBackendDirPath = amplify.pathManager.getBackendDirPath(); + + /** + * Merge the GraphQL Schema with the existing schema.graphql in the projects stack + * + */ + const apiDirPath = `${projectBackendDirPath}/${category}/${resourceName}`; + fs.ensureDirSync(apiDirPath); + const graphqlSchemaFilePath = `${apiDirPath}/schema.graphql`; + fs.ensureFileSync(graphqlSchemaFilePath); + const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath, 'utf8'); + const currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); + + const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; + + const concatGraphQLSchemaDoc + = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); + + fs.writeFileSync(graphqlSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); + const resolversDir = `${projectBackendDirPath}/${category}/${resourceName}/resolvers`; + + /** + * Instantiate a new Relational Template Generator and create + * the template and relational resolvers + */ + const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); + context[rdsResourceName] = resourceName; + context[rdsDatasource] = datasource; + let template = templateGenerator.createTemplate(context); + template = templateGenerator.addRelationalResolvers(template, resolversDir); + const cfn = templateGenerator.printCloudformationTemplate(template); + + /** + * Add the generated the CFN to the appropriate nested stacks directory + */ + const stacksDir = `${projectBackendDirPath}/${category}/${resourceName}/stacks`; + const writeToPath = `${stacksDir}/${resourceName}-${databaseName}-rds.json`; + fs.writeFileSync(writeToPath, cfn, 'utf8'); + + return datasource; + }) + .then((datasourceName) => { + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + return datasourceName; + }) + .then((datasourceName) => { + const { print } = context; + print.success(`Successfully added the ${datasourceName} datasource locally`); + print.info(''); + print.success('Some next steps:'); + print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); + print.info('"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud'); + print.info(''); + }) + .catch((err) => { + context.print.info(err.stack); + context.print.error('There was an error adding the datasource'); + }); + }, +}; + +function datasourceSelectionPrompt(context, supportedDatasources) { + 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) { + context.print.error(`No datasources defined by configured providers for category: ${category}`); + process.exit(1); + } + + if (options.length === 1) { + // No need to ask questions + context.print.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 datasources', + type: 'list', + choices: options, + }]; + + return inquirer.prompt(question) + .then(answer => answer.datasource); +} diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index f25f4cc462..f7570073ca 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -1,7 +1,8 @@ const { run } = require('./commands/api/console'); +const fs = require('fs-extra'); const category = 'api'; - +const categories = 'categories'; async function console(context) { await run(context); @@ -40,7 +41,100 @@ async function migrate(context, serviceName) { await Promise.all(migrateResourcePromises); } +async function initEnv(context) { + const datasource = 'Aurora Serverless'; + const service = 'service'; + const rdsInit = 'rdsInit'; + const rdsRegion = 'rdsRegion'; + const rdsClusterIdentifier = 'rdsClusterIdentifier'; + const rdsSecretStoreArn = 'rdsSecretStoreArn'; + const rdsDatabaseName = 'rdsDatabaseName'; + + const { amplify } = context; + + /** + * Check if we need to do the walkthrough, by looking to see if previous environments have + * configured an RDS datasource + */ + const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); + const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + + let resourceName; + const apis = Object.keys(backendConfig[category]); + for (let i = 0; i < apis.length; i += 1) { + if (backendConfig[category][apis[i]][service] === 'AppSync') { + resourceName = apis[i]; + break; + } + } + + // If an AppSync API does not exist, no need to prompt for rds datasource + if (!resourceName) { + return; + } + + // If an AppSync API has not been initialized with RDS, no need to prompt + if (!backendConfig[category][resourceName][rdsInit]) { + return; + } + + const providerController = require('./provider-utils/awscloudformation/index'); + + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + + /** + * Check team provider info to ensure it hasn't already been created for current env + */ + const currEnv = amplify.getEnvInfo().envName; + const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); + const teamProviderInfo = JSON.parse(fs.readFileSync(teamProviderInfoFilePath)); + if (teamProviderInfo[currEnv][categories] + && teamProviderInfo[currEnv][categories][category] + && teamProviderInfo[currEnv][categories][category][resourceName] + && teamProviderInfo[currEnv][categories][category][resourceName] + && teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion]) { + return; + } + + /** + * Execute the walkthrough + */ + return providerController.addDatasource(context, category, datasource) + .then((answers) => { + /** + * Write the new answers to the team provider info + */ + if (!teamProviderInfo[currEnv][categories]) { + teamProviderInfo[currEnv][categories] = {}; + } + if (!teamProviderInfo[currEnv][categories][category]) { + teamProviderInfo[currEnv][categories][category] = {}; + } + if (!teamProviderInfo[currEnv][categories][category][resourceName]) { + teamProviderInfo[currEnv][categories][category][resourceName] = {}; + } + + teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] + = answers.region; + teamProviderInfo[currEnv][categories][category][resourceName][rdsClusterIdentifier] + = answers.dbClusterArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] + = answers.secretStoreArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] + = answers.databaseName; + + fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); + }) + .then(() => { + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + }); +} + module.exports = { console, migrate, + initEnv, }; diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json old mode 100755 new mode 100644 index 1d4ea35874..26e8fa18c6 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,11 +13,16 @@ "amplify-category-auth": "^1.5.1", "amplify-category-function": "^1.4.1", "amplify-category-storage": "^1.6.1", + "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", + "graphql": "^0.13.2", + "graphql-relational-schema-transformer": "^1.0.0", "inquirer": "^6.0.0", + "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", "opn": "^5.3.0", + "ora": "^3.0.0", "uuid": "^2.0.3" }, "devDependencies": { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 7ec077f67f..159c0766eb 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -99,7 +99,6 @@ function addResource(context, category, service, options) { }); } - async function updateResource(context, category, service) { let answers; serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; @@ -165,6 +164,12 @@ async function migrateResource(context, projectPath, service, resourceName) { return await migrate(context, projectPath, resourceName); } +function addDatasource(context, category, datasource) { + serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-datasources.json`))[datasource]; + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename); +} + module.exports = { - addResource, updateResource, console, migrateResource, + addResource, updateResource, console, migrateResource, addDatasource, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js new file mode 100644 index 0000000000..e322d18271 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -0,0 +1,183 @@ +const inquirer = require('inquirer'); +const AWS = require('aws-sdk'); +const ora = require('ora'); +const { DataApiParams } = require('graphql-relational-schema-transformer'); + +const spinner = ora(''); +const category = 'api'; + +async function serviceWalkthrough(context, defaultValuesFilename, datasourceMetadata) { + const amplifyMeta = context.amplify.getProjectMeta(); + + // Verify that an API exists in the project before proceeding. + if (Object.keys(amplifyMeta[category]).length === 0) { + context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); + process.exit(0); + } + + // Loop through to find the AppSync API Resource Name + let appSyncApi; + const apis = Object.keys(amplifyMeta[category]); + + for (let i = 0; i < apis.length; i += 1) { + if (amplifyMeta[category][apis[i]].service === 'AppSync') { + appSyncApi = apis[i]; + break; + } + } + + // If an AppSync API does not exist, inform the user to create the AppSync API + if (!appSyncApi) { + context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); + process.exit(0); + } + + const { inputs, availableRegions } = datasourceMetadata; + + // Region Question + const selectedRegion = await promptWalkthroughQuestion(inputs, 0, availableRegions); + + // Prepare the SDK with the region + AWS.config.update({ + region: selectedRegion, + }); + + // RDS Cluster Question + const { selectedClusterArn, clusterResourceId } = await selectCluster(inputs); + + // Secret Store Question + const selectedSecretArn = await getSecretStoreArn(inputs, clusterResourceId); + + // Database Name Question + const selectedDatabase = await selectDatabase(inputs, selectedClusterArn, selectedSecretArn); + + return { + region: selectedRegion, + dbClusterArn: selectedClusterArn, + secretStoreArn: selectedSecretArn, + databaseName: selectedDatabase, + resourceName: appSyncApi, + }; +} + +/** + * + * @param {*} inputs + */ +async function selectCluster(inputs) { + const RDS = new AWS.RDS(); + + const describeDBClustersResult = await RDS.describeDBClusters().promise(); + const rawClusters = describeDBClustersResult.DBClusters; + const clusters = new Map(); + + for (let i = 0; i < rawClusters.length; i += 1) { + if (rawClusters[i].EngineMode === 'serverless') { + clusters.set(rawClusters[i].DBClusterIdentifier, rawClusters[i]); + } + } + + const clusterIdentifier = await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); + const selectedCluster = clusters.get(clusterIdentifier); + + return { + selectedClusterArn: selectedCluster.DBClusterArn, + clusterResourceId: selectedCluster.DbClusterResourceId, + }; +} + +/** + * + * @param {*} inputs + * @param {*} clusterResourceId + */ +async function getSecretStoreArn(inputs, clusterResourceId) { + const SecretsManager = new AWS.SecretsManager(); + + const listSecretsResult = await SecretsManager.listSecrets().promise(); + const rawSecrets = listSecretsResult.SecretList; + const secrets = new Map(); + + let selectedSecretArn; + + for (let i = 0; i < rawSecrets.length; i += 1) { + /** + * Attempt to auto-detect Secret Store that was created by Aurora Serverless + * as it follows a specfic format for the Secret Name + */ + if (rawSecrets[i].Name.startsWith(`rds-db-credentials/${clusterResourceId}`)) { + // Found the secret store - store the details and break out. + selectedSecretArn = rawSecrets[i].ARN; + break; + } + secrets.set(rawSecrets[i].Name, rawSecrets[i].ARN); + } + + if (!selectedSecretArn) { + // Kick off questions flow + const selectedSecretName + = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); + selectedSecretArn = secrets.get(selectedSecretName); + } + + return selectedSecretArn; +} + +/** + * + * @param {*} inputs + * @param {*} clusterArn + * @param {*} secretArn + */ +async function selectDatabase(inputs, clusterArn, secretArn) { + // Database Name Question + const DataApi = new AWS.RDSDataService(); + const params = new DataApiParams(); + params.awsSecretStoreArn = secretArn; + params.dbClusterOrInstanceArn = clusterArn; + params.sqlStatements = 'SHOW databases'; + + spinner.start('Fetching Aurora Serverless cluster...'); + const dataApiResult = await DataApi.executeSql(params).promise(); + + // eslint-disable-next-line prefer-destructuring + const records + = dataApiResult.sqlStatementResults[0].resultFrame.records; + const databaseList = []; + + for (let i = 0; i < records.length; i += 1) { + const recordValue = records[i].values[0].stringValue; + // ignore the three meta tables that the cluster creates + if (!['information_schema', 'performance_schema', 'mysql'].includes(recordValue)) { + databaseList.push(recordValue); + } + } + + spinner.succeed('Fetched Aurora Serverless cluster.'); + + return await promptWalkthroughQuestion(inputs, 3, databaseList); +} + +/** + * + * @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, + }, + ]; + + const answer = await inquirer.prompt(question); + return answer[inputs[questionNumber].key]; +} + +module.exports = { + serviceWalkthrough, +}; diff --git a/packages/amplify-category-api/provider-utils/supported-datasources.json b/packages/amplify-category-api/provider-utils/supported-datasources.json new file mode 100644 index 0000000000..8e9475f17c --- /dev/null +++ b/packages/amplify-category-api/provider-utils/supported-datasources.json @@ -0,0 +1,39 @@ +{ + "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", + "defaultValuesFilename": "appSync-rds-defaults.js", + "serviceWalkthroughFilename": "appSync-rds-walkthrough.js", + "cfnFilename": "appSync-rds-cloudformation-template-default.yml.ejs", + "provider": "awscloudformation", + "availableRegions": ["us-east-1"] + } +} \ No newline at end of file From 3c93ab6ba5891f630fedfb7cde7e1a6fe4489399 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 16 Apr 2019 18:38:19 +0000 Subject: [PATCH 174/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.2 - amplify-category-api@1.5.2 - amplify-category-auth@1.5.2 - amplify-category-function@1.4.2 - amplify-category-interactions@1.4.2 - amplify-category-notifications@1.4.2 - amplify-category-storage@1.6.2 - amplify-category-xr@1.5.2 - @aws-amplify/cli@1.6.2 - amplify-codegen@1.4.2 - amplify-e2e-tests@1.5.2 - amplify-graphql-types-generator@1.0.9 - amplify-provider-awscloudformation@1.7.0 - graphql-auth-transformer@3.6.0 - graphql-connection-transformer@3.4.2 - graphql-dynamodb-transformer@3.4.2 - graphql-elasticsearch-transformer@3.5.2 - graphql-http-transformer@3.4.2 - graphql-relational-schema-transformer@1.0.1 - graphql-transformer-common@3.6.0 - graphql-transformer-core@3.6.0 - graphql-transformers-e2e-tests@3.5.0 - graphql-versioned-transformer@3.4.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e9787f7cf6..fe04435887 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 26e8fa18c6..c1891af1d0 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.1", + "version": "1.5.2", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.5.1", - "amplify-category-function": "^1.4.1", - "amplify-category-storage": "^1.6.1", + "amplify-category-auth": "^1.5.2", + "amplify-category-function": "^1.4.2", + "amplify-category-storage": "^1.6.2", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.0", + "graphql-relational-schema-transformer": "^1.0.1", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From f5f2f98a5c517ad84649cafe942d9d0e4abcac85 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 16 Apr 2019 23:38:27 +0000 Subject: [PATCH 175/587] chore(release): Publish [ci skip] - amplify-category-api@1.5.3 - @aws-amplify/cli@1.6.3 - graphql-relational-schema-transformer@1.0.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fe04435887..f7ea074fb9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c1891af1d0..5e3f2a649f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.2", + "version": "1.5.3", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.1", + "graphql-relational-schema-transformer": "^1.0.2", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From e559ffc96062f590cbdbde9a604a7ba6ea2f62cc Mon Sep 17 00:00:00 2001 From: Ashwin Devendran Date: Mon, 22 Apr 2019 21:11:55 -0700 Subject: [PATCH 176/587] Adding small fixes for add-graphql-datasource (#1333) --- .../commands/api/add-datasource.js | 11 ++++- .../appSync-rds-walkthrough.js | 40 ++++++++++++++----- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-datasource.js b/packages/amplify-category-api/commands/api/add-datasource.js index 5a12ec1b62..0c401dd705 100644 --- a/packages/amplify-category-api/commands/api/add-datasource.js +++ b/packages/amplify-category-api/commands/api/add-datasource.js @@ -8,6 +8,7 @@ const { mergeTypes } = require('merge-graphql-schemas'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; +const providerName = 'awscloudformation'; const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-datasources.json`)); const rdsRegion = 'rdsRegion'; @@ -25,6 +26,7 @@ module.exports = { let resourceName; let datasource; let databaseName; + const AWS = await getAwsClient(context, 'list'); return datasourceSelectionPrompt(context, servicesMetadata) .then((result) => { datasource = result.datasource; // eslint-disable-line prefer-destructuring @@ -79,11 +81,12 @@ module.exports = { fs.writeFileSync(backendConfigFilePath, JSON.stringify(backendConfig, null, 4)); + /** * Load the MySqlRelationalDBReader */ // eslint-disable-next-line max-len - const dbReader = new AuroraServerlessMySQLDatabaseReader(answers.region, answers.secretStoreArn, answers.dbClusterArn, answers.databaseName); + const dbReader = new AuroraServerlessMySQLDatabaseReader(answers.region, answers.secretStoreArn, answers.dbClusterArn, answers.databaseName, AWS); /** @@ -192,3 +195,9 @@ function datasourceSelectionPrompt(context, supportedDatasources) { return inquirer.prompt(question) .then(answer => answer.datasource); } + +async function getAwsClient(context, action) { + 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/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index e322d18271..07b7030c0f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -1,10 +1,10 @@ const inquirer = require('inquirer'); -const AWS = require('aws-sdk'); const ora = require('ora'); const { DataApiParams } = require('graphql-relational-schema-transformer'); const spinner = ora(''); const category = 'api'; +const providerName = 'awscloudformation'; async function serviceWalkthrough(context, defaultValuesFilename, datasourceMetadata) { const amplifyMeta = context.amplify.getProjectMeta(); @@ -37,19 +37,21 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // Region Question const 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 - const { selectedClusterArn, clusterResourceId } = await selectCluster(inputs); + const { selectedClusterArn, clusterResourceId } = await selectCluster(inputs, AWS); // Secret Store Question - const selectedSecretArn = await getSecretStoreArn(inputs, clusterResourceId); + const selectedSecretArn = await getSecretStoreArn(inputs, clusterResourceId, AWS); // Database Name Question - const selectedDatabase = await selectDatabase(inputs, selectedClusterArn, selectedSecretArn); + const selectedDatabase = await selectDatabase(inputs, selectedClusterArn, selectedSecretArn, AWS); return { region: selectedRegion, @@ -64,7 +66,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta * * @param {*} inputs */ -async function selectCluster(inputs) { +async function selectCluster(inputs, AWS) { const RDS = new AWS.RDS(); const describeDBClustersResult = await RDS.describeDBClusters().promise(); @@ -91,13 +93,25 @@ async function selectCluster(inputs) { * @param {*} inputs * @param {*} clusterResourceId */ -async function getSecretStoreArn(inputs, clusterResourceId) { +async function getSecretStoreArn(inputs, clusterResourceId, AWS) { const SecretsManager = new AWS.SecretsManager(); + const NextToken = 'NextToken'; + let rawSecrets = []; + const params = { + MaxResults: 20, + }; - const listSecretsResult = await SecretsManager.listSecrets().promise(); - const rawSecrets = listSecretsResult.SecretList; - const secrets = new Map(); + 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(); let selectedSecretArn; for (let i = 0; i < rawSecrets.length; i += 1) { @@ -129,7 +143,7 @@ async function getSecretStoreArn(inputs, clusterResourceId) { * @param {*} clusterArn * @param {*} secretArn */ -async function selectDatabase(inputs, clusterArn, secretArn) { +async function selectDatabase(inputs, clusterArn, secretArn, AWS) { // Database Name Question const DataApi = new AWS.RDSDataService(); const params = new DataApiParams(); @@ -178,6 +192,12 @@ async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) { return answer[inputs[questionNumber].key]; } +async function getAwsClient(context, action) { + const providerPlugins = context.amplify.getProviderPlugins(context); + const provider = require(providerPlugins[providerName]); + return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); +} + module.exports = { serviceWalkthrough, }; From 673c20214a2fd192dbfe4bbc14e8b80906bb1306 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 24 Apr 2019 02:29:27 +0000 Subject: [PATCH 177/587] chore(release): Publish [ci skip] - amplify-category-api@1.5.4 - amplify-category-xr@1.5.3 - @aws-amplify/cli@1.6.4 - amplify-frontend-android@1.5.2 - graphql-relational-schema-transformer@1.0.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f7ea074fb9..ef21d079e3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5e3f2a649f..919dd74d84 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.3", + "version": "1.5.4", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.2", + "graphql-relational-schema-transformer": "^1.0.3", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From ca98779c95117db3ed31d1fdd922172dcba0e23c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 25 Apr 2019 22:44:38 +0000 Subject: [PATCH 178/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.3 - amplify-category-api@1.5.5 - amplify-category-auth@1.5.3 - amplify-category-function@1.4.3 - amplify-category-interactions@1.4.3 - amplify-category-notifications@1.4.3 - amplify-category-storage@1.6.3 - amplify-category-xr@1.5.4 - @aws-amplify/cli@1.6.5 - amplify-provider-awscloudformation@1.7.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ef21d079e3..0bc752f169 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 919dd74d84..da200e3a72 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.4", + "version": "1.5.5", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.5.2", - "amplify-category-function": "^1.4.2", - "amplify-category-storage": "^1.6.2", + "amplify-category-auth": "^1.5.3", + "amplify-category-function": "^1.4.3", + "amplify-category-storage": "^1.6.3", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 0e3475dfdf4dcd575dc00c5a4a67c4c042546fa0 Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Mon, 29 Apr 2019 15:02:22 -0700 Subject: [PATCH 179/587] fix: update CLI to handle UTF8 BOM (#1357) Some editors and platforms can add UTF BOM at the begining of the file. Node JSON.parse doesn't handle the BOM enchoding very well and chokes the CLI. Updating the CLI to use a util method which can handle the BOM chars fix #1355 #1122 --- .../commands/api/add-datasource.js | 4 ++-- packages/amplify-category-api/index.js | 4 ++-- .../provider-utils/awscloudformation/index.js | 10 +++++----- .../service-walkthroughs/apigw-walkthrough.js | 4 ++-- .../service-walkthroughs/appSync-walkthrough.js | 6 +++--- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-datasource.js b/packages/amplify-category-api/commands/api/add-datasource.js index 0c401dd705..fdfdd607ee 100644 --- a/packages/amplify-category-api/commands/api/add-datasource.js +++ b/packages/amplify-category-api/commands/api/add-datasource.js @@ -49,7 +49,7 @@ module.exports = { */ const currEnv = amplify.getEnvInfo().envName; const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); - const teamProviderInfo = JSON.parse(fs.readFileSync(teamProviderInfoFilePath)); + const teamProviderInfo = context.amplify.readJsonFile(teamProviderInfoFilePath); if (!teamProviderInfo[currEnv][categories]) { teamProviderInfo[currEnv][categories] = {}; @@ -75,7 +75,7 @@ module.exports = { fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); backendConfig[category][resourceName][rdsInit] = true; diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index f7570073ca..66b7f9afae 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -57,7 +57,7 @@ async function initEnv(context) { * configured an RDS datasource */ const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + const backendConfig = amplify.readJsonFile(backendConfigFilePath); let resourceName; const apis = Object.keys(backendConfig[category]); @@ -90,7 +90,7 @@ async function initEnv(context) { */ const currEnv = amplify.getEnvInfo().envName; const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); - const teamProviderInfo = JSON.parse(fs.readFileSync(teamProviderInfoFilePath)); + const teamProviderInfo = amplify.readJsonFile(teamProviderInfoFilePath); if (teamProviderInfo[currEnv][categories] && teamProviderInfo[currEnv][categories][category] && teamProviderInfo[currEnv][categories][category][resourceName] diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 159c0766eb..2a1adffc88 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -33,7 +33,7 @@ function copyCfnTemplate(context, category, options, cfnFilename) { function console(context, service) { - serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; const { serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; const { openConsole } = require(serviceWalkthroughSrc); @@ -48,7 +48,7 @@ function console(context, service) { function addResource(context, category, service, options) { let answers; - serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; let { cfnFilename } = serviceMetadata; const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); @@ -101,7 +101,7 @@ function addResource(context, category, service, options) { async function updateResource(context, category, service) { let answers; - serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; let { cfnFilename } = serviceMetadata; const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; @@ -151,7 +151,7 @@ async function updateResource(context, category, service) { } async function migrateResource(context, projectPath, service, resourceName) { - serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-services.json`))[service]; + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; const { serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; const { migrate } = require(serviceWalkthroughSrc); @@ -165,7 +165,7 @@ async function migrateResource(context, projectPath, service, resourceName) { } function addDatasource(context, category, datasource) { - serviceMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../supported-datasources.json`))[datasource]; + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-datasources.json`)[datasource]; const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 59e8ace10e..8bbee3b09a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -67,7 +67,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); let parameters; try { - parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + parameters = context.amplify.readJsonFile(parametersFilePath); } catch (e) { parameters = {}; } @@ -578,7 +578,7 @@ async function migrate(context, projectPath, resourceName) { const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); let parameters; try { - parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + parameters = amplify.readJsonFile(parametersFilePath); } catch (e) { context.print.error(`Error reading api-params.json file for ${resourceName} resource`); throw e; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index d7a84cffb0..646fda456d 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -261,7 +261,7 @@ async function updateWalkthrough(context) { let parameters = {}; try { - parameters = JSON.parse(fs.readFileSync(parametersFilePath)); + parameters = context.amplify.readJsonFile(parametersFilePath); } catch (e) { context.print.error('Parameters file not found'); context.print.info(e.stack); @@ -270,14 +270,14 @@ async function updateWalkthrough(context) { const authType = await askSecurityQuestions(context, parameters); const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - const amplifyMeta = JSON.parse(fs.readFileSync(amplifyMetaFilePath)); + const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); amplifyMeta[category][resourceName].output.securityType = authType; let jsonString = JSON.stringify(amplifyMeta, null, '\t'); fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = JSON.parse(fs.readFileSync(backendConfigFilePath)); + const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); backendConfig[category][resourceName].output.securityType = authType; jsonString = JSON.stringify(backendConfig, null, '\t'); From a5d29f70f5abdd2fd0804b2979beab15b1b97a94 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 30 Apr 2019 20:53:54 +0000 Subject: [PATCH 180/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.4 - amplify-category-api@1.5.6 - amplify-category-auth@1.5.4 - amplify-category-function@1.4.4 - amplify-category-hosting@1.1.1 - amplify-category-interactions@1.4.4 - amplify-category-notifications@1.4.4 - amplify-category-storage@1.6.4 - amplify-category-xr@1.5.5 - @aws-amplify/cli@1.6.6 - amplify-codegen@1.5.0 - amplify-frontend-android@1.6.0 - amplify-frontend-ios@1.6.0 - amplify-frontend-javascript@1.6.0 - amplify-graphql-types-generator@1.0.10 - amplify-provider-awscloudformation@1.8.0 - graphql-elasticsearch-transformer@3.5.3 - graphql-transformers-e2e-tests@3.5.1 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 0bc752f169..23fca77f48 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index da200e3a72..7583b66034 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.5", + "version": "1.5.6", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.5.3", - "amplify-category-function": "^1.4.3", - "amplify-category-storage": "^1.6.3", + "amplify-category-auth": "^1.5.4", + "amplify-category-function": "^1.4.4", + "amplify-category-storage": "^1.6.4", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From d416d07e65efd46c707ddd99b95bec3a061ad190 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 7 May 2019 21:42:40 +0000 Subject: [PATCH 181/587] chore(release): Publish [ci skip] - amplify-category-api@1.5.7 - @aws-amplify/cli@1.6.8 - amplify-frontend-android@1.8.0 - amplify-frontend-ios@1.8.0 - amplify-provider-awscloudformation@1.9.0 - graphql-auth-transformer@3.6.2 - graphql-connection-transformer@3.4.4 - graphql-dynamodb-transformer@3.6.0 - graphql-elasticsearch-transformer@3.5.4 - graphql-http-transformer@3.4.4 - graphql-mapping-template@3.0.6 - graphql-relational-schema-transformer@1.0.4 - graphql-transformer-common@3.6.1 - graphql-transformer-core@3.6.1 - graphql-transformers-e2e-tests@3.5.3 - graphql-versioned-transformer@3.4.4 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 23fca77f48..4b6490580e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7583b66034..85ab90f760 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.6", + "version": "1.5.7", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.3", + "graphql-relational-schema-transformer": "^1.0.4", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 4cde912548c3a0603a65fcd74319e206d18408c4 Mon Sep 17 00:00:00 2001 From: ashwindevendran Date: Thu, 9 May 2019 15:20:26 -0700 Subject: [PATCH 182/587] fixing npe where add-graphql-datasource fails if user doesn't have an API created beforehand --- .../service-walkthroughs/appSync-rds-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 07b7030c0f..f24e44fc7f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -10,7 +10,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta const amplifyMeta = context.amplify.getProjectMeta(); // Verify that an API exists in the project before proceeding. - if (Object.keys(amplifyMeta[category]).length === 0) { + if (amplifyMeta == null || amplifyMeta[category] == null || Object.keys(amplifyMeta[category]).length === 0) { context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); process.exit(0); } From 6cb84cbfb0dbf402b30eca945e6dfaaa6f2d3652 Mon Sep 17 00:00:00 2001 From: ashwindevendran Date: Thu, 9 May 2019 15:20:26 -0700 Subject: [PATCH 183/587] fixing npe where add-graphql-datasource fails if user doesn't have an API created beforehand fixing lint issue fixing lint issues --- .../service-walkthroughs/appSync-rds-walkthrough.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index f24e44fc7f..9ce67256af 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -10,7 +10,8 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 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) { + if (amplifyMeta == null || amplifyMeta[category] == null + || Object.keys(amplifyMeta[category]).length === 0) { context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); process.exit(0); } From 58a9f24b826328c4e6041949b6f7a9580837a9dd Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Fri, 10 May 2019 17:15:31 -0700 Subject: [PATCH 184/587] chore: pin package versions (#1439) --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 85ab90f760..1aa31d0883 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.5.4", - "amplify-category-function": "^1.4.4", - "amplify-category-storage": "^1.6.4", + "amplify-category-auth": "1.5.4", + "amplify-category-function": "1.4.4", + "amplify-category-storage": "1.6.4", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.4", + "graphql-relational-schema-transformer": "1.0.4", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 757b8d6f751a02f741928a14074fc4c04e5a7f5b Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 17 May 2019 00:26:09 +0000 Subject: [PATCH 185/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.5 - amplify-category-api@1.5.8 - amplify-category-auth@1.5.5 - amplify-category-function@1.4.5 - amplify-category-hosting@1.1.2 - amplify-category-interactions@1.4.5 - amplify-category-notifications@1.4.5 - amplify-category-storage@1.6.5 - amplify-category-xr@1.5.6 - @aws-amplify/cli@1.6.9 - amplify-codegen@1.5.1 - amplify-frontend-android@1.8.1 - amplify-frontend-ios@1.8.1 - amplify-provider-awscloudformation@1.9.1 - graphql-auth-transformer@3.6.3 - graphql-connection-transformer@3.4.5 - graphql-dynamodb-transformer@3.6.1 - graphql-elasticsearch-transformer@3.5.5 - graphql-function-transformer@1.0.1 - graphql-http-transformer@3.4.5 - graphql-relational-schema-transformer@1.0.5 - graphql-transformer-common@3.6.2 - graphql-transformer-core@3.6.2 - graphql-transformers-e2e-tests@3.5.4 - graphql-versioned-transformer@3.4.5 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4b6490580e..1b5dbc0d47 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1aa31d0883..28e5739719 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.7", + "version": "1.5.8", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.5.4", - "amplify-category-function": "1.4.4", - "amplify-category-storage": "1.6.4", + "amplify-category-auth": "1.5.5", + "amplify-category-function": "1.4.5", + "amplify-category-storage": "1.6.5", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.4", + "graphql-relational-schema-transformer": "1.0.5", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 7acd3dd5176a7a3e0dbb99974f14e078d3cdde8a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 21 May 2019 19:54:01 +0000 Subject: [PATCH 186/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.4.6 - amplify-category-api@1.5.9 - amplify-category-auth@1.5.6 - amplify-category-function@1.4.6 - amplify-category-interactions@1.4.6 - amplify-category-notifications@1.4.6 - amplify-category-storage@1.6.6 - amplify-category-xr@1.5.7 - @aws-amplify/cli@1.6.10 - amplify-codegen@1.5.2 - amplify-graphql-types-generator@1.0.11 - amplify-provider-awscloudformation@1.10.0 - graphql-auth-transformer@3.6.4 - graphql-connection-transformer@3.4.6 - graphql-dynamodb-transformer@3.7.0 - graphql-elasticsearch-transformer@3.6.0 - graphql-function-transformer@1.0.2 - graphql-http-transformer@3.4.6 - graphql-relational-schema-transformer@1.0.6 - graphql-transformer-common@3.7.0 - graphql-transformer-core@3.6.3 - graphql-transformers-e2e-tests@3.5.5 - graphql-versioned-transformer@3.4.6 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1b5dbc0d47..c407d023b6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 28e5739719..9d3870bdfa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.8", + "version": "1.5.9", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.5.5", - "amplify-category-function": "1.4.5", - "amplify-category-storage": "1.6.5", + "amplify-category-auth": "1.5.6", + "amplify-category-function": "1.4.6", + "amplify-category-storage": "1.6.6", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.5", + "graphql-relational-schema-transformer": "1.0.6", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From bca8881a2d42f99753fd704335896ffed1293a90 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 24 May 2019 00:06:53 +0000 Subject: [PATCH 187/587] chore(release): Publish [ci skip] - amplify-category-api@1.5.10 - @aws-amplify/cli@1.6.11 - graphql-relational-schema-transformer@1.0.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index c407d023b6..8e06dfbec7 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9d3870bdfa..b8f2e3303b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.9", + "version": "1.5.10", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.6", + "graphql-relational-schema-transformer": "1.0.7", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From e7afdba619de8c8adf7a3e3f9b6ebf77a3cccd87 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 28 May 2019 21:06:38 -0700 Subject: [PATCH 188/587] feat: flow to add policies to access amplify resources from Lambda (#1462) * feat: flow to add policies to access amplify resources from Lambda * changes based on feedback * fix variable names * chnage var names to camel-case * fix error messages * fix region string issue * fix wording for resource selection * fix resource cyclic-dependency issues * change JSON.parse to context.amplify.readJSON * modify AppSync CRUD permissions --- packages/amplify-category-api/index.js | 30 ++++++++++ .../provider-utils/awscloudformation/index.js | 16 +++++- .../service-walkthroughs/apigw-walkthrough.js | 57 ++++++++++++++++++- .../appSync-walkthrough.js | 47 ++++++++++++++- 4 files changed, 147 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 66b7f9afae..e0377b29a4 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -133,8 +133,38 @@ async function initEnv(context) { }); } +async function getPermissionPolicies(context, resourceOpsMapping) { + const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); + const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); + const permissionPolicies = []; + const resourceAttributes = []; + + Object.keys(resourceOpsMapping).forEach((resourceName) => { + try { + const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + if (providerController) { + const { policy, attributes } = providerController.getPermissionPolicies( + context, + amplifyMeta[category][resourceName].service, + resourceName, + resourceOpsMapping[resourceName], + ); + permissionPolicies.push(policy); + resourceAttributes.push({ resourceName, attributes, category }); + } else { + context.print.error(`Provider not configured for ${category}: ${resourceName}`); + } + } catch (e) { + context.print.warning(`Could not get policies for ${category}: ${resourceName}`); + throw e; + } + }); + return { permissionPolicies, resourceAttributes }; +} + module.exports = { console, migrate, initEnv, + getPermissionPolicies, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 2a1adffc88..0236823e5a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -170,6 +170,20 @@ function addDatasource(context, category, datasource) { return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename); } +function getPermissionPolicies(context, service, resourceName, crudOptions) { + serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; + const { serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { getIAMPolicies } = require(serviceWalkthroughSrc); + + if (!getPermissionPolicies) { + context.print.info(`No policies found for ${resourceName}`); + return; + } + + return getIAMPolicies(resourceName, crudOptions); +} + module.exports = { - addResource, updateResource, console, migrateResource, addDatasource, + addResource, updateResource, console, migrateResource, addDatasource, getPermissionPolicies, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 8bbee3b09a..481592ce26 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -637,4 +637,59 @@ function convertToCRUD(privacy) { return privacy; } -module.exports = { serviceWalkthrough, updateWalkthrough, migrate }; + +function getIAMPolicies(resourceName, crudOptions) { + let policy = {}; + const actions = []; + + crudOptions.forEach((crudOption) => { + switch (crudOption) { + case 'create': actions.push( + 'apigateway:POST', + 'apigateway:PUT', + ); + break; + case 'update': actions.push('apigateway:PATCH'); + break; + case 'read': actions.push( + 'apigateway:GET', 'apigateway:HEAD', + 'apigateway:OPTIONS', + ); + break; + case 'delete': actions.push('apigateway:DELETE'); + break; + default: console.log(`${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']; + + return { policy, attributes }; +} + +module.exports = { + serviceWalkthrough, updateWalkthrough, migrate, getIAMPolicies, +}; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 646fda456d..b713abfb94 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -375,7 +375,52 @@ async function migrate(context) { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true, migrate: true }); } +function getIAMPolicies(resourceName, crudOptions) { + let policy = {}; + const actions = []; + + crudOptions.forEach((crudOption) => { + switch (crudOption) { + case 'create': actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); + 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: console.log(`${crudOption} not supported`); + } + }); + + policy = { + Effect: 'Allow', + Action: actions, + Resource: [ + { + 'Fn::Join': [ + '', + [ + 'arn:aws:appsync:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':apis/', + { + Ref: `${category}${resourceName}GraphQLAPIIdOutput`, + }, + ], + ], + }, + ], + }; + + const attributes = ['GraphQLAPIIdOutput']; + + return { policy, attributes }; +} + module.exports = { - serviceWalkthrough, updateWalkthrough, openConsole, migrate, + serviceWalkthrough, updateWalkthrough, openConsole, migrate, getIAMPolicies, }; From 2a543fec159eb793b8787ead3d3bd7abdf13fc37 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 29 May 2019 18:30:35 +0000 Subject: [PATCH 189/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.0 - amplify-category-api@1.6.0 - amplify-category-auth@1.6.0 - amplify-category-function@1.5.0 - amplify-category-hosting@1.2.0 - amplify-category-interactions@1.5.0 - amplify-category-notifications@1.4.7 - amplify-category-storage@1.7.0 - amplify-category-xr@1.6.0 - @aws-amplify/cli@1.7.0 - amplify-provider-awscloudformation@1.11.0 - graphql-auth-transformer@3.7.0 - graphql-connection-transformer@3.5.0 - graphql-dynamodb-transformer@3.8.0 - graphql-elasticsearch-transformer@3.6.1 - graphql-function-transformer@1.1.0 - graphql-http-transformer@3.4.7 - graphql-key-transformer@1.1.0 - graphql-mapping-template@3.1.0 - graphql-relational-schema-transformer@1.0.8 - graphql-transformer-common@3.8.0 - graphql-transformer-core@3.7.0 - graphql-transformers-e2e-tests@3.6.0 - graphql-versioned-transformer@3.4.7 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8e06dfbec7..9e24442f82 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b8f2e3303b..3b53ef52f2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.5.10", + "version": "1.6.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.5.6", - "amplify-category-function": "1.4.6", - "amplify-category-storage": "1.6.6", + "amplify-category-auth": "1.6.0", + "amplify-category-function": "1.5.0", + "amplify-category-storage": "1.7.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.7", + "graphql-relational-schema-transformer": "1.0.8", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 8249c8d413648620ed772e089f24c7cf1cb595f2 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 6 Jun 2019 23:28:09 +0000 Subject: [PATCH 190/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.1 - amplify-category-api@1.6.1 - amplify-category-auth@1.6.1 - amplify-category-function@1.5.1 - amplify-category-hosting@1.2.1 - amplify-category-interactions@1.5.1 - amplify-category-notifications@1.4.8 - amplify-category-storage@1.7.1 - amplify-category-xr@1.6.1 - @aws-amplify/cli@1.7.1 - amplify-codegen@1.5.3 - amplify-graphql-docs-generator@1.4.2 - amplify-provider-awscloudformation@1.11.1 - graphql-key-transformer@1.1.1 - graphql-transformers-e2e-tests@3.6.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9e24442f82..8b50595b30 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3b53ef52f2..a0025afef1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.6.0", + "version": "1.6.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.6.0", - "amplify-category-function": "1.5.0", - "amplify-category-storage": "1.7.0", + "amplify-category-auth": "1.6.1", + "amplify-category-function": "1.5.1", + "amplify-category-storage": "1.7.1", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 50b6ed535848eb71682ea8ff36c24da5dd56cedd Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 10 Jun 2019 12:49:12 -0700 Subject: [PATCH 191/587] fix: fixing the IAM policies for AppSync API (#1634) --- .../service-walkthroughs/appSync-walkthrough.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b713abfb94..2d4c052cd3 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -409,6 +409,7 @@ function getIAMPolicies(resourceName, crudOptions) { { Ref: `${category}${resourceName}GraphQLAPIIdOutput`, }, + '/*', ], ], }, From 203ca3d543a34ab4a59b7b2886d74cdad45c9a66 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 10 Jun 2019 15:03:16 -0700 Subject: [PATCH 192/587] feat: add graphQLEndpoint as an env var to lambda functions (#1641) re #1620 --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 2d4c052cd3..9eb1afa974 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -416,7 +416,7 @@ function getIAMPolicies(resourceName, crudOptions) { ], }; - const attributes = ['GraphQLAPIIdOutput']; + const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; return { policy, attributes }; } From 2489d3de45552e27344bc0291d3c490eb507a333 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 11 Jun 2019 19:44:25 +0000 Subject: [PATCH 193/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.2 - amplify-category-api@1.7.0 - amplify-category-auth@1.6.2 - amplify-category-function@1.5.2 - amplify-category-interactions@1.5.2 - amplify-category-notifications@1.4.9 - amplify-category-storage@1.7.2 - amplify-category-xr@1.6.2 - @aws-amplify/cli@1.7.2 - amplify-codegen@1.5.4 - amplify-frontend-javascript@1.6.1 - amplify-provider-awscloudformation@1.11.2 - graphql-key-transformer@1.1.2 - graphql-transformers-e2e-tests@3.6.2 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8b50595b30..0a499917a7 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a0025afef1..adc3db9906 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.6.1", + "version": "1.7.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.6.1", - "amplify-category-function": "1.5.1", - "amplify-category-storage": "1.7.1", + "amplify-category-auth": "1.6.2", + "amplify-category-function": "1.5.2", + "amplify-category-storage": "1.7.2", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 724d79d89f588063a46d4794963ba2ccb51a9de4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 12 Jun 2019 22:41:37 +0000 Subject: [PATCH 194/587] chore(release): Publish [ci skip] - amplify-category-api@1.7.1 - amplify-category-interactions@1.5.3 - @aws-amplify/cli@1.7.3 - amplify-codegen@1.5.5 - amplify-e2e-tests@1.5.3 - amplify-graphql-docs-generator@1.4.3 - amplify-graphql-types-generator@1.0.12 - amplify-provider-awscloudformation@1.11.3 - graphql-auth-transformer@3.7.1 - graphql-connection-transformer@3.5.1 - graphql-dynamodb-transformer@3.8.1 - graphql-elasticsearch-transformer@3.6.2 - graphql-function-transformer@1.1.1 - graphql-http-transformer@3.4.8 - graphql-key-transformer@1.1.3 - graphql-mapping-template@3.1.1 - graphql-relational-schema-transformer@1.0.9 - graphql-transformer-common@3.8.1 - graphql-transformer-core@3.7.1 - graphql-transformers-e2e-tests@3.6.3 - graphql-versioned-transformer@3.4.8 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 0a499917a7..d63faf91bd 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index adc3db9906..cea60f6df9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.0", + "version": "1.7.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.8", + "graphql-relational-schema-transformer": "1.0.9", "inquirer": "^6.0.0", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From e78c451270324475cb94c6b87de6ada170f25d45 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 18 Jun 2019 19:24:47 +0000 Subject: [PATCH 195/587] chore(release): Publish [ci skip] - amplify-category-api@1.7.2 - amplify-category-function@1.5.3 - amplify-category-interactions@1.5.4 - @aws-amplify/cli@1.7.4 - amplify-provider-awscloudformation@1.11.4 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d63faf91bd..6a1874beb5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index cea60f6df9..b32e39145f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.1", + "version": "1.7.2", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,7 +11,7 @@ }, "dependencies": { "amplify-category-auth": "1.6.2", - "amplify-category-function": "1.5.2", + "amplify-category-function": "1.5.3", "amplify-category-storage": "1.7.2", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", From a2ac1a7baa1ec7b10a75ba68f2074dc8f9e7eb50 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Thu, 20 Jun 2019 08:57:26 -0700 Subject: [PATCH 196/587] fix(cli): fix inquirer version (#1690) pin inquirer version to 6.3.1 fix #1688 --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b32e39145f..b7df491cf4 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -18,7 +18,7 @@ "fs-extra": "^7.0.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "1.0.9", - "inquirer": "^6.0.0", + "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", "opn": "^5.3.0", From 5c3f8323ae3bdad5a75e10c9a7f643512e574a05 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 20 Jun 2019 18:09:38 +0000 Subject: [PATCH 197/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.3 - amplify-category-api@1.7.3 - amplify-category-auth@1.6.3 - amplify-category-function@1.5.4 - amplify-category-hosting@1.2.2 - amplify-category-interactions@1.5.5 - amplify-category-notifications@1.4.10 - amplify-category-storage@1.7.3 - amplify-category-xr@1.6.3 - @aws-amplify/cli@1.7.5 - amplify-codegen@1.5.6 - amplify-frontend-android@1.8.2 - amplify-frontend-ios@1.8.2 - amplify-frontend-javascript@1.6.2 - amplify-provider-awscloudformation@1.11.5 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6a1874beb5..f08ecc3a1b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b7df491cf4..50330644ae 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.2", + "version": "1.7.3", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.6.2", - "amplify-category-function": "1.5.3", - "amplify-category-storage": "1.7.2", + "amplify-category-auth": "1.6.3", + "amplify-category-function": "1.5.4", + "amplify-category-storage": "1.7.3", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 8ee27bb910499d9326a80488551e41e100623344 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Sun, 23 Jun 2019 16:26:15 -0700 Subject: [PATCH 198/587] fix(amplify-category-api): fix init env bug (#1715) fix #1713 --- packages/amplify-category-api/index.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index e0377b29a4..6960003859 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -59,6 +59,10 @@ async function initEnv(context) { const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); const backendConfig = amplify.readJsonFile(backendConfigFilePath); + if (!backendConfig[category]) { + return; + } + let resourceName; const apis = Object.keys(backendConfig[category]); for (let i = 0; i < apis.length; i += 1) { From 9c346287751bee5fb8baac8bc55594b1cb7feab5 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 26 Jun 2019 08:08:53 +0000 Subject: [PATCH 199/587] chore(release): Publish [ci skip] - amplify-category-api@1.7.4 - amplify-category-function@1.6.0 - amplify-category-interactions@1.5.6 - amplify-category-storage@1.7.4 - @aws-amplify/cli@1.7.6 - amplify-provider-awscloudformation@1.12.0 - graphql-auth-transformer@3.7.2 - graphql-connection-transformer@3.5.2 - graphql-dynamodb-transformer@3.8.2 - graphql-elasticsearch-transformer@3.6.3 - graphql-function-transformer@1.1.2 - graphql-http-transformer@3.4.9 - graphql-key-transformer@1.1.4 - graphql-relational-schema-transformer@1.0.10 - graphql-transformer-common@3.8.2 - graphql-transformer-core@3.7.2 - graphql-transformers-e2e-tests@3.6.4 - graphql-versioned-transformer@3.4.9 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f08ecc3a1b..94b54a2822 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 50330644ae..f7b2f7db25 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.3", + "version": "1.7.4", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -11,13 +11,13 @@ }, "dependencies": { "amplify-category-auth": "1.6.3", - "amplify-category-function": "1.5.4", - "amplify-category-storage": "1.7.3", + "amplify-category-function": "1.6.0", + "amplify-category-storage": "1.7.4", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.9", + "graphql-relational-schema-transformer": "1.0.10", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 45b5f146d2b1b9b55e71c4c2d166a5511e4d95bc Mon Sep 17 00:00:00 2001 From: Ghosh Date: Sun, 30 Jun 2019 14:32:09 -0700 Subject: [PATCH 200/587] bumping version to 1.7.7 --- packages/amplify-category-api/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f7b2f7db25..9b6deac855 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.4", + "version": "1.7.5", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.10", + "graphql-relational-schema-transformer": "^1.0.11", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 1f892d48845f3b87ea4a7c8633109c6da025a9c0 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 30 Jun 2019 22:47:24 +0000 Subject: [PATCH 201/587] chore(release): Publish [ci skip] - amplify-category-api@1.7.6 - @aws-amplify/cli@1.7.8 - amplify-e2e-tests@1.5.5 - amplify-provider-awscloudformation@1.12.2 - graphql-auth-transformer@3.7.4 - graphql-connection-transformer@3.5.4 - graphql-dynamodb-transformer@3.8.4 - graphql-elasticsearch-transformer@3.6.5 - graphql-function-transformer@1.1.4 - graphql-http-transformer@3.4.11 - graphql-key-transformer@1.1.6 - graphql-relational-schema-transformer@1.0.12 - graphql-transformer-core@3.7.4 - graphql-transformers-e2e-tests@3.6.6 - graphql-versioned-transformer@3.4.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 94b54a2822..bb0f1bcaae 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9b6deac855..a8e09e0bcd 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.5", + "version": "1.7.6", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.11", + "graphql-relational-schema-transformer": "1.0.12", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From dee083c989bd6aa1d7906450e99218a4891aac89 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 9 Jul 2019 19:58:56 +0000 Subject: [PATCH 202/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.4 - amplify-category-api@1.7.7 - amplify-category-auth@1.7.0 - amplify-category-function@1.7.0 - amplify-category-interactions@1.6.0 - amplify-category-notifications@1.4.11 - amplify-category-storage@1.8.0 - amplify-category-xr@1.6.4 - @aws-amplify/cli@1.8.0 - amplify-e2e-tests@1.6.0 - amplify-provider-awscloudformation@1.13.0 - graphql-transformers-e2e-tests@3.6.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index bb0f1bcaae..1761e8a3ca 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a8e09e0bcd..dfc70d2502 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.6", + "version": "1.7.7", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.6.3", - "amplify-category-function": "1.6.0", - "amplify-category-storage": "1.7.4", + "amplify-category-auth": "1.7.0", + "amplify-category-function": "1.7.0", + "amplify-category-storage": "1.8.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 2f8a215088d8a09e2a5bcd5fb275c81656c875d7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 10 Jul 2019 17:41:17 +0000 Subject: [PATCH 203/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.5 - amplify-category-api@1.7.8 - amplify-category-auth@1.7.1 - amplify-category-function@1.7.1 - amplify-category-interactions@1.6.1 - amplify-category-notifications@1.4.12 - amplify-category-storage@1.8.1 - amplify-category-xr@1.6.5 - @aws-amplify/cli@1.8.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1761e8a3ca..fb988c56bf 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index dfc70d2502..98e4bb4643 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.7", + "version": "1.7.8", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.7.0", - "amplify-category-function": "1.7.0", - "amplify-category-storage": "1.8.0", + "amplify-category-auth": "1.7.1", + "amplify-category-function": "1.7.1", + "amplify-category-storage": "1.8.1", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 64f63f51398d12858675d4b9933c33d335e7aabd Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Thu, 18 Jul 2019 10:32:38 -0700 Subject: [PATCH 204/587] chore(cli): manual update versions (#1857) --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 98e4bb4643..64fb519a38 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.8", + "version": "1.7.9", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.7.1", - "amplify-category-function": "1.7.1", - "amplify-category-storage": "1.8.1", + "amplify-category-auth": "^1.7.2", + "amplify-category-function": "^1.7.2", + "amplify-category-storage": "^1.8.2", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From 3f211479d668f87cdb9332e3c670363eabd6fd23 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 23 Jul 2019 19:31:09 +0000 Subject: [PATCH 205/587] chore(release): Publish [ci skip] - amplify-category-analytics@1.5.7 - amplify-category-api@1.7.10 - amplify-category-auth@1.7.3 - amplify-category-function@1.7.3 - amplify-category-interactions@1.6.3 - amplify-category-notifications@1.4.14 - amplify-category-storage@1.8.3 - amplify-category-xr@1.6.7 - @aws-amplify/cli@1.8.3 - amplify-codegen@1.5.7 - amplify-e2e-tests@1.6.2 - amplify-frontend-javascript@1.6.3 - amplify-provider-awscloudformation@1.13.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fb988c56bf..aaabbd6f18 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 64fb519a38..3bc683a12b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.9", + "version": "1.7.10", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.7.2", - "amplify-category-function": "^1.7.2", - "amplify-category-storage": "^1.8.2", + "amplify-category-auth": "1.7.3", + "amplify-category-function": "1.7.3", + "amplify-category-storage": "1.8.3", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", From e69c251e8cce7e5076097e228ba33823194be0ec Mon Sep 17 00:00:00 2001 From: Michael Date: Tue, 23 Jul 2019 19:24:03 -0700 Subject: [PATCH 206/587] Adding parameter to configure server side encryption (#1887) --- .../service-walkthroughs/appSync-walkthrough.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 9eb1afa974..1660cc992f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -72,6 +72,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const parameters = { AppSyncApiName: resourceAnswers[inputs[1].key], DynamoDBBillingMode: 'PAY_PER_REQUEST', + DynamoDBEnableServerSideEncryption: 'false', }; // Ask auth/security question From bf2b40420423dbd57053d18de94b53c543a9785e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 24 Jul 2019 03:49:48 +0000 Subject: [PATCH 207/587] chore(release): Publish [ci skip] - amplify-category-api@1.7.11 - @aws-amplify/cli@1.8.4 - amplify-provider-awscloudformation@1.13.2 - graphql-auth-transformer@3.7.5 - graphql-connection-transformer@3.5.5 - graphql-dynamodb-transformer@3.8.5 - graphql-elasticsearch-transformer@3.6.6 - graphql-function-transformer@1.1.5 - graphql-http-transformer@3.4.12 - graphql-key-transformer@1.1.7 - graphql-relational-schema-transformer@1.0.13 - graphql-transformer-common@3.8.3 - graphql-transformer-core@3.7.5 - graphql-transformers-e2e-tests@3.6.8 - graphql-versioned-transformer@3.4.12 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index aaabbd6f18..5ad79dfa8e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3bc683a12b..d0a0fd7de5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.10", + "version": "1.7.11", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -17,7 +17,7 @@ "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.12", + "graphql-relational-schema-transformer": "1.0.13", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 810b0ba450a41ab91de717b8863e798d72bc4a86 Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 25 Jul 2019 11:59:10 -0700 Subject: [PATCH 208/587] feat: sanity check (#1815) * Removing unused parameter * Adding support for Retain deletion policy for DynamoDB tables created by @model * Adding migration test to amplify-e2e-tests * Adding tests for common issues that can result from key changes. * Adding support for situation where you add and remove index at the same time. Adding more tests that cover @connection migration issues * Breaking up api migration tests into multiple files so they run in parallel. * Adding test for DeletionPolicy flag in transform.config.json. Renaming all projects to lowercase without dashes to make CLI happy. * Adding one more test that revealed a false positive detection * Removing retain policy * Adding back text 'There was an error pushing the API resource' * Fixing lint errors --- packages/amplify-category-api/commands/api/gql-compile.js | 3 +-- packages/amplify-category-api/commands/api/push.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 6542155aa4..7752a81d06 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -6,8 +6,7 @@ module.exports = { try { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); } catch (err) { - context.print.info(err.stack); - context.print.error(err.message); + context.print.error(err.toString()); } }, }; diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index fcb5573123..683ca6a54f 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -9,8 +9,8 @@ module.exports = { context.amplify.constructExeInfo(context); return amplify.pushResources(context, category, resourceName) .catch((err) => { - context.print.info(err.stack); context.print.error('There was an error pushing the API resource'); + context.print.error(err.toString()); }); }, }; From e1610bf53b1955babad4b69542f241855f65d272 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 31 Jul 2019 09:35:09 -0700 Subject: [PATCH 209/587] feat: adding amplify cli predictions category (#1936) --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d0a0fd7de5..276a6e3dc5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.11", + "version": "1.7.12", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.7.3", - "amplify-category-function": "1.7.3", - "amplify-category-storage": "1.8.3", + "amplify-category-auth": "^1.7.4", + "amplify-category-function": "^1.7.4", + "amplify-category-storage": "^1.8.4", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.0.13", + "graphql-relational-schema-transformer": "^1.0.14", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 9643525549e32a1ce6f4e6d07d02dec93b3c4714 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 31 Jul 2019 10:21:36 -0700 Subject: [PATCH 210/587] chore(release): Publish [ci skip] (#1940) - amplify-category-analytics@1.6.0 - amplify-category-api@1.8.0 - amplify-category-auth@1.8.0 - amplify-category-function@1.8.0 - amplify-category-hosting@1.3.0 - amplify-category-interactions@1.7.0 - amplify-category-notifications@1.5.0 - amplify-category-predictions@1.1.0 - amplify-category-storage@1.9.0 - amplify-category-xr@1.7.0 - @aws-amplify/cli@1.9.0 - amplify-codegen@1.6.0 - amplify-e2e-tests@1.7.0 - amplify-frontend-android@1.9.0 - amplify-frontend-ios@1.9.0 - amplify-frontend-javascript@1.7.0 - amplify-graphql-docs-generator@1.5.0 - amplify-graphql-types-generator@1.1.0 - amplify-provider-awscloudformation@1.14.0 - graphql-auth-transformer@3.8.0 - graphql-connection-transformer@3.6.0 - graphql-dynamodb-transformer@3.9.0 - graphql-elasticsearch-transformer@3.7.0 - graphql-function-transformer@1.2.0 - graphql-http-transformer@3.5.0 - graphql-key-transformer@1.2.0 - graphql-mapping-template@3.2.0 - graphql-relational-schema-transformer@1.1.0 - graphql-transformer-common@3.9.0 - graphql-transformer-core@3.8.0 - graphql-transformers-e2e-tests@3.7.0 - graphql-versioned-transformer@3.5.0 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5ad79dfa8e..5ca11fabbc 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 276a6e3dc5..001cd1efee 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.7.12", + "version": "1.8.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^1.7.4", - "amplify-category-function": "^1.7.4", - "amplify-category-storage": "^1.8.4", + "amplify-category-auth": "1.8.0", + "amplify-category-function": "1.8.0", + "amplify-category-storage": "1.9.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^1.0.14", + "graphql-relational-schema-transformer": "1.1.0", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 9c2c201792594ee84ac913efb977b9701783b1a2 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Thu, 1 Aug 2019 17:40:12 -0700 Subject: [PATCH 211/587] chore(release): Publish [ci skip] (#1958) - amplify-category-analytics@1.7.0 - amplify-category-api@1.9.0 - amplify-category-auth@1.9.0 - amplify-category-function@1.9.0 - amplify-category-hosting@1.4.0 - amplify-category-interactions@1.8.0 - amplify-category-notifications@1.6.0 - amplify-category-predictions@1.2.0 - amplify-category-storage@1.10.0 - amplify-category-xr@1.8.0 - @aws-amplify/cli@1.10.0 - amplify-codegen@1.7.0 - amplify-e2e-tests@1.8.0 - amplify-frontend-android@1.10.0 - amplify-frontend-ios@1.10.0 - amplify-frontend-javascript@1.8.0 - amplify-graphql-docs-generator@1.6.0 - amplify-graphql-types-generator@1.2.0 - amplify-provider-awscloudformation@1.15.0 - graphql-auth-transformer@3.9.0 - graphql-connection-transformer@3.7.0 - graphql-dynamodb-transformer@3.10.0 - graphql-elasticsearch-transformer@3.8.0 - graphql-function-transformer@1.3.0 - graphql-http-transformer@3.6.0 - graphql-key-transformer@1.3.0 - graphql-mapping-template@3.3.0 - graphql-relational-schema-transformer@1.2.0 - graphql-transformer-common@3.10.0 - graphql-transformer-core@3.9.0 - graphql-transformers-e2e-tests@3.8.0 - graphql-versioned-transformer@3.6.0 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5ca11fabbc..c7782df6e9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 001cd1efee..e598e40722 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.8.0", + "version": "1.9.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.8.0", - "amplify-category-function": "1.8.0", - "amplify-category-storage": "1.9.0", + "amplify-category-auth": "1.9.0", + "amplify-category-function": "1.9.0", + "amplify-category-storage": "1.10.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.1.0", + "graphql-relational-schema-transformer": "1.2.0", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From a34b19620a07bcf3c835f980e2084cc76b7cea2e Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 7 Aug 2019 14:40:02 -0700 Subject: [PATCH 212/587] chore(release): Publish [ci skip] (#1993) - amplify-appsync-simulator@0.2.0 - amplify-category-analytics@1.8.0 - amplify-category-api@1.10.0 - amplify-category-auth@1.10.0 - amplify-category-function@1.10.0 - amplify-category-hosting@1.5.0 - amplify-category-interactions@1.9.0 - amplify-category-notifications@1.7.0 - amplify-category-predictions@1.3.0 - amplify-category-storage@1.11.0 - amplify-category-xr@1.9.0 - @aws-amplify/cli@1.11.0 - amplify-codegen@1.8.0 - amplify-dynamodb-simulator@0.2.0 - amplify-e2e-tests@1.9.0 - amplify-frontend-android@1.11.0 - amplify-frontend-ios@1.11.0 - amplify-frontend-javascript@1.9.0 - amplify-graphiql-explorer@0.2.0 - amplify-graphql-docs-generator@1.7.0 - amplify-graphql-types-generator@1.3.0 - amplify-provider-awscloudformation@1.16.0 - amplify-storage-simulator@0.2.0 - amplify-util-mock@0.2.0 - amplify-velocity-template@0.1.0 - graphql-auth-transformer@3.10.0 - graphql-connection-transformer@3.8.0 - graphql-dynamodb-transformer@3.11.0 - graphql-elasticsearch-transformer@3.9.0 - graphql-function-transformer@1.4.0 - graphql-http-transformer@3.7.0 - graphql-key-transformer@1.4.0 - graphql-mapping-template@3.4.0 - graphql-relational-schema-transformer@1.3.0 - graphql-transformer-common@3.11.0 - graphql-transformer-core@3.10.0 - graphql-transformers-e2e-tests@3.9.0 - graphql-versioned-transformer@3.7.0 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index c7782df6e9..b4d1f12ae2 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e598e40722..0c164d2691 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.9.0", + "version": "1.10.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.9.0", - "amplify-category-function": "1.9.0", - "amplify-category-storage": "1.10.0", + "amplify-category-auth": "1.10.0", + "amplify-category-function": "1.10.0", + "amplify-category-storage": "1.11.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.2.0", + "graphql-relational-schema-transformer": "1.3.0", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 4ea0bb23f424be243d5c28fc61f24e2ed4f83b54 Mon Sep 17 00:00:00 2001 From: Warren McQuinn Date: Thu, 8 Aug 2019 16:47:46 -0500 Subject: [PATCH 213/587] fix(amplify-provider-awscloudformation): apigw unauth access (#1906) --- ...w-cloudformation-template-default.json.ejs | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index e227b47022..244f836f80 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -188,6 +188,37 @@ "<%= props.paths[i].name %>/*" ] ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "<%= props.paths[i].privacy.unauth[x] %>", + "<%= props.paths[i].name %>" + ] + ] } <% if (x !== props.paths[i].privacy.unauth.length - 1) { %> , From 1d921174934ed7cead022ff0a84cba525b6b281a Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 13 Aug 2019 16:28:44 -0700 Subject: [PATCH 214/587] chore(release): Publish [ci skip] (#2039) - amplify-appsync-simulator@0.3.0 - amplify-category-analytics@1.9.0 - amplify-category-api@1.11.0 - amplify-category-auth@1.11.0 - amplify-category-function@1.11.0 - amplify-category-hosting@1.6.0 - amplify-category-interactions@1.10.0 - amplify-category-notifications@1.8.0 - amplify-category-predictions@1.4.0 - amplify-category-storage@1.12.0 - amplify-category-xr@1.10.0 - @aws-amplify/cli@1.12.0 - amplify-codegen@1.9.0 - amplify-dynamodb-simulator@0.3.0 - amplify-e2e-tests@1.10.0 - amplify-frontend-android@1.12.0 - amplify-frontend-ios@1.12.0 - amplify-frontend-javascript@1.10.0 - amplify-graphiql-explorer@0.3.0 - amplify-graphql-docs-generator@1.8.0 - amplify-graphql-types-generator@1.4.0 - amplify-provider-awscloudformation@1.17.0 - amplify-storage-simulator@0.3.0 - amplify-util-mock@0.3.0 - amplify-velocity-template@0.2.0 - graphql-auth-transformer@3.11.0 - graphql-connection-transformer@3.9.0 - graphql-dynamodb-transformer@3.12.0 - graphql-elasticsearch-transformer@3.10.0 - graphql-function-transformer@1.5.0 - graphql-http-transformer@3.8.0 - graphql-key-transformer@1.5.0 - graphql-mapping-template@3.5.0 - graphql-relational-schema-transformer@1.4.0 - graphql-transformer-common@3.12.0 - graphql-transformer-core@3.11.0 - graphql-transformers-e2e-tests@3.10.0 - graphql-versioned-transformer@3.8.0 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index b4d1f12ae2..a4a15001b0 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0c164d2691..40d04a9743 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.10.0", + "version": "1.11.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,14 +10,14 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.10.0", - "amplify-category-function": "1.10.0", - "amplify-category-storage": "1.11.0", + "amplify-category-auth": "1.11.0", + "amplify-category-function": "1.11.0", + "amplify-category-storage": "1.12.0", "aws-sdk": "^2.391.0", "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.3.0", + "graphql-relational-schema-transformer": "1.4.0", "inquirer": "6.3.1", "merge-graphql-schemas": "^1.5.8", "moment": "^2.22.2", From 646d21ddc3ec28951487cb38a43a05bc5610271b Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 14 Aug 2019 08:24:04 +0200 Subject: [PATCH 215/587] fix: move test package dependencies to devDependencies (#2034) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 40d04a9743..bcdcaab1b5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -14,7 +14,6 @@ "amplify-category-function": "1.11.0", "amplify-category-storage": "1.12.0", "aws-sdk": "^2.391.0", - "eslint": "^4.9.0", "fs-extra": "^7.0.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "1.4.0", @@ -26,6 +25,7 @@ "uuid": "^2.0.3" }, "devDependencies": { + "eslint": "^4.9.0", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" } From abcadbf3ef08f4bda9584d35148b3aacf538315f Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Fri, 16 Aug 2019 21:00:07 +0200 Subject: [PATCH 216/587] chore: sync, update, clean package versions (#2066) * chore: update tooling dependencies * chore: update and sync aws-sdk * chore: sync runtime package versions, update non-breaking ones * chore: sync and update dev package versions * chore: update remaining packages, update yarn.lock * chore: fix node version in circleci, fix package version for @types/node --- packages/amplify-category-api/package.json | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index bcdcaab1b5..1b1bccc0c6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,19 +13,20 @@ "amplify-category-auth": "1.11.0", "amplify-category-function": "1.11.0", "amplify-category-storage": "1.12.0", - "aws-sdk": "^2.391.0", - "fs-extra": "^7.0.0", + "aws-sdk": "^2.510.0", + "fs-extra": "^8.1.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "1.4.0", - "inquirer": "6.3.1", - "merge-graphql-schemas": "^1.5.8", - "moment": "^2.22.2", + "graphql-tag-pluck": "^0.8.4", + "inquirer": "^6.5.1", + "merge-graphql-schemas": "^1.7.0", + "moment": "^2.24.0", "opn": "^5.3.0", - "ora": "^3.0.0", - "uuid": "^2.0.3" + "ora": "^3.4.0", + "uuid": "^3.3.2" }, "devDependencies": { - "eslint": "^4.9.0", + "eslint": "^4.19.1", "eslint-config-airbnb-base": "^12.1.0", "eslint-plugin-import": "^2.12.0" } From 9f051bd94bcabfc0a6dd7910a118d50299dc5b7f Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Thu, 22 Aug 2019 02:31:05 +0200 Subject: [PATCH 217/587] fix: #429 - Editor hanging bug (#2086) --- packages/amplify-category-api/package.json | 2 +- .../service-walkthroughs/appSync-walkthrough.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1b1bccc0c6..1b75931a6c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -21,7 +21,7 @@ "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", - "opn": "^5.3.0", + "open": "^6.4.0", "ora": "^3.4.0", "uuid": "^3.3.2" }, diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 1660cc992f..86a2ed5703 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,7 +1,7 @@ const inquirer = require('inquirer'); const fs = require('fs-extra'); const path = require('path'); -const opn = require('opn'); +const open = require('open'); const category = 'api'; const serviceName = 'AppSync'; @@ -30,7 +30,7 @@ function openConsole(context) { const consoleUrl = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - opn(consoleUrl, { wait: false }); + open(consoleUrl, { wait: false }); } else { context.print.error('AppSync API is not pushed in the cloud.'); } From 2dcc623db09e8c06b486a351784e0007f199ba2d Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 27 Aug 2019 22:36:15 -0700 Subject: [PATCH 218/587] chore(release): Publish [ci skip] (#2162) - amplify-appsync-simulator@0.4.0 - amplify-category-analytics@1.10.0 - amplify-category-api@1.12.0 - amplify-category-auth@1.12.0 - amplify-category-function@1.12.0 - amplify-category-hosting@1.7.0 - amplify-category-interactions@1.11.0 - amplify-category-notifications@1.9.0 - amplify-category-predictions@1.5.0 - amplify-category-storage@1.13.0 - amplify-category-xr@1.11.0 - @aws-amplify/cli@2.0.0 - amplify-codegen@1.10.0 - amplify-dynamodb-simulator@0.4.0 - amplify-e2e-tests@1.11.0 - amplify-frontend-android@1.13.0 - amplify-frontend-ios@1.13.0 - amplify-frontend-javascript@1.11.0 - amplify-graphiql-explorer@0.4.0 - amplify-graphql-docs-generator@1.9.0 - amplify-graphql-types-generator@1.5.0 - amplify-provider-awscloudformation@2.0.0 - amplify-storage-simulator@0.4.0 - amplify-util-mock@1.0.0 - amplify-velocity-template@0.3.0 - graphql-auth-transformer@4.0.0 - graphql-connection-transformer@3.10.0 - graphql-dynamodb-transformer@4.0.0 - graphql-elasticsearch-transformer@3.11.0 - graphql-function-transformer@1.6.0 - graphql-http-transformer@3.9.0 - graphql-key-transformer@1.6.0 - graphql-mapping-template@3.6.0 - graphql-relational-schema-transformer@1.5.0 - graphql-transformer-common@3.13.0 - graphql-transformer-core@4.0.0 - graphql-transformers-e2e-tests@4.0.0 - graphql-versioned-transformer@3.9.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a4a15001b0..f07439c4e6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1b75931a6c..0426134fc6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.11.0", + "version": "1.12.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.11.0", - "amplify-category-function": "1.11.0", - "amplify-category-storage": "1.12.0", + "amplify-category-auth": "1.12.0", + "amplify-category-function": "1.12.0", + "amplify-category-storage": "1.13.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.4.0", + "graphql-relational-schema-transformer": "1.5.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From b8f13d69d1b7df2cb0f3b29a0f8b3920dad165ab Mon Sep 17 00:00:00 2001 From: Nikhil Lingireddy Date: Wed, 28 Aug 2019 16:30:39 -0700 Subject: [PATCH 219/587] refactor(graphql-relational-schema-transformer): deprecate executeSql (#2165) * refactor(graphql-relational-schema-transformer): deprecate executeSql * Delete RelationalDBResolverGenerator.ts Resolver changes for the deprecation are handled behind the scenes by AppSync and so they are unnecessary. * fix: remove resolver changes --- .../service-walkthroughs/appSync-rds-walkthrough.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 9ce67256af..76b3f55c87 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -148,20 +148,20 @@ async function selectDatabase(inputs, clusterArn, secretArn, AWS) { // Database Name Question const DataApi = new AWS.RDSDataService(); const params = new DataApiParams(); - params.awsSecretStoreArn = secretArn; - params.dbClusterOrInstanceArn = clusterArn; - params.sqlStatements = 'SHOW databases'; + params.secretArn = secretArn; + params.resourceArn = clusterArn; + params.sql = 'SHOW databases'; spinner.start('Fetching Aurora Serverless cluster...'); - const dataApiResult = await DataApi.executeSql(params).promise(); + const dataApiResult = await DataApi.executeStatement(params).promise(); // eslint-disable-next-line prefer-destructuring const records - = dataApiResult.sqlStatementResults[0].resultFrame.records; + = dataApiResult.records; const databaseList = []; for (let i = 0; i < records.length; i += 1) { - const recordValue = records[i].values[0].stringValue; + const recordValue = records[i][0].stringValue; // ignore the three meta tables that the cluster creates if (!['information_schema', 'performance_schema', 'mysql'].includes(recordValue)) { databaseList.push(recordValue); From dbcf576ebb05b5dd9d2c58d771598c255d369b08 Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Fri, 30 Aug 2019 11:44:54 -0700 Subject: [PATCH 220/587] chore(release): Publish [ci skip] (#2184) - amplify-appsync-simulator@0.5.0 - amplify-category-analytics@1.11.0 - amplify-category-api@1.13.0 - amplify-category-auth@1.13.0 - amplify-category-function@1.13.0 - amplify-category-hosting@1.8.0 - amplify-category-interactions@1.12.0 - amplify-category-notifications@1.10.0 - amplify-category-predictions@1.6.0 - amplify-category-storage@1.14.0 - amplify-category-xr@1.12.0 - @aws-amplify/cli@3.0.0 - amplify-codegen@1.11.0 - amplify-dynamodb-simulator@0.5.0 - amplify-e2e-tests@1.12.0 - amplify-frontend-android@1.14.0 - amplify-frontend-ios@1.14.0 - amplify-frontend-javascript@1.12.0 - amplify-graphiql-explorer@0.5.0 - amplify-graphql-docs-generator@1.10.0 - amplify-graphql-types-generator@1.6.0 - amplify-provider-awscloudformation@3.0.0 - amplify-storage-simulator@0.5.0 - amplify-util-mock@2.0.0 - amplify-velocity-template@0.4.0 - graphql-auth-transformer@5.0.0 - graphql-connection-transformer@3.11.0 - graphql-dynamodb-transformer@5.0.0 - graphql-elasticsearch-transformer@3.12.0 - graphql-function-transformer@1.7.0 - graphql-http-transformer@3.10.0 - graphql-key-transformer@1.7.0 - graphql-mapping-template@3.7.0 - graphql-relational-schema-transformer@1.6.0 - graphql-transformer-common@3.14.0 - graphql-transformer-core@5.0.0 - graphql-transformers-e2e-tests@5.0.0 - graphql-versioned-transformer@3.10.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f07439c4e6..f1cfb0607f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0426134fc6..59678cbf88 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.12.0", + "version": "1.13.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.12.0", - "amplify-category-function": "1.12.0", - "amplify-category-storage": "1.13.0", + "amplify-category-auth": "1.13.0", + "amplify-category-function": "1.13.0", + "amplify-category-storage": "1.14.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.5.0", + "graphql-relational-schema-transformer": "1.6.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From d5092446233b2e3eb7a7fe764639b43e8cb2dc29 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Tue, 10 Sep 2019 22:08:50 +0200 Subject: [PATCH 221/587] feat: implement multi-auth functionality (#1916) * feat: implement multi-auth functionality * feat: implement IAM policy generation for private/iam auth combination * feat: add multi-auth transformer tests * feat: add multi-auth transformer e2e tests, fix auth propagation bugs found during testing * fix: authConfig check bug * feat: add more e2e and transformer tests, fix bugs, refactoring * fix: update yarn.lock after merge * fix: add missing dependency to auth transformer * feat: implement multi-auth functionality * feat: implement IAM policy generation for private/iam auth combination * feat: add multi-auth transformer tests * feat: add multi-auth transformer e2e tests, fix auth propagation bugs found during testing * fix: authConfig check bug * feat: add more e2e and transformer tests, fix bugs, refactoring * fix: update yarn.lock after merge * fix: add missing dependency to auth transformer * fix: merge, fix some unrelated tests. E2E has broken tests that needs fixing * fix: auth config * fix: fix e2e tests, only versioned e2e failing * fix: versioned e2e test * fix: rebase compilation issues * fix: address crucial DX related feedback * feat: add authrole, unauthrole separation, detailed policy generation * feat: add multi-auth support for subscription resolver generation * fix: subscription IAM policy generation * fix: update snapshots --- .../commands/api/add-datasource.js | 2 +- .../commands/api/gql-compile.js | 2 +- packages/amplify-category-api/index.js | 2 +- .../appSync-walkthrough.js | 330 +++++++++++++++--- 4 files changed, 287 insertions(+), 49 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-datasource.js b/packages/amplify-category-api/commands/api/add-datasource.js index fdfdd607ee..989cb4f377 100644 --- a/packages/amplify-category-api/commands/api/add-datasource.js +++ b/packages/amplify-category-api/commands/api/add-datasource.js @@ -139,7 +139,7 @@ module.exports = { return datasource; }) .then((datasourceName) => { - context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); return datasourceName; }) .then((datasourceName) => { diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 7752a81d06..52123b73f0 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -4,7 +4,7 @@ module.exports = { name: subcommand, run: async (context) => { try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); } catch (err) { context.print.error(err.toString()); } diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 6960003859..85b26cf7cf 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -133,7 +133,7 @@ async function initEnv(context) { fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); }) .then(() => { - context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true }); + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); }); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 86a2ed5703..dcd969b2ba 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -44,7 +44,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat process.exit(0); } - const { amplify } = context; const { inputs } = serviceMetadata; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; @@ -75,9 +74,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat DynamoDBEnableServerSideEncryption: 'false', }; - // Ask auth/security question + // Ask auth/security questions - const authType = await askSecurityQuestions(context, parameters); + const authConfig = await askSecurityQuestions(context, parameters); // Ask schema file question @@ -94,7 +93,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const schemaFileAnswer = await inquirer.prompt(schemaFileQuestion); - const backendDir = amplify.pathManager.getBackendDirPath(); const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; @@ -127,9 +125,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); - return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } // The user doesn't have an annotated schema file @@ -167,14 +165,20 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat context.print.info('Creating a base schema for you...'); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, noConfig: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + resourceDir, parameters, authConfig, + }); - return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } + // Guided creation of the transform schema + const authTypes = getAuthTypes(authConfig); + const onlyApiKeyAuthEnabled = authTypes.includes('API_KEY') && authTypes.length === 1; let templateSchemaChoices = inputs[4].options; - if (authType === 'API_KEY') { + + if (onlyApiKeyAuthEnabled) { templateSchemaChoices = templateSchemaChoices.filter(schema => schema.value !== 'single-object-auth-schema.graphql'); } @@ -210,7 +214,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat let notCompiled = true; while (notCompiled) { try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); } catch (e) { context.print.error('Failed compiling GraphQL schema:'); context.print.info(e.message); @@ -225,15 +229,13 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat notCompiled = false; } - return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; }); } + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); - - - return { answers: resourceAnswers, output: { securityType: authType }, noCfnFile: true }; + return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } async function updateWalkthrough(context) { @@ -268,72 +270,299 @@ async function updateWalkthrough(context) { context.print.info(e.stack); } - const authType = await askSecurityQuestions(context, parameters); + const authConfig = await askSecurityQuestions(context, parameters); const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); - amplifyMeta[category][resourceName].output.securityType = authType; + if (amplifyMeta[category][resourceName].output.securityType) { + delete amplifyMeta[category][resourceName].output.securityType; + } + + amplifyMeta[category][resourceName].output.authConfig = authConfig; let jsonString = JSON.stringify(amplifyMeta, null, '\t'); fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); - backendConfig[category][resourceName].output.securityType = authType; + if (backendConfig[category][resourceName].output.securityType) { + delete backendConfig[category][resourceName].output.securityType; + } + + backendConfig[category][resourceName].output.authConfig = authConfig; jsonString = JSON.stringify(backendConfig, null, '\t'); fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); } async function askSecurityQuestions(context, parameters) { - const securityTypeQuestion = { + 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 defaultAuthTypeQuestion = { type: 'list', name: 'authType', - message: 'Choose an authorization type for the API', + message: 'Choose the default authorization type for the API', + choices: authProviderChoices, + }; + + const { authType } = await inquirer.prompt([defaultAuthTypeQuestion]); + + const authConfig = { + additionalAuthenticationProviders: [], + }; + + // Get default auth configured + const defaultAuth = await askAuthQuestions(authType, context); + + authConfig.defaultAuthentication = defaultAuth; + + const advancedSettingsQuestion = { + type: 'list', + name: 'advancedSettings', + message: 'Do you want to configure advanced settings for the GraphQL API', choices: [ { - name: 'API key', - value: 'API_KEY', + name: 'No, I am done.', + value: false, }, { - name: 'Amazon Cognito User Pool', - value: 'AMAZON_COGNITO_USER_POOLS', + name: 'Yes, I want to make some additional changes.', + value: true, }, ], }; - const { authType } = await inquirer.prompt([securityTypeQuestion]); + const advancedSettingsAnswer = await inquirer.prompt([advancedSettingsQuestion]); - if (authType === 'AMAZON_COGNITO_USER_POOLS') { - let authResourceName = checkIfAuthExists(context); + if (advancedSettingsAnswer.advancedSettings) { + // Get additional auth configured + const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== authType); - if (!authResourceName) { - try { - const { add } = require('amplify-category-auth'); + const additionalProvidersQuestion = { + type: 'checkbox', + name: 'authType', + message: 'Choose the additional authorization types you want to configure for the API', + choices: remainingAuthProviderChoices, + }; + + const additionalProvidersAnswer = await inquirer.prompt([additionalProvidersQuestion]); + + for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { + const authProvider = additionalProvidersAnswer.authType[i]; + + const config = await askAuthQuestions(authProvider, context, true); - authResourceName = await add(context); - } catch (e) { - context.print.error('Auth plugin not installed in the CLI. You need to install it to use this feature.'); + authConfig.additionalAuthenticationProviders.push(config); + } + + const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter(provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS'); + const additionalUserPoolProvider = additionalUserPoolProviders.length > 0 + ? additionalUserPoolProviders[0] : undefined; + + if (authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { + let userPoolId; + const configuredUserPoolName = checkIfAuthExists(context); + + 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, it is probably a CLI error, please submit an issue on GitHub.'); } + + parameters.AuthCognitoUserPoolId = { + 'Fn::GetAtt': [ + userPoolId, + 'Outputs.UserPoolId', + ], + }; } else { - context.print.info('Use a Cognito user pool configured as a part of this project'); + delete parameters.AuthCognitoUserPoolId; + } + } + + return authConfig; +} + +async function askAuthQuestions(authType, context, printLeadText = false) { + if (authType === 'AMAZON_COGNITO_USER_POOLS') { + if (printLeadText) { + context.print.info('Cognito UserPool configuration'); } - parameters.AuthCognitoUserPoolId = { - 'Fn::GetAtt': [ - `auth${authResourceName}`, - 'Outputs.UserPoolId', - ], + const userPoolConfig = await askUserPoolQuestions(context); + + return userPoolConfig; + } + + if (authType === 'API_KEY') { + if (printLeadText) { + context.print.info('API key configuration'); + } + + const apiKeyConfig = await askApiKeyQuestions(); + + return apiKeyConfig; + } + + if (authType === 'AWS_IAM') { + return { + authenticationType: 'AWS_IAM', }; - } else if (authType === 'API_KEY') { - if (parameters.AuthCognitoUserPoolId) { - delete parameters.AuthCognitoUserPoolId; + } + + if (authType === 'OPENID_CONNECT') { + if (printLeadText) { + context.print.info('OpenID Connect configuration'); + } + + const openIDConnectConfig = await askOpenIDConnectQuestions(); + + return openIDConnectConfig; + } + + context.print.error(`Unknown authType: ${authType}`); + process.exit(1); +} + +async function askUserPoolQuestions(context) { + let authResourceName = checkIfAuthExists(context); + + if (!authResourceName) { + try { + const { add } = require('amplify-category-auth'); + + authResourceName = await add(context); + } catch (e) { + context.print.error('Auth plugin not installed in the CLI. You need to install it to use this feature.'); } + } else { + context.print.info('Use a Cognito user pool configured as a part of this project.'); } - return authType; + return { + authenticationType: 'AMAZON_COGNITO_USER_POOLS', + userPoolConfig: { + userPoolId: `auth${authResourceName}`, + }, + }; +} + +async function askApiKeyQuestions() { + const apiKeyQuestions = [ + { + type: 'input', + name: 'description', + message: 'Enter a description for the API key:', + }, + { + type: 'input', + name: 'apiKeyExpirationDays', + message: 'After how many days from now the API key should expire (1-365):', + default: 180, + validate: validateDays, + }, + ]; + + const apiKeyConfig = await inquirer.prompt(apiKeyQuestions); + + return { + authenticationType: 'API_KEY', + apiKeyConfig, + }; +} + +async function askOpenIDConnectQuestions() { + const openIDConnectQuestions = [ + { + type: 'input', + name: 'name', + message: 'Enter a name for the OpenID Connect provider:', + }, + { + type: 'input', + name: 'issuerUrl', + message: 'Enter the OpenID Connect provider domain (Issuer URL):', + validate: validateIssuerUrl, + }, + { + type: 'input', + name: 'clientId', + message: 'Enter the Client Id from your OpenID Client Connect application (optional):', + }, + { + type: 'input', + name: 'iatTTL', + message: 'Enter the number of milliseconds a token is valid after being issued to a user:', + validate: validateTTL, + }, + { + type: 'input', + name: 'authTTL', + message: 'Enter the number of milliseconds a token is valid after being authenticated:', + validate: validateTTL, + }, + ]; + + const openIDConnectConfig = await inquirer.prompt(openIDConnectQuestions); + + return { + authenticationType: 'OPENID_CONNECT', + openIDConnectConfig, + }; +} + +function validateDays(input) { + const isValid = /^\d+$/.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) { + 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) { + const isValid = /^\d+$/.test(input); + + if (!isValid) { + return 'The value must be a number.'; + } + + return true; } function resourceAlreadyExists(context) { @@ -353,7 +582,6 @@ function resourceAlreadyExists(context) { return resourceName; } - function checkIfAuthExists(context) { const { amplify } = context; const { amplifyMeta } = amplify.getProjectDetails(); @@ -373,7 +601,7 @@ function checkIfAuthExists(context) { } async function migrate(context) { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { noConfig: true, forceCompile: true, migrate: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true }); } function getIAMPolicies(resourceName, crudOptions) { @@ -422,6 +650,16 @@ function getIAMPolicies(resourceName, crudOptions) { return { policy, attributes }; } +function getAuthTypes(authConfig) { + const additionalAuthTypes = (authConfig.additionalAuthenticationProviders || []) + .map(provider => provider.authenticationType) + .filter(t => !!t); + + const uniqueAuthTypes = new Set([...additionalAuthTypes, + authConfig.defaultAuthentication.authenticationType]); + + return [...uniqueAuthTypes.keys()]; +} module.exports = { serviceWalkthrough, updateWalkthrough, openConsole, migrate, getIAMPolicies, From 2da6916581ce0637e6e9f96b8c76113697439f21 Mon Sep 17 00:00:00 2001 From: Yathiraj <511386+yuth@users.noreply.github.com> Date: Tue, 10 Sep 2019 19:07:48 -0700 Subject: [PATCH 222/587] fix(amplify-category-api): include userpool id in parameter.json (#2238) --- .../appSync-walkthrough.js | 168 +++++++++++------- 1 file changed, 101 insertions(+), 67 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index dcd969b2ba..292777ff98 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -16,20 +16,20 @@ function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); const categoryAmplifyMeta = amplifyMeta[category]; let appSyncMeta; - Object.keys((categoryAmplifyMeta)).forEach((resourceName) => { - if (categoryAmplifyMeta[resourceName].service === serviceName && - categoryAmplifyMeta[resourceName].output) { + Object.keys(categoryAmplifyMeta).forEach((resourceName) => { + if ( + categoryAmplifyMeta[resourceName].service === serviceName && + categoryAmplifyMeta[resourceName].output + ) { appSyncMeta = categoryAmplifyMeta[resourceName].output; } }); - if (appSyncMeta) { const { GraphQLAPIIdOutput } = appSyncMeta; const { Region } = amplifyMeta.providers[providerName]; - const consoleUrl = - `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; + const consoleUrl = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; open(consoleUrl, { wait: false }); } else { context.print.error('AppSync API is not pushed in the cloud.'); @@ -110,7 +110,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); - fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); + fs.writeFileSync( + `${resourceDir}/${stacksDirName}/${defaultStackName}`, + defaultCustomResourcesStack, + ); if (schemaFileAnswer[inputs[2].key]) { // User has an annotated schema file @@ -125,14 +128,18 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters, + authConfig, + }); return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } // The user doesn't have an annotated schema file - if (!await amplify.confirmPrompt.run('Do you want a guided schema creation?')) { + if (!(await amplify.confirmPrompt.run('Do you want a guided schema creation?'))) { // Copy the most basic schema onto the users resource dir and transform that const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; @@ -166,7 +173,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat context.print.info('Creating a base schema for you...'); await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, parameters, authConfig, + resourceDir, + parameters, + authConfig, }); return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; @@ -209,31 +218,39 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, targetSchemaFilePath); if (editSchemaChoice) { - return context.amplify.openEditor(context, targetSchemaFilePath) - .then(async () => { - let notCompiled = true; - while (notCompiled) { - try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); - } catch (e) { - context.print.error('Failed compiling GraphQL schema:'); - context.print.info(e.message); - const continueQuestion = { - type: 'input', - name: 'pressKey', - message: `Correct the errors in schema.graphql and press Enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, - }; - await inquirer.prompt(continueQuestion); - continue; - } - notCompiled = false; + return context.amplify.openEditor(context, targetSchemaFilePath).then(async () => { + let notCompiled = true; + while (notCompiled) { + try { + await context.amplify.executeProviderUtils( + context, + 'awscloudformation', + 'compileSchema', + { resourceDir, parameters, authConfig }, + ); + } catch (e) { + context.print.error('Failed compiling GraphQL schema:'); + context.print.info(e.message); + const continueQuestion = { + type: 'input', + name: 'pressKey', + message: `Correct the errors in schema.graphql and press Enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, + }; + await inquirer.prompt(continueQuestion); + continue; } + notCompiled = false; + } - return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; - }); + return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; + }); } - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters, + authConfig, + }); return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } @@ -294,7 +311,11 @@ async function updateWalkthrough(context) { jsonString = JSON.stringify(backendConfig, null, '\t'); fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, authConfig }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters, + authConfig, + }); } async function askSecurityQuestions(context, parameters) { @@ -373,34 +394,33 @@ async function askSecurityQuestions(context, parameters) { authConfig.additionalAuthenticationProviders.push(config); } - - const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter(provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS'); - const additionalUserPoolProvider = additionalUserPoolProviders.length > 0 - ? additionalUserPoolProviders[0] : undefined; - - if (authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { - let userPoolId; - const configuredUserPoolName = checkIfAuthExists(context); - - 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, it is probably a CLI error, please submit an issue on GitHub.'); - } - - parameters.AuthCognitoUserPoolId = { - 'Fn::GetAtt': [ - userPoolId, - 'Outputs.UserPoolId', - ], - }; + } + const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter(provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS'); + const additionalUserPoolProvider = + additionalUserPoolProviders.length > 0 ? additionalUserPoolProviders[0] : undefined; + + if ( + authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || + additionalUserPoolProvider + ) { + let userPoolId; + const configuredUserPoolName = checkIfAuthExists(context); + + if (authConfig.userPoolConfig) { + ({ userPoolId } = authConfig.userPoolConfig); + } else if (additionalUserPoolProvider && additionalUserPoolProvider.userPoolConfig) { + ({ userPoolId } = additionalUserPoolProvider.userPoolConfig); + } else if (configuredUserPoolName) { + userPoolId = `auth${configuredUserPoolName}`; } else { - delete parameters.AuthCognitoUserPoolId; + throw new Error('Cannot find a configured Cognito User Pool.'); } + + parameters.AuthCognitoUserPoolId = { + 'Fn::GetAtt': [userPoolId, 'Outputs.UserPoolId'], + }; + } else { + delete parameters.AuthCognitoUserPoolId; } return authConfig; @@ -601,7 +621,10 @@ function checkIfAuthExists(context) { } async function migrate(context) { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true }); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + forceCompile: true, + migrate: true, + }); } function getIAMPolicies(resourceName, crudOptions) { @@ -610,15 +633,20 @@ function getIAMPolicies(resourceName, crudOptions) { crudOptions.forEach((crudOption) => { switch (crudOption) { - case 'create': actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); + case 'create': + actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); break; - case 'update': actions.push('appsync:Update*'); + case 'update': + actions.push('appsync:Update*'); break; - case 'read': actions.push('appsync:Get*', 'appsync:List*'); + case 'read': + actions.push('appsync:Get*', 'appsync:List*'); break; - case 'delete': actions.push('appsync:Delete*'); + case 'delete': + actions.push('appsync:Delete*'); break; - default: console.log(`${crudOption} not supported`); + default: + console.log(`${crudOption} not supported`); } }); @@ -655,12 +683,18 @@ function getAuthTypes(authConfig) { .map(provider => provider.authenticationType) .filter(t => !!t); - const uniqueAuthTypes = new Set([...additionalAuthTypes, - authConfig.defaultAuthentication.authenticationType]); + const uniqueAuthTypes = new Set([ + ...additionalAuthTypes, + authConfig.defaultAuthentication.authenticationType, + ]); return [...uniqueAuthTypes.keys()]; } module.exports = { - serviceWalkthrough, updateWalkthrough, openConsole, migrate, getIAMPolicies, + serviceWalkthrough, + updateWalkthrough, + openConsole, + migrate, + getIAMPolicies, }; From adb4ac189f1911772074587b9138f532d2375a3b Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 11 Sep 2019 17:13:46 -0700 Subject: [PATCH 223/587] chore(release): Publish [ci skip] * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.6.0 - amplify-category-analytics@1.12.0 - amplify-category-api@1.14.0 - amplify-category-auth@1.14.0 - amplify-category-function@1.14.0 - amplify-category-hosting@1.9.0 - amplify-category-interactions@1.13.0 - amplify-category-notifications@1.11.0 - amplify-category-predictions@1.7.0 - amplify-category-storage@1.15.0 - amplify-category-xr@1.13.0 - @aws-amplify/cli@3.1.0 - amplify-codegen@1.12.0 - amplify-dynamodb-simulator@0.6.0 - amplify-e2e-tests@1.13.0 - amplify-frontend-android@1.15.0 - amplify-frontend-ios@1.15.0 - amplify-frontend-javascript@1.13.0 - amplify-graphiql-explorer@0.6.0 - amplify-graphql-docs-generator@1.11.0 - amplify-graphql-types-generator@1.7.0 - amplify-provider-awscloudformation@3.1.0 - amplify-storage-simulator@0.6.0 - amplify-ui-tests@1.1.0 - amplify-util-mock@2.1.0 - amplify-velocity-template@0.5.0 - graphql-auth-transformer@5.1.0 - graphql-connection-transformer@3.12.0 - graphql-dynamodb-transformer@5.1.0 - graphql-elasticsearch-transformer@3.13.0 - graphql-function-transformer@1.8.0 - graphql-http-transformer@3.11.0 - graphql-key-transformer@1.8.0 - graphql-mapping-template@3.8.0 - graphql-relational-schema-transformer@1.7.0 - graphql-transformer-common@3.15.0 - graphql-transformer-core@5.1.0 - graphql-transformers-e2e-tests@5.1.0 - graphql-versioned-transformer@3.11.0 * chore: version bump to 3.1.1 * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.7.0 - amplify-category-analytics@1.13.0 - amplify-category-api@1.15.0 - amplify-category-auth@1.15.0 - amplify-category-function@1.15.0 - amplify-category-hosting@1.10.0 - amplify-category-interactions@1.14.0 - amplify-category-notifications@1.12.0 - amplify-category-predictions@1.8.0 - amplify-category-storage@1.16.0 - amplify-category-xr@1.14.0 - @aws-amplify/cli@3.2.0 - amplify-codegen@1.13.0 - amplify-dynamodb-simulator@0.7.0 - amplify-e2e-tests@1.14.0 - amplify-frontend-android@1.16.0 - amplify-frontend-ios@1.16.0 - amplify-frontend-javascript@1.14.0 - amplify-graphiql-explorer@0.7.0 - amplify-graphql-docs-generator@1.12.0 - amplify-graphql-types-generator@1.8.0 - amplify-provider-awscloudformation@3.2.0 - amplify-storage-simulator@0.7.0 - amplify-ui-tests@1.2.0 - amplify-util-mock@2.2.0 - amplify-velocity-template@0.6.0 - graphql-auth-transformer@5.2.0 - graphql-connection-transformer@3.13.0 - graphql-dynamodb-transformer@5.2.0 - graphql-elasticsearch-transformer@3.14.0 - graphql-function-transformer@1.9.0 - graphql-http-transformer@3.12.0 - graphql-key-transformer@1.9.0 - graphql-mapping-template@3.9.0 - graphql-relational-schema-transformer@1.8.0 - graphql-transformer-common@3.16.0 - graphql-transformer-core@5.2.0 - graphql-transformers-e2e-tests@5.2.0 - graphql-versioned-transformer@3.12.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 59678cbf88..8e7843b868 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.13.0", + "version": "1.15.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.13.0", - "amplify-category-function": "1.13.0", - "amplify-category-storage": "1.14.0", + "amplify-category-auth": "1.15.0", + "amplify-category-function": "1.15.0", + "amplify-category-storage": "1.16.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.6.0", + "graphql-relational-schema-transformer": "1.8.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From c326184051cd7eca9538f2128ee2ea17ca117266 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Wed, 11 Sep 2019 22:44:48 -0700 Subject: [PATCH 224/587] feat(cli): new plugin platform (#2254) implemented the new plugin platform, and add the amplify plugin commands --- .../amplify-category-api/amplify-plugin.json | 18 +++++++++++++++ packages/amplify-category-api/index.js | 22 +++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 packages/amplify-category-api/amplify-plugin.json diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json new file mode 100644 index 0000000000..691e7c503b --- /dev/null +++ b/packages/amplify-category-api/amplify-plugin.json @@ -0,0 +1,18 @@ +{ + "name": "api", + "type": "category", + "commands": [ + "add-datesource", + "add", + "console", + "gql-compile", + "push", + "remove", + "update", + "help" + ], + "commandAliases":{ + "configure": "update" + }, + "eventHandlers": [] +} \ No newline at end of file diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 85b26cf7cf..73587ffa3a 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -1,9 +1,12 @@ const { run } = require('./commands/api/console'); const fs = require('fs-extra'); +const path = require('path'); const category = 'api'; + const categories = 'categories'; + async function console(context) { await run(context); } @@ -166,9 +169,28 @@ async function getPermissionPolicies(context, resourceOpsMapping) { return { permissionPolicies, resourceAttributes }; } +async function executeAmplifyCommand(context) { + 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); + } + + const commandModule = require(commandPath); + await commandModule.run(context); +} + +async function handleAmplifyEvent(context, args) { + console.log(`${category} handleAmplifyEvent to be implmented`); + context.print.info(`Received event args ${args}`); +} + module.exports = { console, migrate, initEnv, getPermissionPolicies, + executeAmplifyCommand, + handleAmplifyEvent, }; From 0586b6c55c7f8c76feaf1ce215fe3052b22236c1 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 17 Sep 2019 11:52:03 -0700 Subject: [PATCH 225/587] fix(amplify-category-api): fix api add-graphql-datasource command (#2320) --- packages/amplify-category-api/amplify-plugin.json | 2 +- .../api/{add-datasource.js => add-graphql-datasource.js} | 0 packages/amplify-category-api/index.js | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/amplify-category-api/commands/api/{add-datasource.js => add-graphql-datasource.js} (100%) diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 691e7c503b..8cf4ad9d46 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -2,7 +2,7 @@ "name": "api", "type": "category", "commands": [ - "add-datesource", + "add-graphql-datasource", "add", "console", "gql-compile", diff --git a/packages/amplify-category-api/commands/api/add-datasource.js b/packages/amplify-category-api/commands/api/add-graphql-datasource.js similarity index 100% rename from packages/amplify-category-api/commands/api/add-datasource.js rename to packages/amplify-category-api/commands/api/add-graphql-datasource.js diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 73587ffa3a..fabe947169 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -182,7 +182,7 @@ async function executeAmplifyCommand(context) { } async function handleAmplifyEvent(context, args) { - console.log(`${category} handleAmplifyEvent to be implmented`); + context.print.info(`${category} handleAmplifyEvent to be implmented`); context.print.info(`Received event args ${args}`); } From 95c0abc3ce1b17e594176f72b67d1d3c0ea89faa Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 17 Sep 2019 15:34:16 -0700 Subject: [PATCH 226/587] refactor: fix typos and remove unneeded code * refactor(cli): fix typos and remove unneeded code * lint --- packages/amplify-category-api/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index fabe947169..457ef6e266 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -182,7 +182,7 @@ async function executeAmplifyCommand(context) { } async function handleAmplifyEvent(context, args) { - context.print.info(`${category} handleAmplifyEvent to be implmented`); + context.print.info(`${category} handleAmplifyEvent to be implemented`); context.print.info(`Received event args ${args}`); } From 46d3c03bc4e33055207d3f88e1b529618cf082a9 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 17 Sep 2019 18:09:48 -0700 Subject: [PATCH 227/587] Release v3.4.0 (#2326) * chore: bumping up minor versions for publish * chore: bump CLI version to 3.4.0 * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.10.0 - amplify-category-analytics@1.15.0 - amplify-category-api@1.17.0 - amplify-category-auth@1.17.0 - amplify-category-function@1.17.0 - amplify-category-hosting@1.13.0 - amplify-category-interactions@1.16.0 - amplify-category-notifications@1.14.0 - amplify-category-predictions@1.11.0 - amplify-category-storage@1.18.0 - amplify-category-xr@1.16.0 - @aws-amplify/cli@3.4.0 - amplify-codegen@1.16.0 - amplify-dynamodb-simulator@0.10.0 - amplify-e2e-tests@1.17.0 - amplify-frontend-android@1.19.0 - amplify-frontend-ios@1.19.0 - amplify-frontend-javascript@1.17.0 - amplify-graphiql-explorer@0.10.0 - amplify-graphql-docs-generator@1.15.0 - amplify-graphql-types-generator@1.11.0 - amplify-provider-awscloudformation@3.4.0 - amplify-storage-simulator@0.10.0 - amplify-ui-tests@1.5.0 - amplify-util-mock@2.4.0 - amplify-velocity-template@0.9.0 - graphql-auth-transformer@5.5.0 - graphql-connection-transformer@3.16.0 - graphql-dynamodb-transformer@5.5.0 - graphql-elasticsearch-transformer@3.17.0 - graphql-function-transformer@1.12.0 - graphql-http-transformer@3.15.0 - graphql-key-transformer@1.12.0 - graphql-mapping-template@3.12.0 - graphql-relational-schema-transformer@1.11.0 - graphql-transformer-common@3.19.0 - graphql-transformer-core@5.5.0 - graphql-transformers-e2e-tests@5.5.0 - graphql-versioned-transformer@3.15.0 --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8e7843b868..c074c70586 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.15.0", + "version": "1.17.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,9 +10,9 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.15.0", - "amplify-category-function": "1.15.0", - "amplify-category-storage": "1.16.0", + "amplify-category-auth": "1.17.0", + "amplify-category-function": "1.17.0", + "amplify-category-storage": "1.18.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", From de4f0952ed7384d5541071ea472a63d2c131eba3 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 17 Sep 2019 19:05:24 -0700 Subject: [PATCH 228/587] refactor(cli): bump versions manually (#2325) * fix(cli): manually bump versions * graphql package version bumpg * storage related version bumps * appsync simulator version bump --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c074c70586..85674b70fc 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -16,7 +16,7 @@ "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.8.0", + "graphql-relational-schema-transformer": "1.11.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From dd3b8aaeb89e1acf953f7c484855ff730ed6168b Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 17 Sep 2019 21:34:18 -0700 Subject: [PATCH 229/587] Release v3.7 (#2330) * update circleci config * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.11.0 - amplify-category-analytics@1.16.0 - amplify-category-api@1.18.0 - amplify-category-auth@1.18.0 - amplify-category-function@1.18.0 - amplify-category-hosting@1.14.0 - amplify-category-interactions@1.17.0 - amplify-category-notifications@1.15.0 - amplify-category-predictions@1.12.0 - amplify-category-storage@1.19.0 - amplify-category-xr@1.17.0 - @aws-amplify/cli@3.5.0 - amplify-codegen@1.17.0 - amplify-dynamodb-simulator@0.11.0 - amplify-e2e-tests@1.18.0 - amplify-frontend-android@1.20.0 - amplify-frontend-ios@1.20.0 - amplify-frontend-javascript@1.18.0 - amplify-graphiql-explorer@0.11.0 - amplify-graphql-docs-generator@1.16.0 - amplify-graphql-types-generator@1.12.0 - amplify-provider-awscloudformation@3.5.0 - amplify-storage-simulator@0.11.0 - amplify-ui-tests@1.6.0 - amplify-util-mock@2.5.0 - amplify-velocity-template@0.10.0 - graphql-auth-transformer@5.6.0 - graphql-connection-transformer@3.17.0 - graphql-dynamodb-transformer@5.6.0 - graphql-elasticsearch-transformer@3.18.0 - graphql-function-transformer@1.13.0 - graphql-http-transformer@3.16.0 - graphql-key-transformer@1.13.0 - graphql-mapping-template@3.13.0 - graphql-relational-schema-transformer@1.12.0 - graphql-transformer-common@3.20.0 - graphql-transformer-core@5.6.0 - graphql-transformers-e2e-tests@5.6.0 - graphql-versioned-transformer@3.16.0 * revert: beta circle ci config * force publish to bump up version for release * bump up CLI version to 3.6.0 * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.13.0 - amplify-category-analytics@1.18.0 - amplify-category-api@1.20.0 - amplify-category-auth@1.20.0 - amplify-category-function@1.20.0 - amplify-category-hosting@1.16.0 - amplify-category-interactions@1.19.0 - amplify-category-notifications@1.17.0 - amplify-category-predictions@1.14.0 - amplify-category-storage@1.21.0 - amplify-category-xr@1.19.0 - @aws-amplify/cli@3.7.0 - amplify-codegen@1.19.0 - amplify-dynamodb-simulator@0.13.0 - amplify-e2e-tests@1.20.0 - amplify-frontend-android@1.22.0 - amplify-frontend-ios@1.22.0 - amplify-frontend-javascript@1.20.0 - amplify-graphiql-explorer@0.13.0 - amplify-graphql-docs-generator@1.18.0 - amplify-graphql-types-generator@1.14.0 - amplify-provider-awscloudformation@3.7.0 - amplify-storage-simulator@0.13.0 - amplify-ui-tests@1.8.0 - amplify-util-mock@2.7.0 - amplify-velocity-template@0.12.0 - graphql-auth-transformer@5.8.0 - graphql-connection-transformer@3.19.0 - graphql-dynamodb-transformer@5.8.0 - graphql-elasticsearch-transformer@3.20.0 - graphql-function-transformer@1.15.0 - graphql-http-transformer@3.18.0 - graphql-key-transformer@1.15.0 - graphql-mapping-template@3.15.0 - graphql-relational-schema-transformer@1.14.0 - graphql-transformer-common@3.22.0 - graphql-transformer-core@5.8.0 - graphql-transformers-e2e-tests@5.8.0 - graphql-versioned-transformer@3.18.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 85674b70fc..0ae94c546b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.17.0", + "version": "1.20.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.17.0", - "amplify-category-function": "1.17.0", - "amplify-category-storage": "1.18.0", + "amplify-category-auth": "1.20.0", + "amplify-category-function": "1.20.0", + "amplify-category-storage": "1.21.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.11.0", + "graphql-relational-schema-transformer": "1.14.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From 31144fd2c34283fc6eb9c1eeaf1ea79d7a7693cf Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 18 Sep 2019 19:53:58 -0700 Subject: [PATCH 230/587] chore(release): Publish [ci skip] (#2345) * chore: modify release script in package.json * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.14.0 - amplify-category-analytics@1.19.0 - amplify-category-api@1.21.0 - amplify-category-auth@1.21.0 - amplify-category-function@1.21.0 - amplify-category-hosting@1.17.0 - amplify-category-interactions@1.20.0 - amplify-category-notifications@1.18.0 - amplify-category-predictions@1.15.0 - amplify-category-storage@1.22.0 - amplify-category-xr@1.20.0 - @aws-amplify/cli@3.8.0 - amplify-codegen@1.20.0 - amplify-dynamodb-simulator@0.14.0 - amplify-e2e-tests@1.21.0 - amplify-frontend-android@1.23.0 - amplify-frontend-ios@1.23.0 - amplify-frontend-javascript@1.21.0 - amplify-graphiql-explorer@0.14.0 - amplify-graphql-docs-generator@1.19.0 - amplify-graphql-types-generator@1.15.0 - amplify-provider-awscloudformation@3.8.0 - amplify-storage-simulator@0.14.0 - amplify-ui-tests@1.9.0 - amplify-util-mock@2.8.0 - amplify-velocity-template@0.13.0 - graphql-auth-transformer@5.9.0 - graphql-connection-transformer@3.20.0 - graphql-dynamodb-transformer@5.9.0 - graphql-elasticsearch-transformer@3.21.0 - graphql-function-transformer@1.16.0 - graphql-http-transformer@3.19.0 - graphql-key-transformer@1.16.0 - graphql-mapping-template@3.16.0 - graphql-relational-schema-transformer@1.15.0 - graphql-transformer-common@3.23.0 - graphql-transformer-core@5.9.0 - graphql-transformers-e2e-tests@5.9.0 - graphql-versioned-transformer@3.19.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0ae94c546b..e03f9c882a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.20.0", + "version": "1.21.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.20.0", - "amplify-category-function": "1.20.0", - "amplify-category-storage": "1.21.0", + "amplify-category-auth": "1.21.0", + "amplify-category-function": "1.21.0", + "amplify-category-storage": "1.22.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.14.0", + "graphql-relational-schema-transformer": "1.15.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From 6c01f2ca9e822a06d8f5c5f99189097be2a773c0 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 23 Sep 2019 00:16:34 -0700 Subject: [PATCH 231/587] chore(release): Publish [ci skip] (#2359) - amplify-appsync-simulator@0.15.0 - amplify-category-analytics@1.20.0 - amplify-category-api@1.22.0 - amplify-category-auth@1.22.0 - amplify-category-function@1.22.0 - amplify-category-hosting@1.18.0 - amplify-category-interactions@1.21.0 - amplify-category-notifications@1.19.0 - amplify-category-predictions@1.16.0 - amplify-category-storage@1.23.0 - amplify-category-xr@1.21.0 - @aws-amplify/cli@3.9.0 - amplify-codegen@1.21.0 - amplify-dynamodb-simulator@0.15.0 - amplify-e2e-tests@1.22.0 - amplify-frontend-android@1.24.0 - amplify-frontend-ios@1.24.0 - amplify-frontend-javascript@1.22.0 - amplify-graphiql-explorer@0.15.0 - amplify-graphql-docs-generator@1.20.0 - amplify-graphql-types-generator@1.16.0 - amplify-provider-awscloudformation@3.9.0 - amplify-storage-simulator@0.15.0 - amplify-ui-tests@1.10.0 - amplify-util-mock@2.9.0 - amplify-velocity-template@0.14.0 - graphql-auth-transformer@5.10.0 - graphql-connection-transformer@3.21.0 - graphql-dynamodb-transformer@5.10.0 - graphql-elasticsearch-transformer@3.22.0 - graphql-function-transformer@1.17.0 - graphql-http-transformer@3.20.0 - graphql-key-transformer@1.17.0 - graphql-mapping-template@3.17.0 - graphql-relational-schema-transformer@1.16.0 - graphql-transformer-common@3.24.0 - graphql-transformer-core@5.10.0 - graphql-transformers-e2e-tests@5.10.0 - graphql-versioned-transformer@3.20.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e03f9c882a..7defd1d538 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.21.0", + "version": "1.22.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.21.0", - "amplify-category-function": "1.21.0", - "amplify-category-storage": "1.22.0", + "amplify-category-auth": "1.22.0", + "amplify-category-function": "1.22.0", + "amplify-category-storage": "1.23.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.15.0", + "graphql-relational-schema-transformer": "1.16.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From dc83d369a56a1712ea40f8ac5005340840814097 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 25 Sep 2019 19:40:39 -0700 Subject: [PATCH 232/587] chore(release): Publish [ci skip] (#2417) - amplify-appsync-simulator@0.16.0 - amplify-category-analytics@1.21.0 - amplify-category-api@1.23.0 - amplify-category-auth@1.23.0 - amplify-category-function@1.23.0 - amplify-category-hosting@1.19.0 - amplify-category-interactions@1.22.0 - amplify-category-notifications@1.20.0 - amplify-category-predictions@1.17.0 - amplify-category-storage@1.24.0 - amplify-category-xr@1.22.0 - @aws-amplify/cli@3.10.0 - amplify-codegen@1.22.0 - amplify-dynamodb-simulator@0.16.0 - amplify-e2e-tests@1.23.0 - amplify-frontend-android@1.25.0 - amplify-frontend-ios@1.25.0 - amplify-frontend-javascript@1.23.0 - amplify-graphiql-explorer@0.16.0 - amplify-graphql-docs-generator@1.21.0 - amplify-graphql-types-generator@1.17.0 - amplify-provider-awscloudformation@3.10.0 - amplify-storage-simulator@0.16.0 - amplify-ui-tests@1.11.0 - amplify-util-mock@2.10.0 - amplify-velocity-template@0.15.0 - graphql-auth-transformer@5.11.0 - graphql-connection-transformer@3.22.0 - graphql-dynamodb-transformer@5.11.0 - graphql-elasticsearch-transformer@3.23.0 - graphql-function-transformer@1.18.0 - graphql-http-transformer@3.21.0 - graphql-key-transformer@1.18.0 - graphql-mapping-template@3.18.0 - graphql-relational-schema-transformer@1.17.0 - graphql-transformer-common@3.25.0 - graphql-transformer-core@5.11.0 - graphql-transformers-e2e-tests@5.11.0 - graphql-versioned-transformer@3.21.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7defd1d538..f849c60df8 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.22.0", + "version": "1.23.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.22.0", - "amplify-category-function": "1.22.0", - "amplify-category-storage": "1.23.0", + "amplify-category-auth": "1.23.0", + "amplify-category-function": "1.23.0", + "amplify-category-storage": "1.24.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.16.0", + "graphql-relational-schema-transformer": "1.17.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From b64cea0b7a3f4a42dcc628315145040ee50c3bb5 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Fri, 27 Sep 2019 12:08:26 -0700 Subject: [PATCH 233/587] fix(amplify-category-api): safeguard prompt with empty options (#2430) when the CLI prompt the user to select from some options, it uses the inquirer library, and if the options are empty, inquirer throws error, which leads the CLI to exit without proper messages given to the user. This PR safeguard against such situation for the RDS selection, and it will print out proper error message before the CLI exits. fix #2423 --- .../appSync-rds-walkthrough.js | 43 +++++++++++++------ 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 76b3f55c87..16a3b0a53b 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -46,13 +46,14 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta }); // RDS Cluster Question - const { selectedClusterArn, clusterResourceId } = await selectCluster(inputs, AWS); + const { selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, AWS); // Secret Store Question - const selectedSecretArn = await getSecretStoreArn(inputs, clusterResourceId, AWS); + const selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS); // Database Name Question - const selectedDatabase = await selectDatabase(inputs, selectedClusterArn, selectedSecretArn, AWS); + const selectedDatabase = + await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); return { region: selectedRegion, @@ -67,7 +68,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta * * @param {*} inputs */ -async function selectCluster(inputs, AWS) { +async function selectCluster(context, inputs, AWS) { const RDS = new AWS.RDS(); const describeDBClustersResult = await RDS.describeDBClusters().promise(); @@ -80,13 +81,18 @@ async function selectCluster(inputs, AWS) { } } - const clusterIdentifier = await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); - const selectedCluster = clusters.get(clusterIdentifier); + if (clusters.size > 0) { + const clusterIdentifier = + await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); + const selectedCluster = clusters.get(clusterIdentifier); - return { - selectedClusterArn: selectedCluster.DBClusterArn, - clusterResourceId: selectedCluster.DbClusterResourceId, - }; + return { + selectedClusterArn: selectedCluster.DBClusterArn, + clusterResourceId: selectedCluster.DbClusterResourceId, + }; + } + context.print.error('No properly configured Aurora Serverless clusters found.'); + process.exit(0); } /** @@ -94,7 +100,7 @@ async function selectCluster(inputs, AWS) { * @param {*} inputs * @param {*} clusterResourceId */ -async function getSecretStoreArn(inputs, clusterResourceId, AWS) { +async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { const SecretsManager = new AWS.SecretsManager(); const NextToken = 'NextToken'; let rawSecrets = []; @@ -103,6 +109,7 @@ async function getSecretStoreArn(inputs, clusterResourceId, AWS) { }; const listSecretsResult = await SecretsManager.listSecrets(params).promise(); + rawSecrets = listSecretsResult.SecretList; let token = listSecretsResult.NextToken; while (token) { @@ -128,11 +135,14 @@ async function getSecretStoreArn(inputs, clusterResourceId, AWS) { secrets.set(rawSecrets[i].Name, rawSecrets[i].ARN); } - if (!selectedSecretArn) { + if (!selectedSecretArn && secrets.size > 0) { // Kick off questions flow const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); selectedSecretArn = secrets.get(selectedSecretName); + } else { + context.print.error('No RDS access credentials found in the AWS Secrect Manager.'); + process.exit(0); } return selectedSecretArn; @@ -144,7 +154,7 @@ async function getSecretStoreArn(inputs, clusterResourceId, AWS) { * @param {*} clusterArn * @param {*} secretArn */ -async function selectDatabase(inputs, clusterArn, secretArn, AWS) { +async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { // Database Name Question const DataApi = new AWS.RDSDataService(); const params = new DataApiParams(); @@ -170,7 +180,12 @@ async function selectDatabase(inputs, clusterArn, secretArn, AWS) { spinner.succeed('Fetched Aurora Serverless cluster.'); - return await promptWalkthroughQuestion(inputs, 3, databaseList); + if (databaseList.length > 0) { + return await promptWalkthroughQuestion(inputs, 3, databaseList); + } + + context.print.error('No properly configured databases found.'); + process.exit(0); } /** From 5d903bbd9258432c351f5efc1b3c3622f4fae0c8 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 1 Oct 2019 13:01:19 -0700 Subject: [PATCH 234/587] chore(release): Publish [ci skip] (#2469) - amplify-appsync-simulator@0.17.0 - amplify-category-analytics@1.22.0 - amplify-category-api@1.24.0 - amplify-category-auth@1.24.0 - amplify-category-function@1.24.0 - amplify-category-hosting@1.20.0 - amplify-category-interactions@1.23.0 - amplify-category-notifications@1.21.0 - amplify-category-predictions@1.18.0 - amplify-category-storage@1.25.0 - amplify-category-xr@1.23.0 - @aws-amplify/cli@3.11.0 - amplify-codegen@1.23.0 - amplify-dynamodb-simulator@0.17.0 - amplify-e2e-tests@1.24.0 - amplify-frontend-android@1.26.0 - amplify-frontend-ios@1.26.0 - amplify-frontend-javascript@1.24.0 - amplify-graphiql-explorer@0.17.0 - amplify-graphql-docs-generator@1.22.0 - amplify-graphql-types-generator@1.18.0 - amplify-provider-awscloudformation@3.11.0 - amplify-storage-simulator@0.17.0 - amplify-ui-tests@1.12.0 - amplify-util-mock@2.11.0 - amplify-velocity-template@0.16.0 - graphql-auth-transformer@5.12.0 - graphql-connection-transformer@3.23.0 - graphql-dynamodb-transformer@5.12.0 - graphql-elasticsearch-transformer@3.24.0 - graphql-function-transformer@1.19.0 - graphql-http-transformer@3.22.0 - graphql-key-transformer@1.19.0 - graphql-mapping-template@3.19.0 - graphql-relational-schema-transformer@1.18.0 - graphql-transformer-common@3.26.0 - graphql-transformer-core@5.12.0 - graphql-transformers-e2e-tests@5.12.0 - graphql-versioned-transformer@3.22.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f849c60df8..0c9eedb94e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.23.0", + "version": "1.24.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.23.0", - "amplify-category-function": "1.23.0", - "amplify-category-storage": "1.24.0", + "amplify-category-auth": "1.24.0", + "amplify-category-function": "1.24.0", + "amplify-category-storage": "1.25.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.17.0", + "graphql-relational-schema-transformer": "1.18.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From e86067d6981c29465a6a76bd54748eb30feda1e5 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Fri, 13 Sep 2019 10:44:16 -0700 Subject: [PATCH 235/587] chore: add pretty-quick to run prettier on staged files --- packages/amplify-category-api/.eslintrc.json | 28 ++++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/packages/amplify-category-api/.eslintrc.json b/packages/amplify-category-api/.eslintrc.json index ef16d9dd3f..f010567e49 100644 --- a/packages/amplify-category-api/.eslintrc.json +++ b/packages/amplify-category-api/.eslintrc.json @@ -1,15 +1,15 @@ { - "extends": "airbnb-base", - "rules": { - "no-param-reassign": "off", - "no-return-await" : "off", - "no-constant-condition": "off", - "no-continue": "off", - "no-await-in-loop": "off", - "no-use-before-define": "off", - "no-console": "off", - "global-require": "off", - "import/no-dynamic-require": "off", - "consistent-return": "off" - } -} \ No newline at end of file + "extends": ["airbnb-base", "plugin:prettier/recommended"], + "rules": { + "no-param-reassign": "off", + "no-return-await": "off", + "no-constant-condition": "off", + "no-continue": "off", + "no-await-in-loop": "off", + "no-use-before-define": "off", + "no-console": "off", + "global-require": "off", + "import/no-dynamic-require": "off", + "consistent-return": "off" + } +} From 9947e61965c45909e40adaba39bf7eccbf8c93cf Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Thu, 3 Oct 2019 14:51:10 -0700 Subject: [PATCH 236/587] style: run code through prettier --- packages/amplify-category-api/commands/api.js | 2 +- .../commands/api/add-graphql-datasource.js | 72 ++++----- .../amplify-category-api/commands/api/add.js | 18 ++- .../commands/api/console.js | 12 +- .../commands/api/gql-compile.js | 2 +- .../amplify-category-api/commands/api/push.js | 11 +- .../commands/api/remove.js | 14 +- .../commands/api/update.js | 10 +- packages/amplify-category-api/index.js | 53 +++---- .../default-values/apigw-defaults.js | 2 +- .../default-values/appSync-defaults.js | 2 +- .../provider-utils/awscloudformation/index.js | 144 ++++++++---------- .../service-walkthroughs/apigw-walkthrough.js | 132 ++++++++-------- .../appSync-rds-walkthrough.js | 23 ++- .../appSync-walkthrough.js | 60 ++++---- 15 files changed, 271 insertions(+), 286 deletions(-) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index 2202629d00..a59782c5c8 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -2,7 +2,7 @@ const featureName = 'api'; module.exports = { name: featureName, - run: async (context) => { + run: async context => { if (/^win/.test(process.platform)) { try { const { run } = require(`./${featureName}/${context.parameters.first}`); diff --git a/packages/amplify-category-api/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/commands/api/add-graphql-datasource.js index 989cb4f377..5d9525d9f3 100644 --- a/packages/amplify-category-api/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/commands/api/add-graphql-datasource.js @@ -21,14 +21,14 @@ const rdsInit = 'rdsInit'; module.exports = { name: subcommand, - run: async (context) => { + run: async context => { const { amplify } = context; let resourceName; let datasource; let databaseName; const AWS = await getAwsClient(context, 'list'); return datasourceSelectionPrompt(context, servicesMetadata) - .then((result) => { + .then(result => { datasource = result.datasource; // eslint-disable-line prefer-destructuring const providerController = require(`../../provider-utils/${result.providerName}/index`); @@ -39,7 +39,7 @@ module.exports = { return providerController.addDatasource(context, category, result.datasource); }) - .then((answers) => { + .then(answers => { resourceName = answers.resourceName; // eslint-disable-line prefer-destructuring databaseName = answers.databaseName; // eslint-disable-line prefer-destructuring @@ -63,14 +63,10 @@ module.exports = { teamProviderInfo[currEnv][categories][category][resourceName] = {}; } - teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] - = answers.region; - teamProviderInfo[currEnv][categories][category][resourceName][rdsIdentifier] - = answers.dbClusterArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] - = answers.secretStoreArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] - = answers.databaseName; + teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] = answers.region; + teamProviderInfo[currEnv][categories][category][resourceName][rdsIdentifier] = answers.dbClusterArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); @@ -81,22 +77,26 @@ module.exports = { fs.writeFileSync(backendConfigFilePath, JSON.stringify(backendConfig, null, 4)); - /** * Load the MySqlRelationalDBReader */ // eslint-disable-next-line max-len - const dbReader = new AuroraServerlessMySQLDatabaseReader(answers.region, answers.secretStoreArn, answers.dbClusterArn, answers.databaseName, AWS); - + const dbReader = new AuroraServerlessMySQLDatabaseReader( + answers.region, + answers.secretStoreArn, + answers.dbClusterArn, + answers.databaseName, + AWS + ); /** * Instantiate a new Relational Schema Transformer and perform * the db instrospection to get the GraphQL Schema and Template Context */ - const relationalSchemaTransformer = - new RelationalDBSchemaTransformer(dbReader, answers.databaseName); + const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName); return relationalSchemaTransformer.introspectDatabaseSchema(); - }).then((graphqlSchemaContext) => { + }) + .then(graphqlSchemaContext => { const projectBackendDirPath = amplify.pathManager.getBackendDirPath(); /** @@ -112,8 +112,7 @@ module.exports = { const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const concatGraphQLSchemaDoc - = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); + const concatGraphQLSchemaDoc = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); fs.writeFileSync(graphqlSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); const resolversDir = `${projectBackendDirPath}/${category}/${resourceName}/resolvers`; @@ -138,20 +137,22 @@ module.exports = { return datasource; }) - .then((datasourceName) => { + .then(datasourceName => { context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); return datasourceName; }) - .then((datasourceName) => { + .then(datasourceName => { const { print } = context; print.success(`Successfully added the ${datasourceName} datasource locally`); print.info(''); print.success('Some next steps:'); print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - print.info('"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud'); + print.info( + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud' + ); print.info(''); }) - .catch((err) => { + .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the datasource'); }); @@ -160,8 +161,10 @@ module.exports = { function datasourceSelectionPrompt(context, supportedDatasources) { const options = []; - Object.keys(supportedDatasources).forEach((datasource) => { - const optionName = supportedDatasources[datasource].alias || `${supportedDatasources[datasource].providerName}:${supportedDatasources[datasource].service}`; + Object.keys(supportedDatasources).forEach(datasource => { + const optionName = + supportedDatasources[datasource].alias || + `${supportedDatasources[datasource].providerName}:${supportedDatasources[datasource].service}`; options.push({ name: optionName, value: { @@ -180,20 +183,21 @@ function datasourceSelectionPrompt(context, supportedDatasources) { if (options.length === 1) { // No need to ask questions context.print.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); - return new Promise((resolve) => { + return new Promise(resolve => { resolve(options[0].value); }); } - const question = [{ - name: 'datasource', - message: 'Please select from one of the below mentioned datasources', - type: 'list', - choices: options, - }]; + const question = [ + { + name: 'datasource', + message: 'Please select from one of the below mentioned datasources', + type: 'list', + choices: options, + }, + ]; - return inquirer.prompt(question) - .then(answer => answer.datasource); + return inquirer.prompt(question).then(answer => answer.datasource); } async function getAwsClient(context, action) { diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 203230f18c..e71e363c50 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -8,16 +8,16 @@ let options; module.exports = { name: subcommand, - run: async (context) => { + run: async context => { const { amplify } = context; - return amplify.serviceSelectionPrompt(context, category, servicesMetadata) - .then((result) => { + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(result => { options = { service: result.service, providerPlugin: result.providerName, }; - const providerController = - require(`../../provider-utils/${result.providerName}/index`); + const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { context.print.error('Provider not configured for this category'); return; @@ -25,16 +25,18 @@ module.exports = { return providerController.addResource(context, category, result.service, options); }) - .then((resourceName) => { + .then(resourceName => { const { print } = context; print.success(`Successfully added resource ${resourceName} locally`); print.info(''); print.success('Some next steps:'); print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - print.info('"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud'); + print.info( + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud' + ); print.info(''); }) - .catch((err) => { + .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the API resource'); }); diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index 2942741c43..e9260f3e7e 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -6,12 +6,12 @@ const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider module.exports = { name: subcommand, - run: async (context) => { + run: async context => { const { amplify } = context; - return amplify.serviceSelectionPrompt(context, category, servicesMetadata) - .then((result) => { - const providerController = - require(`../../provider-utils/${result.providerName}/index`); + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(result => { + const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { context.print.error('Provider not configured for this category'); return; @@ -19,7 +19,7 @@ module.exports = { return providerController.console(context, result.service); }) - .catch((err) => { + .catch(err => { context.print.error('Error opening console.'); context.print.info(err.message); }); diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 52123b73f0..5b499cc553 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -2,7 +2,7 @@ const subcommand = 'gql-compile'; module.exports = { name: subcommand, - run: async (context) => { + run: async context => { try { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); } catch (err) { diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index 683ca6a54f..324b969e79 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -3,14 +3,13 @@ const category = 'api'; module.exports = { name: subcommand, - run: async (context) => { + run: async context => { const { amplify, parameters } = context; const resourceName = parameters.first; context.amplify.constructExeInfo(context); - return amplify.pushResources(context, category, resourceName) - .catch((err) => { - context.print.error('There was an error pushing the API resource'); - context.print.error(err.toString()); - }); + return amplify.pushResources(context, category, resourceName).catch(err => { + context.print.error('There was an error pushing the API resource'); + context.print.error(err.toString()); + }); }, }; diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index 0ad4814a14..c6ae3c5c4d 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -6,23 +6,21 @@ const gqlConfigFilename = '.graphqlconfig.yml'; module.exports = { name: subcommand, - run: async (context) => { + run: async context => { const { amplify, parameters } = context; const resourceName = parameters.first; - return amplify.removeResource(context, category, resourceName) - .then((resourceValues) => { + return amplify + .removeResource(context, category, resourceName) + .then(resourceValues => { if (resourceValues.service === 'AppSync') { const { projectPath } = amplify.getEnvInfo(); - const gqlConfigFile = path.normalize(path.join( - projectPath, - gqlConfigFilename, - )); + const gqlConfigFile = path.normalize(path.join(projectPath, gqlConfigFilename)); context.filesystem.remove(gqlConfigFile); } }) - .catch((err) => { + .catch(err => { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); }); diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index 27585e1fa7..27a5ee171c 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -4,15 +4,15 @@ const subcommand = 'update'; const category = 'api'; const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); - module.exports = { name: subcommand, alias: ['configure'], - run: async (context) => { + run: async context => { const { amplify } = context; - return amplify.serviceSelectionPrompt(context, category, servicesMetadata) - .then((result) => { + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(result => { const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { context.print.error('Provider not configured for this category'); @@ -21,7 +21,7 @@ module.exports = { return providerController.updateResource(context, category, result.service); }) .then(() => context.print.success('Successfully updated resource')) - .catch((err) => { + .catch(err => { context.print.error(err.message); }); }, diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 457ef6e266..6099279fdd 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -6,7 +6,6 @@ const category = 'api'; const categories = 'categories'; - async function console(context) { await run(context); } @@ -14,20 +13,17 @@ async function console(context) { async function migrate(context, serviceName) { const { projectPath, amplifyMeta } = context.migrationInfo; const migrateResourcePromises = []; - Object.keys(amplifyMeta).forEach((categoryName) => { + Object.keys(amplifyMeta).forEach(categoryName => { if (categoryName === category) { - Object.keys(amplifyMeta[category]).forEach((resourceName) => { + Object.keys(amplifyMeta[category]).forEach(resourceName => { try { if (amplifyMeta[category][resourceName].providerPlugin) { const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { - migrateResourcePromises.push(providerController.migrateResource( - context, - projectPath, - amplifyMeta[category][resourceName].service, - resourceName, - )); + migrateResourcePromises.push( + providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName) + ); } } } else { @@ -98,22 +94,25 @@ async function initEnv(context) { const currEnv = amplify.getEnvInfo().envName; const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); const teamProviderInfo = amplify.readJsonFile(teamProviderInfoFilePath); - if (teamProviderInfo[currEnv][categories] - && teamProviderInfo[currEnv][categories][category] - && teamProviderInfo[currEnv][categories][category][resourceName] - && teamProviderInfo[currEnv][categories][category][resourceName] - && teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion]) { + if ( + teamProviderInfo[currEnv][categories] && + teamProviderInfo[currEnv][categories][category] && + teamProviderInfo[currEnv][categories][category][resourceName] && + teamProviderInfo[currEnv][categories][category][resourceName] && + teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] + ) { return; } /** * Execute the walkthrough */ - return providerController.addDatasource(context, category, datasource) - .then((answers) => { - /** - * Write the new answers to the team provider info - */ + return providerController + .addDatasource(context, category, datasource) + .then(answers => { + /** + * Write the new answers to the team provider info + */ if (!teamProviderInfo[currEnv][categories]) { teamProviderInfo[currEnv][categories] = {}; } @@ -124,14 +123,10 @@ async function initEnv(context) { teamProviderInfo[currEnv][categories][category][resourceName] = {}; } - teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] - = answers.region; - teamProviderInfo[currEnv][categories][category][resourceName][rdsClusterIdentifier] - = answers.dbClusterArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] - = answers.secretStoreArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] - = answers.databaseName; + teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] = answers.region; + teamProviderInfo[currEnv][categories][category][resourceName][rdsClusterIdentifier] = answers.dbClusterArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; + teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); }) @@ -146,7 +141,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { const permissionPolicies = []; const resourceAttributes = []; - Object.keys(resourceOpsMapping).forEach((resourceName) => { + Object.keys(resourceOpsMapping).forEach(resourceName => { try { const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); if (providerController) { @@ -154,7 +149,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { context, amplifyMeta[category][resourceName].service, resourceName, - resourceOpsMapping[resourceName], + resourceOpsMapping[resourceName] ); permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js index 991d984e42..7ab876f8fa 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js @@ -1,6 +1,6 @@ const uuid = require('uuid'); -const getAllDefaults = (project) => { +const getAllDefaults = project => { const name = project.projectConfig.projectName.toLowerCase().replace(/[^0-9a-zA-Z]/gi, ''); const [shortId] = uuid().split('-'); const defaults = { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js index 5c535cb023..0d5cb71570 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js @@ -1,6 +1,6 @@ const uuid = require('uuid'); -const getAllDefaults = (project) => { +const getAllDefaults = project => { const name = project.projectConfig.projectName.toLowerCase(); const region = project.amplifyMeta.providers.awscloudformation.Region; const [shortId] = uuid().split('-'); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js index 0236823e5a..858d52498c 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/index.js @@ -13,7 +13,6 @@ function serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFile return serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); } - function copyCfnTemplate(context, category, options, cfnFilename) { const { amplify } = context; const targetDir = amplify.pathManager.getBackendDirPath(); @@ -31,7 +30,6 @@ function copyCfnTemplate(context, category, options, cfnFilename) { return context.amplify.copyBatch(context, copyJobs, options, true, false); } - function console(context, service) { serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; const { serviceWalkthroughFilename } = serviceMetadata; @@ -53,50 +51,45 @@ function addResource(context, category, service, options) { const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) - .then((result) => { - 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; - } - copyCfnTemplate(context, category, answers, cfnFilename); - - const parameters = { ...answers }; - const cfnParameters = { - authRoleName: { - Ref: 'AuthRoleName', - }, - unauthRoleName: { - Ref: 'UnauthRoleName', - }, - }; - const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); - fs.ensureDirSync(resourceDirPath); - - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let jsonString = JSON.stringify(parameters, null, 4); - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); - - const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - jsonString = JSON.stringify(cfnParameters, null, 4); - fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); + return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename).then(result => { + 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; } - context.amplify.updateamplifyMetaAfterResourceAdd( - category, - answers.resourceName, - options, - ); - return answers.resourceName; - }); + copyCfnTemplate(context, category, answers, cfnFilename); + + const parameters = { ...answers }; + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); + + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + let jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); + jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); + } + context.amplify.updateamplifyMetaAfterResourceAdd(category, answers.resourceName, options); + return answers.resourceName; + }); } async function updateResource(context, category, service) { @@ -113,41 +106,31 @@ async function updateResource(context, category, service) { process.exit(0); } - return updateWalkthrough(context, defaultValuesFilename, serviceMetadata) - .then((result) => { - const options = {}; - if (result) { - if (result.answers) { - ({ answers } = result); - options.dependsOn = result.dependsOn; - } else { - answers = result; - } + return updateWalkthrough(context, defaultValuesFilename, serviceMetadata).then(result => { + const options = {}; + if (result) { + if (result.answers) { + ({ answers } = result); + options.dependsOn = result.dependsOn; + } else { + answers = result; + } - if (!result.noCfnFile) { - if (answers.customCfnFile) { - cfnFilename = answers.customCfnFile; - } - copyCfnTemplate(context, category, answers, cfnFilename); - const parameters = { ...answers }; - const resourceDirPath = path.join( - projectBackendDirPath, - category, - parameters.resourceName, - ); - fs.ensureDirSync(resourceDirPath); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - const jsonString = JSON.stringify(parameters, null, 4); - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); - context.amplify.updateamplifyMetaAfterResourceUpdate( - category, - answers.resourceName, - 'dependsOn', - answers.dependsOn, - ); + if (!result.noCfnFile) { + if (answers.customCfnFile) { + cfnFilename = answers.customCfnFile; } + copyCfnTemplate(context, category, answers, cfnFilename); + const parameters = { ...answers }; + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + const jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + context.amplify.updateamplifyMetaAfterResourceUpdate(category, answers.resourceName, 'dependsOn', answers.dependsOn); } - }); + } + }); } async function migrateResource(context, projectPath, service, resourceName) { @@ -185,5 +168,10 @@ function getPermissionPolicies(context, service, resourceName, crudOptions) { } module.exports = { - addResource, updateResource, console, migrateResource, addDatasource, getPermissionPolicies, + addResource, + updateResource, + console, + migrateResource, + addDatasource, + getPermissionPolicies, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 481592ce26..95dc31b4fe 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -30,9 +30,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - const resources = allResources - .filter(resource => resource.service === serviceName) - .map(resource => resource.resourceName); + const resources = allResources.filter(resource => resource.service === serviceName).map(resource => resource.resourceName); // There can only be one appsync resource if (resources.length === 0) { @@ -45,20 +43,24 @@ async function updateWalkthrough(context, defaultValuesFilename) { paths: [], }; - const question = [{ - name: 'resourceName', - message: 'Please select the REST API you would want to update', - type: 'list', - choices: resources, - }, { - name: 'operation', - message: 'What would you like to do', - type: 'list', - choices: [ - { name: 'Add another path', value: 'add' }, - { name: 'Update path', value: 'update' }, - { name: 'Remove path', value: 'remove' }], - }]; + const question = [ + { + name: 'resourceName', + message: 'Please select the REST API you would want to update', + type: 'list', + choices: resources, + }, + { + name: 'operation', + message: 'What would you like to do', + type: 'list', + choices: [ + { name: 'Add another path', value: 'add' }, + { name: 'Update path', value: 'update' }, + { name: 'Remove path', value: 'remove' }, + ], + }, + ]; const updateApi = await inquirer.prompt(question); @@ -130,14 +132,14 @@ async function pathFlow(context, answers, currentPath) { const { dependsOn } = pathsAnswer; const privacy = {}; - privacy.auth = pathsAnswer.paths - .filter(path => path.privacy.auth && path.privacy.auth.length > 0).length; - privacy.unauth = pathsAnswer.paths - .filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length; + privacy.auth = pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length; + privacy.unauth = pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length; answers = { ...answers, privacy, dependsOn }; - if (context.amplify.getProjectDetails() && context.amplify.getProjectDetails().amplifyMeta && + if ( + context.amplify.getProjectDetails() && + context.amplify.getProjectDetails().amplifyMeta && context.amplify.getProjectDetails().amplifyMeta.providers && context.amplify.getProjectDetails().amplifyMeta.providers.awscloudformation ) { @@ -182,7 +184,7 @@ async function askPrivacy(context, answers, currentPath) { const apiAccess = await inquirer.prompt({ name: 'restrict', type: 'confirm', - default: !((currentPath && currentPath.open)), + default: !(currentPath && currentPath.open), message: 'Restrict API access', }); @@ -204,21 +206,27 @@ async function askPrivacy(context, answers, currentPath) { value: 'protected', }, ], - default: (currentPath && currentPath.privacy && currentPath.privacy.protected) ? 'protected' : 'private', + default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', }); const privacy = {}; privacy[answer.privacy] = true; - if (answer.privacy === 'open') { return privacy; } + if (answer.privacy === 'open') { + return privacy; + } const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); context.api = { privacy: answer.privacy, }; - let { privacy: { auth: authPrivacy } } = currentPath || { privacy: {} }; - let { privacy: { unauth: unauthPrivacy } } = currentPath || { privacy: {} }; + let { + privacy: { auth: authPrivacy }, + } = currentPath || { privacy: {} }; + let { + privacy: { unauth: unauthPrivacy }, + } = currentPath || { privacy: {} }; // convert legacy permissions to CRUD structure if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { @@ -294,11 +302,7 @@ async function askReadWrite(userType, context, privacy) { }); } - return await context.amplify.crudFlow( - userType, - permissionMap, - defaults, - ); + return await context.amplify.crudFlow(userType, permissionMap, defaults); } async function askPaths(context, answers, currentPath) { @@ -422,7 +426,7 @@ function validatePathName(name, paths) { // Create subpath from the beginning to find a match on existing paths const findSubPath = (path, subpath) => path.name === subpath; let subpath = ''; - split.forEach((sub) => { + split.forEach(sub => { subpath = `${subpath}/${sub}`; const subpathFind = paths.find(path => findSubPath(path, subpath)); if (subpathFind) { @@ -443,7 +447,7 @@ function findDependsOn(paths) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; const functionArns = []; - paths.forEach((path) => { + paths.forEach(path => { if (path.lambdaFunction && !path.lambdaArn) { if (!dependsOn.find(func => func.resourceName === path.lambdaFunction)) { dependsOn.push({ @@ -470,7 +474,7 @@ function functionsExist(context) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; - Object.keys(functionResources).forEach((resourceName) => { + Object.keys(functionResources).forEach(resourceName => { if (functionResources[resourceName].service === 'Lambda') { lambdaFunctions.push(resourceName); } @@ -485,10 +489,14 @@ function functionsExist(context) { async function askLambdaSource(context, functionType, path, currentPath) { switch (functionType) { - case 'arn': return askLambdaArn(context, currentPath); - case 'projectFunction': return askLambdaFromProject(context, currentPath); - case 'newFunction': return newLambdaFunction(context, path); - default: throw new Error('Type not supported'); + case 'arn': + return askLambdaArn(context, currentPath); + case 'projectFunction': + return askLambdaFromProject(context, currentPath); + case 'newFunction': + return newLambdaFunction(context, path); + default: + throw new Error('Type not supported'); } } @@ -503,17 +511,16 @@ function newLambdaFunction(context, path) { path, functionTemplate: 'serverless', }; - return add(context, 'awscloudformation', 'Lambda') - .then((resourceName) => { - context.print.success('Succesfully added the Lambda function locally'); - return { lambdaFunction: resourceName }; - }); + return add(context, 'awscloudformation', 'Lambda').then(resourceName => { + context.print.success('Succesfully added the Lambda function locally'); + return { lambdaFunction: resourceName }; + }); } async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; - Object.keys(functionResources).forEach((resourceName) => { + Object.keys(functionResources).forEach(resourceName => { if (functionResources[resourceName].service === 'Lambda') { lambdaFunctions.push(resourceName); } @@ -548,8 +555,7 @@ async function askLambdaArn(context, currentPath) { name: 'lambdaChoice', message: 'Please select a Lambda function', choices: lambdaOptions, - default: (currentPath && currentPath.lambdaArn) ? - `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, + default: currentPath && currentPath.lambdaArn ? `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, }; let lambdaOption; @@ -561,8 +567,7 @@ async function askLambdaArn(context, currentPath) { } } - const lambdaCloudOptionAnswer = - lambdaFunctions.find(lambda => lambda.FunctionArn === lambdaOption.lambdaChoice); + const lambdaCloudOptionAnswer = lambdaFunctions.find(lambda => lambda.FunctionArn === lambdaOption.lambdaChoice); return { lambdaArn: lambdaCloudOptionAnswer.FunctionArn, @@ -637,28 +642,26 @@ function convertToCRUD(privacy) { return privacy; } - function getIAMPolicies(resourceName, crudOptions) { let policy = {}; const actions = []; - crudOptions.forEach((crudOption) => { + crudOptions.forEach(crudOption => { switch (crudOption) { - case 'create': actions.push( - 'apigateway:POST', - 'apigateway:PUT', - ); + case 'create': + actions.push('apigateway:POST', 'apigateway:PUT'); break; - case 'update': actions.push('apigateway:PATCH'); + case 'update': + actions.push('apigateway:PATCH'); break; - case 'read': actions.push( - 'apigateway:GET', 'apigateway:HEAD', - 'apigateway:OPTIONS', - ); + case 'read': + actions.push('apigateway:GET', 'apigateway:HEAD', 'apigateway:OPTIONS'); break; - case 'delete': actions.push('apigateway:DELETE'); + case 'delete': + actions.push('apigateway:DELETE'); break; - default: console.log(`${crudOption} not supported`); + default: + console.log(`${crudOption} not supported`); } }); @@ -691,5 +694,8 @@ function getIAMPolicies(resourceName, crudOptions) { } module.exports = { - serviceWalkthrough, updateWalkthrough, migrate, getIAMPolicies, + serviceWalkthrough, + updateWalkthrough, + migrate, + getIAMPolicies, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 16a3b0a53b..68b26eb6e0 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -10,9 +10,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 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) { - context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); + if (amplifyMeta == null || amplifyMeta[category] == null || Object.keys(amplifyMeta[category]).length === 0) { + context.print.error( + 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.' + ); process.exit(0); } @@ -29,7 +30,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // If an AppSync API does not exist, inform the user to create the AppSync API if (!appSyncApi) { - context.print.error('You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'); + context.print.error( + 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.' + ); process.exit(0); } @@ -52,8 +55,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta const selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS); // Database Name Question - const selectedDatabase = - await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); + const selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); return { region: selectedRegion, @@ -82,8 +84,7 @@ async function selectCluster(context, inputs, AWS) { } if (clusters.size > 0) { - const clusterIdentifier = - await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); + const clusterIdentifier = await promptWalkthroughQuestion(inputs, 1, Array.from(clusters.keys())); const selectedCluster = clusters.get(clusterIdentifier); return { @@ -137,8 +138,7 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { if (!selectedSecretArn && secrets.size > 0) { // Kick off questions flow - const selectedSecretName - = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); + const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); selectedSecretArn = secrets.get(selectedSecretName); } else { context.print.error('No RDS access credentials found in the AWS Secrect Manager.'); @@ -166,8 +166,7 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { const dataApiResult = await DataApi.executeStatement(params).promise(); // eslint-disable-next-line prefer-destructuring - const records - = dataApiResult.records; + const records = dataApiResult.records; const databaseList = []; for (let i = 0; i < records.length; i += 1) { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 292777ff98..972f15309a 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -16,11 +16,8 @@ function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); const categoryAmplifyMeta = amplifyMeta[category]; let appSyncMeta; - Object.keys(categoryAmplifyMeta).forEach((resourceName) => { - if ( - categoryAmplifyMeta[resourceName].service === serviceName && - categoryAmplifyMeta[resourceName].output - ) { + Object.keys(categoryAmplifyMeta).forEach(resourceName => { + if (categoryAmplifyMeta[resourceName].service === serviceName && categoryAmplifyMeta[resourceName].output) { appSyncMeta = categoryAmplifyMeta[resourceName].output; } }); @@ -40,7 +37,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const resourceName = resourceAlreadyExists(context); if (resourceName) { - context.print.warning('You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'); + context.print.warning( + 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.' + ); process.exit(0); } @@ -110,10 +109,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); - fs.writeFileSync( - `${resourceDir}/${stacksDirName}/${defaultStackName}`, - defaultCustomResourcesStack, - ); + fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); if (schemaFileAnswer[inputs[2].key]) { // User has an annotated schema file @@ -222,12 +218,11 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat let notCompiled = true; while (notCompiled) { try { - await context.amplify.executeProviderUtils( - context, - 'awscloudformation', - 'compileSchema', - { resourceDir, parameters, authConfig }, - ); + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters, + authConfig, + }); } catch (e) { context.print.error('Failed compiling GraphQL schema:'); context.print.info(e.message); @@ -266,7 +261,9 @@ async function updateWalkthrough(context) { const 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}`); + 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); const backEndDir = context.amplify.pathManager.getBackendDirPath(); @@ -395,14 +392,12 @@ async function askSecurityQuestions(context, parameters) { authConfig.additionalAuthenticationProviders.push(config); } } - const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter(provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS'); - const additionalUserPoolProvider = - additionalUserPoolProviders.length > 0 ? additionalUserPoolProviders[0] : undefined; - - if ( - authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || - additionalUserPoolProvider - ) { + const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter( + provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS' + ); + const additionalUserPoolProvider = additionalUserPoolProviders.length > 0 ? additionalUserPoolProviders[0] : undefined; + + if (authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { let userPoolId; const configuredUserPoolName = checkIfAuthExists(context); @@ -566,7 +561,9 @@ function validateDays(input) { } function validateIssuerUrl(input) { - const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test(input); + 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.'; @@ -592,7 +589,7 @@ function resourceAlreadyExists(context) { if (amplifyMeta[category]) { const categoryResources = amplifyMeta[category]; - Object.keys(categoryResources).forEach((resource) => { + Object.keys(categoryResources).forEach(resource => { if (categoryResources[resource].service === serviceName) { resourceName = resource; } @@ -611,7 +608,7 @@ function checkIfAuthExists(context) { if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { const categoryResources = amplifyMeta[authCategory]; - Object.keys(categoryResources).forEach((resource) => { + Object.keys(categoryResources).forEach(resource => { if (categoryResources[resource].service === authServiceName) { authResourceName = resource; } @@ -631,7 +628,7 @@ function getIAMPolicies(resourceName, crudOptions) { let policy = {}; const actions = []; - crudOptions.forEach((crudOption) => { + crudOptions.forEach(crudOption => { switch (crudOption) { case 'create': actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); @@ -683,10 +680,7 @@ function getAuthTypes(authConfig) { .map(provider => provider.authenticationType) .filter(t => !!t); - const uniqueAuthTypes = new Set([ - ...additionalAuthTypes, - authConfig.defaultAuthentication.authenticationType, - ]); + const uniqueAuthTypes = new Set([...additionalAuthTypes, authConfig.defaultAuthentication.authenticationType]); return [...uniqueAuthTypes.keys()]; } From 7a4083f9bc85b80e63d6ecd7b6053681ae2edecb Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Fri, 4 Oct 2019 20:45:41 +0200 Subject: [PATCH 237/587] fix: change default length for api key back to 7 days (#2507) --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 972f15309a..941a8e5295 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -496,7 +496,7 @@ async function askApiKeyQuestions() { type: 'input', name: 'apiKeyExpirationDays', message: 'After how many days from now the API key should expire (1-365):', - default: 180, + default: 7, validate: validateDays, }, ]; From 36dab68d3913106e54fbce22fa9c7a4538793d72 Mon Sep 17 00:00:00 2001 From: TrueLecter Date: Tue, 8 Oct 2019 00:21:10 +0300 Subject: [PATCH 238/587] fix(amplify-category-api): Fix #2498 (#2503) * Fixes 'No RDS access credentials found in the AWS Secret Manager' when Query Editor secret is found * Codestyle fix --- .../appSync-rds-walkthrough.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 68b26eb6e0..ba68ea74da 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -136,13 +136,15 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { secrets.set(rawSecrets[i].Name, rawSecrets[i].ARN); } - if (!selectedSecretArn && secrets.size > 0) { - // Kick off questions flow - const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); - selectedSecretArn = secrets.get(selectedSecretName); - } else { - context.print.error('No RDS access credentials found in the AWS Secrect Manager.'); - process.exit(0); + if (!selectedSecretArn) { + if (secrets.size > 0) { + // Kick off questions flow + const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); + selectedSecretArn = secrets.get(selectedSecretName); + } else { + context.print.error('No RDS access credentials found in the AWS Secrect Manager.'); + process.exit(0); + } } return selectedSecretArn; From 2477171634481c55e74388819dbf1262d9eadd99 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Tue, 8 Oct 2019 14:35:14 -0700 Subject: [PATCH 239/587] fix(cli): add console command in the help message (#2494) * fix(cli): add console command in the help message fix #1607 * add console section in help commands * add help messages for awscloudformation * minor fix * minor fix * change per review request * minor fixes --- packages/amplify-category-api/commands/api.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index a59782c5c8..d1243e0f1c 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -37,6 +37,10 @@ module.exports = { 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', + }, ]; context.amplify.showHelp(header, commands); From 2ffef0f6e110632c678b2a137e03666287613b53 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Thu, 10 Oct 2019 04:52:12 -0700 Subject: [PATCH 240/587] chore(release): Publish [ci skip] (#2549) - amplify-appsync-simulator@0.18.0 - amplify-category-analytics@1.23.0 - amplify-category-api@1.25.0 - amplify-category-auth@1.25.0 - amplify-category-function@1.25.0 - amplify-category-hosting@1.21.0 - amplify-category-interactions@1.24.0 - amplify-category-notifications@1.22.0 - amplify-category-predictions@1.19.0 - amplify-category-storage@1.26.0 - amplify-category-xr@1.24.0 - @aws-amplify/cli@3.12.0 - amplify-codegen@1.24.0 - amplify-dynamodb-simulator@0.18.0 - amplify-e2e-tests@1.25.0 - amplify-frontend-android@1.27.0 - amplify-frontend-ios@1.27.0 - amplify-frontend-javascript@1.25.0 - amplify-graphiql-explorer@0.18.0 - amplify-graphql-docs-generator@1.23.0 - amplify-graphql-types-generator@1.19.0 - amplify-provider-awscloudformation@3.12.0 - amplify-storage-simulator@0.18.0 - amplify-ui-tests@1.13.0 - amplify-util-mock@2.12.0 - amplify-velocity-template@0.17.0 - graphql-auth-transformer@5.13.0 - graphql-connection-transformer@3.24.0 - graphql-dynamodb-transformer@5.13.0 - graphql-elasticsearch-transformer@3.25.0 - graphql-function-transformer@1.20.0 - graphql-http-transformer@3.23.0 - graphql-key-transformer@1.20.0 - graphql-mapping-template@3.20.0 - graphql-relational-schema-transformer@1.19.0 - graphql-transformer-common@3.27.0 - graphql-transformer-core@5.13.0 - graphql-transformers-e2e-tests@5.13.0 - graphql-versioned-transformer@3.23.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0c9eedb94e..41dd18f3a9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.24.0", + "version": "1.25.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.24.0", - "amplify-category-function": "1.24.0", - "amplify-category-storage": "1.25.0", + "amplify-category-auth": "1.25.0", + "amplify-category-function": "1.25.0", + "amplify-category-storage": "1.26.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.18.0", + "graphql-relational-schema-transformer": "1.19.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From 87dd1561034bdbb9ea903a0ce5ba64bdedf4747f Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 11 Oct 2019 12:17:31 -0700 Subject: [PATCH 241/587] chore(release): Publish [ci skip] (#2565) * git rm --cached amplify-velociy-template/src/parse/index.js * chore(release): Publish [ci skip] - amplify-appsync-simulator@0.19.0 - amplify-category-analytics@1.24.0 - amplify-category-api@1.26.0 - amplify-category-auth@1.26.0 - amplify-category-function@1.26.0 - amplify-category-hosting@1.22.0 - amplify-category-interactions@1.25.0 - amplify-category-notifications@1.23.0 - amplify-category-predictions@1.20.0 - amplify-category-storage@1.27.0 - amplify-category-xr@1.25.0 - @aws-amplify/cli@3.13.0 - amplify-codegen@1.25.0 - amplify-dynamodb-simulator@0.19.0 - amplify-e2e-tests@1.26.0 - amplify-frontend-android@1.28.0 - amplify-frontend-ios@1.28.0 - amplify-frontend-javascript@1.26.0 - amplify-graphiql-explorer@0.19.0 - amplify-graphql-docs-generator@1.24.0 - amplify-graphql-types-generator@1.20.0 - amplify-provider-awscloudformation@3.13.0 - amplify-storage-simulator@0.19.0 - amplify-ui-tests@1.14.0 - amplify-util-mock@2.13.0 - amplify-velocity-template@0.18.0 - graphql-auth-transformer@5.14.0 - graphql-connection-transformer@3.25.0 - graphql-dynamodb-transformer@5.14.0 - graphql-elasticsearch-transformer@3.26.0 - graphql-function-transformer@1.21.0 - graphql-http-transformer@3.24.0 - graphql-key-transformer@1.21.0 - graphql-mapping-template@3.21.0 - graphql-relational-schema-transformer@1.20.0 - graphql-transformer-common@3.28.0 - graphql-transformer-core@5.14.0 - graphql-transformers-e2e-tests@5.14.0 - graphql-versioned-transformer@3.24.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 41dd18f3a9..36ee0efad4 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.25.0", + "version": "1.26.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.25.0", - "amplify-category-function": "1.25.0", - "amplify-category-storage": "1.26.0", + "amplify-category-auth": "1.26.0", + "amplify-category-function": "1.26.0", + "amplify-category-storage": "1.27.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.19.0", + "graphql-relational-schema-transformer": "1.20.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From 75f8486a5ca6a6ea2d6b4bc5ea95c17bc60a891e Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 11 Oct 2019 18:48:54 -0700 Subject: [PATCH 242/587] chore(release): Publish [ci skip] (#2573) - amplify-appsync-simulator@0.20.0 - amplify-category-analytics@1.25.0 - amplify-category-api@1.27.0 - amplify-category-auth@1.27.0 - amplify-category-function@1.27.0 - amplify-category-hosting@1.23.0 - amplify-category-interactions@1.26.0 - amplify-category-notifications@1.24.0 - amplify-category-predictions@1.21.0 - amplify-category-storage@1.28.0 - amplify-category-xr@1.26.0 - @aws-amplify/cli@3.14.0 - amplify-codegen@1.26.0 - amplify-dynamodb-simulator@0.20.0 - amplify-e2e-tests@1.27.0 - amplify-frontend-android@1.29.0 - amplify-frontend-ios@1.29.0 - amplify-frontend-javascript@1.27.0 - amplify-graphiql-explorer@0.20.0 - amplify-graphql-docs-generator@1.25.0 - amplify-graphql-types-generator@1.21.0 - amplify-provider-awscloudformation@3.14.0 - amplify-storage-simulator@0.20.0 - amplify-ui-tests@1.15.0 - amplify-util-mock@2.14.0 - amplify-velocity-template@0.19.0 - graphql-auth-transformer@5.15.0 - graphql-connection-transformer@3.26.0 - graphql-dynamodb-transformer@5.15.0 - graphql-elasticsearch-transformer@3.27.0 - graphql-function-transformer@1.22.0 - graphql-http-transformer@3.25.0 - graphql-key-transformer@1.22.0 - graphql-mapping-template@3.22.0 - graphql-relational-schema-transformer@1.21.0 - graphql-transformer-common@3.29.0 - graphql-transformer-core@5.15.0 - graphql-transformers-e2e-tests@5.15.0 - graphql-versioned-transformer@3.25.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 36ee0efad4..1d197d75b5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.26.0", + "version": "1.27.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.26.0", - "amplify-category-function": "1.26.0", - "amplify-category-storage": "1.27.0", + "amplify-category-auth": "1.27.0", + "amplify-category-function": "1.27.0", + "amplify-category-storage": "1.28.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.20.0", + "graphql-relational-schema-transformer": "1.21.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From a71f5b7762f9f54c3113afbccae99c5ec729f8ac Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Mon, 14 Oct 2019 12:47:34 -0700 Subject: [PATCH 243/587] fix(amplify-category-api): use standard json read (#2581) use standard amplify cli provided json read to avoid json parse bug --- .../commands/api/add-graphql-datasource.js | 2 +- packages/amplify-category-api/commands/api/add.js | 4 +--- packages/amplify-category-api/commands/api/console.js | 4 +--- packages/amplify-category-api/commands/api/update.js | 4 +--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/commands/api/add-graphql-datasource.js index 5d9525d9f3..2290f6db06 100644 --- a/packages/amplify-category-api/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/commands/api/add-graphql-datasource.js @@ -9,7 +9,6 @@ const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; const providerName = 'awscloudformation'; -const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-datasources.json`)); const rdsRegion = 'rdsRegion'; const rdsIdentifier = 'rdsClusterIdentifier'; @@ -23,6 +22,7 @@ module.exports = { name: subcommand, run: async context => { const { amplify } = context; + const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-datasources.json`); let resourceName; let datasource; let databaseName; diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index e71e363c50..cebc5de014 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -1,8 +1,5 @@ -const fs = require('fs'); - const subcommand = 'add'; const category = 'api'; -const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); let options; @@ -10,6 +7,7 @@ module.exports = { name: subcommand, run: async context => { const { amplify } = context; + const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); return amplify .serviceSelectionPrompt(context, category, servicesMetadata) .then(result => { diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index e9260f3e7e..6970d423e2 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -1,13 +1,11 @@ -const fs = require('fs'); - const subcommand = 'console'; const category = 'api'; -const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); module.exports = { name: subcommand, run: async context => { const { amplify } = context; + const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); return amplify .serviceSelectionPrompt(context, category, servicesMetadata) .then(result => { diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index 27a5ee171c..4d27616a3a 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -1,14 +1,12 @@ -const fs = require('fs'); - const subcommand = 'update'; const category = 'api'; -const servicesMetadata = JSON.parse(fs.readFileSync(`${__dirname}/../../provider-utils/supported-services.json`)); module.exports = { name: subcommand, alias: ['configure'], run: async context => { const { amplify } = context; + const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); return amplify .serviceSelectionPrompt(context, category, servicesMetadata) From 5794b86407ac7a05b77883178e563e3407444c3c Mon Sep 17 00:00:00 2001 From: Patrick Donelan Date: Tue, 15 Oct 2019 07:49:38 +1100 Subject: [PATCH 244/587] Remove incorrect apostrophe in command description (#2578) s/it's/its/ in output of `amplify api help` --- packages/amplify-category-api/commands/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js index d1243e0f1c..948dc4ae4a 100755 --- a/packages/amplify-category-api/commands/api.js +++ b/packages/amplify-category-api/commands/api.js @@ -19,7 +19,7 @@ module.exports = { }, { name: 'push', - description: `Provisions ${featureName} cloud resources and it's dependencies with the latest local developments`, + description: `Provisions ${featureName} cloud resources and its dependencies with the latest local developments`, }, { name: 'remove', From 28f7edadc7cb18e7c51c51a50b9c0d9e656f817e Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 15 Oct 2019 11:45:17 -0700 Subject: [PATCH 245/587] chore(release): Publish [ci skip] (#2585) - amplify-appsync-simulator@0.21.0 - amplify-category-analytics@1.26.0 - amplify-category-api@1.28.0 - amplify-category-auth@1.28.0 - amplify-category-function@1.28.0 - amplify-category-hosting@1.24.0 - amplify-category-interactions@1.27.0 - amplify-category-notifications@1.25.0 - amplify-category-predictions@1.22.0 - amplify-category-storage@1.29.0 - amplify-category-xr@1.27.0 - @aws-amplify/cli@3.15.0 - amplify-codegen@1.27.0 - amplify-dynamodb-simulator@0.21.0 - amplify-e2e-tests@1.28.0 - amplify-frontend-android@1.30.0 - amplify-frontend-ios@1.30.0 - amplify-frontend-javascript@1.28.0 - amplify-graphiql-explorer@0.21.0 - amplify-graphql-docs-generator@1.26.0 - amplify-graphql-types-generator@1.22.0 - amplify-provider-awscloudformation@3.15.0 - amplify-storage-simulator@0.21.0 - amplify-ui-tests@1.16.0 - amplify-util-mock@2.15.0 - amplify-velocity-template@0.20.0 - graphql-auth-transformer@5.16.0 - graphql-connection-transformer@3.27.0 - graphql-dynamodb-transformer@5.16.0 - graphql-elasticsearch-transformer@3.28.0 - graphql-function-transformer@1.23.0 - graphql-http-transformer@3.26.0 - graphql-key-transformer@1.23.0 - graphql-mapping-template@3.23.0 - graphql-relational-schema-transformer@1.22.0 - graphql-transformer-common@3.30.0 - graphql-transformer-core@5.16.0 - graphql-transformers-e2e-tests@5.16.0 - graphql-versioned-transformer@3.26.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1d197d75b5..ef8ece0af2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.27.0", + "version": "1.28.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.27.0", - "amplify-category-function": "1.27.0", - "amplify-category-storage": "1.28.0", + "amplify-category-auth": "1.28.0", + "amplify-category-function": "1.28.0", + "amplify-category-storage": "1.29.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.21.0", + "graphql-relational-schema-transformer": "1.22.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From e0b37806aef2a0f4f885a2b04231615f23ca7ce4 Mon Sep 17 00:00:00 2001 From: Andrew Davidson Date: Tue, 22 Oct 2019 00:01:59 +0100 Subject: [PATCH 246/587] Add new available regions for Aurora Serverless (#1556) --- .../provider-utils/supported-datasources.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/supported-datasources.json b/packages/amplify-category-api/provider-utils/supported-datasources.json index 8e9475f17c..1b17b5fea8 100644 --- a/packages/amplify-category-api/provider-utils/supported-datasources.json +++ b/packages/amplify-category-api/provider-utils/supported-datasources.json @@ -34,6 +34,6 @@ "serviceWalkthroughFilename": "appSync-rds-walkthrough.js", "cfnFilename": "appSync-rds-cloudformation-template-default.yml.ejs", "provider": "awscloudformation", - "availableRegions": ["us-east-1"] + "availableRegions": ["us-east-1", "us-east-2", "us-west-2", "ap-northeast-1", "eu-west-1"] } -} \ No newline at end of file +} From f132e3f4d133da0d70500cf38e387c5f4f9bc73f Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Thu, 24 Oct 2019 23:23:23 -0700 Subject: [PATCH 247/587] chore(release): Publish [ci skip] (#2630) - amplify-appsync-simulator@0.22.0 - amplify-category-analytics@1.27.0 - amplify-category-api@1.29.0 - amplify-category-auth@1.29.0 - amplify-category-function@1.29.0 - amplify-category-hosting@1.25.0 - amplify-category-interactions@1.28.0 - amplify-category-notifications@1.26.0 - amplify-category-predictions@1.23.0 - amplify-category-storage@1.30.0 - amplify-category-xr@1.28.0 - @aws-amplify/cli@3.16.0 - amplify-codegen@1.28.0 - amplify-dynamodb-simulator@0.22.0 - amplify-e2e-tests@1.29.0 - amplify-frontend-android@1.31.0 - amplify-frontend-ios@1.31.0 - amplify-frontend-javascript@1.29.0 - amplify-graphiql-explorer@0.22.0 - amplify-graphql-docs-generator@1.27.0 - amplify-graphql-types-generator@1.23.0 - amplify-provider-awscloudformation@3.16.0 - amplify-storage-simulator@0.22.0 - amplify-ui-tests@1.17.0 - amplify-util-mock@2.16.0 - amplify-velocity-template@0.21.0 - graphql-auth-transformer@5.17.0 - graphql-connection-transformer@3.28.0 - graphql-dynamodb-transformer@5.17.0 - graphql-elasticsearch-transformer@3.29.0 - graphql-function-transformer@1.24.0 - graphql-http-transformer@3.27.0 - graphql-key-transformer@1.24.0 - graphql-mapping-template@3.24.0 - graphql-relational-schema-transformer@1.23.0 - graphql-transformer-common@3.31.0 - graphql-transformer-core@5.17.0 - graphql-transformers-e2e-tests@5.17.0 - graphql-versioned-transformer@3.27.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ef8ece0af2..4217d4fb09 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.28.0", + "version": "1.29.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.28.0", - "amplify-category-function": "1.28.0", - "amplify-category-storage": "1.29.0", + "amplify-category-auth": "1.29.0", + "amplify-category-function": "1.29.0", + "amplify-category-storage": "1.30.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.22.0", + "graphql-relational-schema-transformer": "1.23.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From e4c345722dde76d284327e2026adad18d74e6c94 Mon Sep 17 00:00:00 2001 From: Richard Threlkeld Date: Wed, 30 Oct 2019 17:28:00 -0700 Subject: [PATCH 248/587] feat: User Pool Groups, Admin Auth Support, Custom Group Role Policies (#2443) --- ...w-cloudformation-template-default.json.ejs | 110 +++++++ .../service-walkthroughs/apigw-walkthrough.js | 274 +++++++++++++----- 2 files changed, 314 insertions(+), 70 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 244f836f80..28974b62bf 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -135,6 +135,116 @@ } }, <% } %> + <% for(var i=0; i < props.paths.length; i++) { %> + <%if (props.paths[i].privacy && props.paths[i].privacy.userPoolGroups) { %> + <% let selectedUserPoolGroupList = Object.keys(props.paths[i].privacy.userPoolGroups); %> + <% for(var j=0; j < selectedUserPoolGroupList.length; j++) { %> + "<%=selectedUserPoolGroupList[j]%>Group<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>Policy": { + "DependsOn": [ + "<%= props.apiName %>" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "<%= props.apiName %>-<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>-<%=selectedUserPoolGroupList[j]%>-group-policy", + "Roles": [ + { + "Fn::Join": [ + "", + [ + { + "Ref": "auth<%= props.authResourceName%>UserPoolId" + }, + "-<%=selectedUserPoolGroupList[j]%>GroupRole" + ] + ] + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "execute-api:Invoke" + ], + "Resource": [ + + <% for(var x=0; x < props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length; x++) { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", + "<%= props.paths[i].name %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", + "<%= props.paths[i].name %>" + ] + ] + } + <% if (x !== props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length - 1) { %> + , + <% } %> + <% } %> + ] + } + ] + } + } + }, + <% } %> + <% } %> + <% } %> <%if (props.privacy.unauth) { %> "PolicyAPIGW<%= props.apiName %>unauth": { "DependsOn": [ diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 95dc31b4fe..c3f566e2b8 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -64,6 +64,13 @@ async function updateWalkthrough(context, defaultValuesFilename) { const updateApi = await inquirer.prompt(question); + if (updateApi.resourceName === 'AdminQueries') { + context.print.warning( + `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command` + ); + process.exit(0); + } + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const resourceDirPath = pathLib.join(projectBackendDirPath, category, updateApi.resourceName); const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); @@ -96,7 +103,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { answers.paths = answers.paths.filter(path => path.name !== pathToRemove.path); - const { dependsOn, functionArns } = findDependsOn(answers.paths); + const { dependsOn, functionArns } = await findDependsOn(answers.paths, context); answers.dependsOn = dependsOn; answers.functionArns = functionArns; @@ -192,52 +199,119 @@ async function askPrivacy(context, answers, currentPath) { return { open: true }; } - const answer = await inquirer.prompt({ - name: 'privacy', - type: 'list', - message: 'Who should have access?', - choices: [ - { - name: 'Authenticated users only', - value: 'private', - }, - { - name: 'Authenticated and Guest users', - value: 'protected', - }, - ], - default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', - }); + const userPoolGroupList = await context.amplify.getUserPoolGroupList(context); + let permissionSelected = 'Auth/Guest Users'; + let allowUnauthenticatedIdentities = false; const privacy = {}; - privacy[answer.privacy] = true; + const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); - if (answer.privacy === 'open') { - return privacy; - } + if (userPoolGroupList.length > 0) { + do { + if (permissionSelected === 'Learn more') { + context.print.info(''); + context.print.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.' + ); + context.print.info(''); + } + const permissionSelection = await inquirer.prompt({ + name: 'selection', + type: 'list', + message: 'Restrict access by?', + choices: ['Auth/Guest Users', 'Individual Groups', 'Both', 'Learn more'], + default: 'Auth/Guest Users', + }); - const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); - context.api = { - privacy: answer.privacy, - }; - - let { - privacy: { auth: authPrivacy }, - } = currentPath || { privacy: {} }; - let { - privacy: { unauth: unauthPrivacy }, - } = currentPath || { privacy: {} }; - - // convert legacy permissions to CRUD structure - if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { - authPrivacy = convertToCRUD(authPrivacy); + permissionSelected = permissionSelection.selection; + } while (permissionSelected === 'Learn more'); } - if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { - unauthPrivacy = convertToCRUD(unauthPrivacy); + + if (permissionSelected === 'Both' || permissionSelected === 'Auth/Guest Users') { + const answer = await inquirer.prompt({ + name: 'privacy', + type: 'list', + message: 'Who should have access?', + choices: [ + { + name: 'Authenticated users only', + value: 'private', + }, + { + name: 'Authenticated and Guest users', + value: 'protected', + }, + ], + default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', + }); + + privacy[answer.privacy] = true; + + context.api = { + privacy: answer.privacy, + }; + + let { + privacy: { auth: authPrivacy }, + } = currentPath || { privacy: {} }; + let { + privacy: { unauth: unauthPrivacy }, + } = currentPath || { privacy: {} }; + + // convert legacy permissions to CRUD structure + if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { + authPrivacy = convertToCRUD(authPrivacy); + } + if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { + unauthPrivacy = convertToCRUD(unauthPrivacy); + } + + if (answer.privacy === 'private') { + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + } catch (e) { + context.print.error(e); + throw e; + } + } + } + + if (answer.privacy === 'protected') { + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); + allowUnauthenticatedIdentities = true; + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities }; + // getting requirement satisfaction map + const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + // checking to see if any requirements are unsatisfied + const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + + // if requirements are unsatisfied, trigger auth + + if (foundUnmetRequirements) { + try { + await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); + } catch (e) { + context.print.error(e); + throw e; + } + } + } } - if (answer.privacy === 'private') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + if (permissionSelected === 'Both' || permissionSelected === 'Individual Groups') { + // Enable Auth if not enabled const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; // getting requirement satisfaction map @@ -250,37 +324,56 @@ async function askPrivacy(context, answers, currentPath) { if (foundUnmetRequirements) { try { await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - return privacy; } catch (e) { context.print.error(e); throw e; } } - } - if (answer.privacy === 'protected') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); - privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); + // Get Auth resource name + const authResourceName = await getAuthResourceName(context); + answers.authResourceName = authResourceName; - const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); + let defaultSelectedGroups = []; - // if requirements are unsatisfied, trigger auth + if (currentPath && currentPath.privacy && currentPath.privacy.userPoolGroups) { + defaultSelectedGroups = Object.keys(currentPath.privacy.userPoolGroups); + } - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - return privacy; - } catch (e) { - context.print.error(e); - throw e; + const userPoolGroupSelection = await inquirer.prompt([ + { + name: 'userpoolGroups', + type: 'checkbox', + message: 'Select groups:', + choices: userPoolGroupList, + default: defaultSelectedGroups, + validate: inputs => { + if (inputs.length === 0) { + return 'Select at least one option'; + } + return true; + }, + }, + ]); + + const selectedUserPoolGroupList = userPoolGroupSelection.userpoolGroups; + + for (let i = 0; i < selectedUserPoolGroupList.length; i += 1) { + let defaults = []; + if ( + currentPath && + currentPath.privacy && + currentPath.privacy.userPoolGroups && + currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]] + ) { + defaults = currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]]; } + if (!privacy.userPoolGroups) { + privacy.userPoolGroups = {}; + } + privacy.userPoolGroups[selectedUserPoolGroupList[i]] = await askReadWrite(selectedUserPoolGroupList[i], context, defaults); } } - return privacy; } } @@ -302,7 +395,9 @@ async function askReadWrite(userType, context, privacy) { }); } - return await context.amplify.crudFlow(userType, permissionMap, defaults); + const crudAnswers = await context.amplify.crudFlow(userType, permissionMap, defaults); + + return crudAnswers; } async function askPaths(context, answers, currentPath) { @@ -380,6 +475,7 @@ async function askPaths(context, answers, currentPath) { if (currentPath) { break; } + addAnotherPath = (await inquirer.prompt({ name: 'anotherPath', type: 'confirm', @@ -388,7 +484,7 @@ async function askPaths(context, answers, currentPath) { })).anotherPath; } while (addAnotherPath); - const { dependsOn, functionArns } = findDependsOn(paths); + const { dependsOn, functionArns } = await findDependsOn(paths, context); return { paths, dependsOn, functionArns }; } @@ -443,30 +539,68 @@ function validatePathName(name, paths) { return err; } -function findDependsOn(paths) { +async function findDependsOn(paths, context) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; const functionArns = []; - paths.forEach(path => { - if (path.lambdaFunction && !path.lambdaArn) { - if (!dependsOn.find(func => func.resourceName === path.lambdaFunction)) { + + for (let i = 0; i < paths.length; i += 1) { + if (paths[i].lambdaFunction && !paths[i].lambdaArn) { + if (!dependsOn.find(func => func.resourceName === paths[i].lambdaFunction)) { dependsOn.push({ category: 'function', - resourceName: path.lambdaFunction, + resourceName: paths[i].lambdaFunction, attributes: ['Name', 'Arn'], }); } } - if (!functionArns.find(func => func.lambdaFunction === path.lambdaFunction)) { + if (!functionArns.find(func => func.lambdaFunction === paths[i].lambdaFunction)) { functionArns.push({ - lambdaFunction: path.lambdaFunction, - lambdaArn: path.lambdaArn, + lambdaFunction: paths[i].lambdaFunction, + lambdaArn: paths[i].lambdaArn, }); } - }); + if (paths[i].privacy && paths[i].privacy.userPoolGroups) { + const userPoolGroups = Object.keys(paths[i].privacy.userPoolGroups); + if (userPoolGroups.length > 0) { + // Get auth resource name + + const authResourceName = await getAuthResourceName(context); + + 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 }; } +async function getAuthResourceName(context) { + let authResources = (await context.amplify.getResourceStatus('auth')).allResources; + authResources = authResources.filter(resource => resource.service === 'Cognito'); + if (authResources.length === 0) { + throw new Error('No auth resource found. Please add it using amplify add auth'); + } + + const authResourceName = authResources[0].resourceName; + return authResourceName; +} + function functionsExist(context) { if (!context.amplify.getProjectDetails().amplifyMeta.function) { return false; From f624212bdd0a71eabba57ba907a9f46960a5d9a7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 31 Oct 2019 02:38:02 +0000 Subject: [PATCH 249/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@0.23.0 - amplify-category-analytics@1.28.0 - amplify-category-api@1.30.0 - amplify-category-auth@1.30.0 - amplify-category-function@1.30.0 - amplify-category-hosting@1.26.0 - amplify-category-interactions@1.29.0 - amplify-category-notifications@1.27.0 - amplify-category-predictions@1.24.0 - amplify-category-storage@1.31.0 - amplify-category-xr@1.29.0 - @aws-amplify/cli@3.17.0 - amplify-codegen@1.29.0 - amplify-dynamodb-simulator@0.23.0 - amplify-e2e-tests@1.30.0 - amplify-frontend-android@1.32.0 - amplify-frontend-ios@1.32.0 - amplify-frontend-javascript@1.30.0 - amplify-graphiql-explorer@0.23.0 - amplify-graphql-docs-generator@1.28.0 - amplify-graphql-types-generator@1.24.0 - amplify-provider-awscloudformation@3.17.0 - amplify-storage-simulator@0.23.0 - amplify-ui-tests@1.18.0 - amplify-util-mock@2.17.0 - amplify-velocity-template@0.22.0 - graphql-auth-transformer@5.18.0 - graphql-connection-transformer@3.29.0 - graphql-dynamodb-transformer@5.18.0 - graphql-elasticsearch-transformer@3.30.0 - graphql-function-transformer@1.25.0 - graphql-http-transformer@3.28.0 - graphql-key-transformer@1.25.0 - graphql-mapping-template@3.25.0 - graphql-relational-schema-transformer@1.24.0 - graphql-transformer-common@3.32.0 - graphql-transformer-core@5.18.0 - graphql-transformers-e2e-tests@5.18.0 - graphql-versioned-transformer@3.28.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4217d4fb09..737fa63142 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.29.0", + "version": "1.30.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.29.0", - "amplify-category-function": "1.29.0", - "amplify-category-storage": "1.30.0", + "amplify-category-auth": "1.30.0", + "amplify-category-function": "1.30.0", + "amplify-category-storage": "1.31.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.23.0", + "graphql-relational-schema-transformer": "1.24.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From fbceb6544adad1ba7fdd64743ee7031369c58367 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Wed, 30 Oct 2019 19:54:11 -0700 Subject: [PATCH 250/587] chore(release): Publish [ci skip] (#2653) - amplify-appsync-simulator@0.23.0 - amplify-category-analytics@1.28.0 - amplify-category-api@1.30.0 - amplify-category-auth@1.30.0 - amplify-category-function@1.30.0 - amplify-category-hosting@1.26.0 - amplify-category-interactions@1.29.0 - amplify-category-notifications@1.27.0 - amplify-category-predictions@1.24.0 - amplify-category-storage@1.31.0 - amplify-category-xr@1.29.0 - @aws-amplify/cli@3.17.0 - amplify-codegen@1.29.0 - amplify-dynamodb-simulator@0.23.0 - amplify-e2e-tests@1.30.0 - amplify-frontend-android@1.32.0 - amplify-frontend-ios@1.32.0 - amplify-frontend-javascript@1.30.0 - amplify-graphiql-explorer@0.23.0 - amplify-graphql-docs-generator@1.28.0 - amplify-graphql-types-generator@1.24.0 - amplify-provider-awscloudformation@3.17.0 - amplify-storage-simulator@0.23.0 - amplify-ui-tests@1.18.0 - amplify-util-mock@2.17.0 - amplify-velocity-template@0.22.0 - graphql-auth-transformer@5.18.0 - graphql-connection-transformer@3.29.0 - graphql-dynamodb-transformer@5.18.0 - graphql-elasticsearch-transformer@3.30.0 - graphql-function-transformer@1.25.0 - graphql-http-transformer@3.28.0 - graphql-key-transformer@1.25.0 - graphql-mapping-template@3.25.0 - graphql-relational-schema-transformer@1.24.0 - graphql-transformer-common@3.32.0 - graphql-transformer-core@5.18.0 - graphql-transformers-e2e-tests@5.18.0 - graphql-versioned-transformer@3.28.0 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4217d4fb09..737fa63142 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.29.0", + "version": "1.30.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,13 +10,13 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.29.0", - "amplify-category-function": "1.29.0", - "amplify-category-storage": "1.30.0", + "amplify-category-auth": "1.30.0", + "amplify-category-function": "1.30.0", + "amplify-category-storage": "1.31.0", "aws-sdk": "^2.510.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.23.0", + "graphql-relational-schema-transformer": "1.24.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", From 432ff95c273f08aad00f81c71a043af4cf8d8ac4 Mon Sep 17 00:00:00 2001 From: ammarkarachi <56042290+ammarkarachi@users.noreply.github.com> Date: Fri, 1 Nov 2019 15:13:51 -0700 Subject: [PATCH 251/587] feat: Delete all (#2615) * feat(cli): implemented delete all delete all also deletes the deployment bucket * style(cli): rewording the prompt * test: test for deleting a project * feat(cli): added deleting an environment through the same workflow * style: fixed lonely if * refactor(cli): removed unused * refactor(amplify-provider-awscloudformation): refactored code refactored for initialize project * feat(amplify-provider-awscloudformation): deleteing storage too now Getting the zip info and deleting the storage created too * style: unused variable and require line * test(amplify-e2e-tests): delete all test for environments Add environment and then delete all to test deletion of all environments * refactor(amplify-provider-awscloudformation): get file by env use a default argument for environment name * feat(cli): added delete s3 with --force --force overrides deleting and deleting also deletes the s3 buckets * refactor(cli): linter errors * refactor(cli): fix tabs for linter * style(cli): space in comment * feat: delete graphql generated files * style: destructuring and graphql-config lib * refactor: removed deleting an unused file * refactor(amplify-e2e-tests): changed function name changed function name from initProjectWithProfile to initJSProjectWithProfile * refactor(amplify-provider-awscloudformation): renamed function renamed function to deleteObject to deleteAllObjects * fix(cli): graphql files not removed on remnove env graphql files will only removed when delete is executed * test(amplify-e2e-tests): check for existense of s3 * refactor(cli): removed unused * refactor(amplify-provider-awscloudformation): renamed variable renamed variable to make it less generic * refactor(cli): used path to join * refactor: refactored code in to a function * refactor(amplify-provider-awscloudformation): changed variable name * chore: yarn.lock --- .../provider-utils/supported-datasources.json | 71 +++++++++---------- 1 file changed, 34 insertions(+), 37 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/supported-datasources.json b/packages/amplify-category-api/provider-utils/supported-datasources.json index 1b17b5fea8..6916a622ab 100644 --- a/packages/amplify-category-api/provider-utils/supported-datasources.json +++ b/packages/amplify-category-api/provider-utils/supported-datasources.json @@ -1,39 +1,36 @@ { - "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", - "defaultValuesFilename": "appSync-rds-defaults.js", - "serviceWalkthroughFilename": "appSync-rds-walkthrough.js", - "cfnFilename": "appSync-rds-cloudformation-template-default.yml.ejs", - "provider": "awscloudformation", - "availableRegions": ["us-east-1", "us-east-2", "us-west-2", "ap-northeast-1", "eu-west-1"] - } + "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", + "defaultValuesFilename": "appSync-rds-defaults.js", + "serviceWalkthroughFilename": "appSync-rds-walkthrough.js", + "cfnFilename": "appSync-rds-cloudformation-template-default.yml.ejs", + "provider": "awscloudformation", + "availableRegions": ["us-east-1", "us-east-2", "us-west-2", "ap-northeast-1", "eu-west-1"] + } } From 7dd4d0527763738217763aa004f0d5e4044ddb48 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Sat, 16 Nov 2019 14:27:36 -0800 Subject: [PATCH 252/587] chore: api walkthrough update (#2763) --- .../commands/api/update.js | 1 + packages/amplify-category-api/package.json | 1 + .../appSync-walkthrough.js | 318 +++++++++++++++--- .../sync-conflict-handler-index.js.ejs | 37 ++ .../sync-conflict-handler-package.json.ejs | 6 + .../sync-conflict-handler-template.json.ejs | 197 +++++++++++ 6 files changed, 517 insertions(+), 43 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index 4d27616a3a..7c31d07468 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -21,6 +21,7 @@ module.exports = { .then(() => context.print.success('Successfully updated resource')) .catch(err => { context.print.error(err.message); + console.log(err.stack); }); }, }; diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 737fa63142..d07ccf0bcc 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,6 +17,7 @@ "fs-extra": "^8.1.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "1.24.0", + "graphql-transformer-core": "5.18.0", "graphql-tag-pluck": "^0.8.4", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 941a8e5295..d9ee939192 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,7 +1,9 @@ const inquirer = require('inquirer'); const fs = require('fs-extra'); +const uuid = require('uuid'); const path = require('path'); const open = require('open'); +const TransformPackage = require('graphql-transformer-core'); const category = 'api'; const serviceName = 'AppSync'; @@ -12,6 +14,27 @@ const resolversDirName = 'resolvers'; const stacksDirName = 'stacks'; const defaultStackName = 'CustomResources.json'; +const { collectDirectivesByTypeNames, readTransformerConfiguration, writeTransformerConfiguration } = TransformPackage; + +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', + }, +]; + function openConsole(context) { const amplifyMeta = context.amplify.getProjectMeta(); const categoryAmplifyMeta = amplifyMeta[category]; @@ -35,6 +58,9 @@ function openConsole(context) { async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { const resourceName = resourceAlreadyExists(context); + let authConfig; + let defaultAuthType; + let resolverConfig; if (resourceName) { context.print.warning( @@ -73,9 +99,13 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat DynamoDBEnableServerSideEncryption: 'false', }; - // Ask auth/security questions + // Ask additonal questions - const authConfig = await askSecurityQuestions(context, parameters); + /* eslint-disable */ + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); + ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType)); + await checkForCognitoUserPools(context, parameters, authConfig); + /* eslint-disable */ // Ask schema file question @@ -213,6 +243,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, targetSchemaFilePath); + if (resolverConfig) { + await writeResolverConfig(context, resolverConfig, resourceDir); + } + if (editSchemaChoice) { return context.amplify.openEditor(context, targetSchemaFilePath).then(async () => { let notCompiled = true; @@ -250,10 +284,62 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } +async function writeResolverConfig(context, syncConfig, resourceDir) { + const localTransformerConfig = await readTransformerConfiguration(resourceDir); + localTransformerConfig.ResolverConfig = syncConfig; + await writeTransformerConfiguration(resourceDir, localTransformerConfig); +} + +async function createSyncFunction(context) { + const targetDir = context.amplify.pathManager.getBackendDirPath(); + const pluginDir = __dirname; + const [shortId] = uuid().split('-'); + + const functionName = `syncConflictHandler${shortId}`; + + const functionProps = { + functionName: `${functionName}`, + roleName: `${functionName}LambdaRole`, + }; + + const copyJobs = [ + { + dir: pluginDir, + template: '../sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs', + target: `${targetDir}/function/${functionName}/src/index.js`, + }, + { + dir: pluginDir, + template: '../sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs', + target: `${targetDir}/function/${functionName}/src/package.json`, + }, + { + dir: pluginDir, + template: '../sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs', + target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + await context.amplify.copyBatch(context, copyJobs, functionProps, true); + + const backendConfigs = { + service: 'Lambda', + providerPlugin: 'awscloudformation', + build: true, + }; + + await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); + context.print.success(`Successfully added ${functionName} function locally`); + + return functionName + '-${env}'; +} + async function updateWalkthrough(context) { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; + let authConfig, defaultAuthType, resolverConfig; const resources = allResources.filter(resource => resource.service === 'AppSync'); // There can only be one appsync resource @@ -284,7 +370,27 @@ async function updateWalkthrough(context) { context.print.info(e.stack); } - const authConfig = await askSecurityQuestions(context, parameters); + // Get models + + const project = await TransformPackage.readProjectConfiguration(resourceDir); + + // 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); + } + }); + } + + /* eslint-disable */ + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); + ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes)); + await checkForCognitoUserPools(context, parameters, authConfig); + /* eslint-disable */ const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); @@ -308,6 +414,10 @@ async function updateWalkthrough(context) { jsonString = JSON.stringify(backendConfig, null, '\t'); fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); + if (resolverConfig) { + await writeResolverConfig(context, resolverConfig, resourceDir); + } + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, parameters, @@ -315,43 +425,8 @@ async function updateWalkthrough(context) { }); } -async function askSecurityQuestions(context, parameters) { - 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 defaultAuthTypeQuestion = { - type: 'list', - name: 'authType', - message: 'Choose the default authorization type for the API', - choices: authProviderChoices, - }; - - const { authType } = await inquirer.prompt([defaultAuthTypeQuestion]); - - const authConfig = { - additionalAuthenticationProviders: [], - }; - - // Get default auth configured - const defaultAuth = await askAuthQuestions(authType, context); - - authConfig.defaultAuthentication = defaultAuth; +async function askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes) { + let resolverConfig; const advancedSettingsQuestion = { type: 'list', @@ -372,8 +447,162 @@ async function askSecurityQuestions(context, parameters) { const advancedSettingsAnswer = await inquirer.prompt([advancedSettingsQuestion]); if (advancedSettingsAnswer.advancedSettings) { + authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); + if (process.env.AMPLIFY_DATASTORE_SYNC === 'true') { + resolverConfig = await askResolverConflictQuestion(context, parameters, modelTypes); + } + } + + return { authConfig, resolverConfig }; +} + +async function askResolverConflictQuestion(context, parameters, modelTypes) { + let resolverConfig = {}; + + if (await context.prompt.confirm('Configure conflict detection?')) { + const askConflictResolutionStrategy = async msg => { + let conflictResolutionStrategy; + + do { + if (conflictResolutionStrategy === 'Learn More') { + // Todo: Update the help text + context.print.info(''); + context.print.info('DataStore help text'); + context.print.info(''); + } + + const conflictResolutionQuestion = { + type: 'list', + name: 'conflictResolutionStrategy', + message: msg, + default: 'AUTOMERGE', + choices: [ + { + name: 'Auto Merge', + value: 'AUTOMERGE', + }, + { + name: 'Optimistic Concurrency', + value: 'OPTIMISTIC_CONCURRENCY', + }, + { + name: 'Custom Lambda', + value: 'LAMBDA', + }, + { + name: 'Learn More', + value: 'Learn More', + }, + ], + }; + ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); + } while (conflictResolutionStrategy === 'Learn More'); + + let syncConfig = { + ConflictHandler: conflictResolutionStrategy, + ConflictDetection: 'VERSION', + }; + + if (conflictResolutionStrategy === 'LAMBDA') { + const lambdaFunctionName = await askSyncFunctionQuestion(context); + syncConfig.LambdaConflictHandler = {}; + syncConfig.LambdaConflictHandler.name = lambdaFunctionName; + } + + 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?')) { + 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 (let i = 0; i < selectedModelTypes.length; i += 1) { + resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( + `Select the resolution strategy for ${selectedModelTypes[i]} model` + ); + } + } + } + } + } + + return resolverConfig; +} + +async function askSyncFunctionQuestion(context) { + 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; + + if (syncLambdaAnswer === 'NEW') { + lambdaFunctionName = await createSyncFunction(context); + } else { + const syncLambdaNameQuestion = { + type: 'input', + name: 'lambdaFunctionName', + message: 'Enter lambda function name', + validate: val => !!val, + }; + ({ lambdaFunctionName } = await inquirer.prompt([syncLambdaNameQuestion])); + } + + return lambdaFunctionName; +} +async function askDefaultAuthQuestion(context, parameters) { + const defaultAuthTypeQuestion = { + type: 'list', + name: 'defaultAuthType', + message: 'Choose the default authorization type for the API', + choices: authProviderChoices, + }; + + const { defaultAuthType } = await inquirer.prompt([defaultAuthTypeQuestion]); + + const authConfig = { + additionalAuthenticationProviders: [], + }; + + // Get default auth configured + const defaultAuth = await askAuthQuestions(defaultAuthType, context); + + authConfig.defaultAuthentication = defaultAuth; + + return { authConfig, defaultAuthType }; +} + +async function askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType) { + if (await context.prompt.confirm('Configure additional auth types?')) { // Get additional auth configured - const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== authType); + const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType); const additionalProvidersQuestion = { type: 'checkbox', @@ -392,6 +621,11 @@ async function askSecurityQuestions(context, parameters) { authConfig.additionalAuthenticationProviders.push(config); } } + + return authConfig; +} + +async function checkForCognitoUserPools(context, parameters, authConfig) { const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter( provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS' ); @@ -417,8 +651,6 @@ async function askSecurityQuestions(context, parameters) { } else { delete parameters.AuthCognitoUserPoolId; } - - return authConfig; } async function askAuthQuestions(authType, context, printLeadText = false) { diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs new file mode 100644 index 0000000000..7034c711ce --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs @@ -0,0 +1,37 @@ +// 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/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs new file mode 100644 index 0000000000..084c06bc3d --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs @@ -0,0 +1,6 @@ +{ + "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/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs new file mode 100644 index 0000000000..169b9ec33a --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs @@ -0,0 +1,197 @@ +{ + "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": "nodejs10.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" + } + } + } +} From b5811d5ad01b8db0f5c75a8b69f6b9bf9009f006 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 20 Nov 2019 13:15:04 -0800 Subject: [PATCH 253/587] feat: conditions update (#2789) * feat: conditions update * fix: build * fix: missing scalar name override * fix: address PR comments * fix: reverted requested changes due to a bug in mock --- .../service-walkthroughs/appSync-walkthrough.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index d9ee939192..b86036aa5d 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -14,7 +14,12 @@ const resolversDirName = 'resolvers'; const stacksDirName = 'stacks'; const defaultStackName = 'CustomResources.json'; -const { collectDirectivesByTypeNames, readTransformerConfiguration, writeTransformerConfiguration } = TransformPackage; +const { + collectDirectivesByTypeNames, + readTransformerConfiguration, + writeTransformerConfiguration, + TRANSFORM_CURRENT_VERSION, +} = TransformPackage; const authProviderChoices = [ { @@ -137,6 +142,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.mkdirSync(stacksDirectoryPath); } + // During API add, make sure we're creating a transform.conf.json file with the latest version the CLI supports. + await updateTransformerConfigVersion(resourceDir); + // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); @@ -290,6 +298,12 @@ async function writeResolverConfig(context, syncConfig, resourceDir) { await writeTransformerConfiguration(resourceDir, localTransformerConfig); } +async function updateTransformerConfigVersion(resourceDir) { + const localTransformerConfig = await readTransformerConfiguration(resourceDir); + localTransformerConfig.Version = TRANSFORM_CURRENT_VERSION; + await writeTransformerConfiguration(resourceDir, localTransformerConfig); +} + async function createSyncFunction(context) { const targetDir = context.amplify.pathManager.getBackendDirPath(); const pluginDir = __dirname; From f8a60086157c1a5157f7186327048721fb7222fc Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Fri, 22 Nov 2019 16:46:14 -0800 Subject: [PATCH 254/587] feat(cli): cLI updates and new features for Amplify Console (#2742) * feat(cli): cLI updates and new features for Amplify Console * change amplify console command * dev * add migraiton check in attach workflow * dev * dev * allow pulling different env * update message printout * region map * update aws-sdk version * yarn * handle unsupported region of Amplify service * handle unsupported regions of Amplify service * yarn * dev * address PR review comments * text changes to address PR review comments --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d07ccf0bcc..dfed909797 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,7 +13,7 @@ "amplify-category-auth": "1.30.0", "amplify-category-function": "1.30.0", "amplify-category-storage": "1.31.0", - "aws-sdk": "^2.510.0", + "aws-sdk": "^2.577.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "1.24.0", From c96d1a492d137f14150ea4962b9b5090e9cbbc0b Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 25 Nov 2019 13:52:20 -0800 Subject: [PATCH 255/587] chore: 4.0 release (#2835) * chore: major release * chore(release): Publish [ci skip] - amplify-app@2.0.0 - amplify-appsync-simulator@1.0.0 - amplify-category-analytics@2.0.0 - amplify-category-api@2.0.0 - amplify-category-auth@2.0.0 - amplify-category-function@2.0.0 - amplify-category-hosting@2.0.0 - amplify-category-interactions@2.0.0 - amplify-category-notifications@2.0.0 - amplify-category-predictions@2.0.0 - amplify-category-storage@2.0.0 - amplify-category-xr@2.0.0 - @aws-amplify/cli@4.0.0 - amplify-codegen-appsync-model-plugin@1.0.0 - amplify-codegen@2.0.0 - amplify-dynamodb-simulator@1.0.0 - amplify-e2e-tests@2.0.0 - amplify-frontend-android@2.0.0 - amplify-frontend-ios@2.0.0 - amplify-frontend-javascript@2.0.0 - amplify-graphiql-explorer@1.0.0 - amplify-graphql-docs-generator@2.0.0 - amplify-graphql-types-generator@2.0.0 - amplify-provider-awscloudformation@4.0.0 - amplify-storage-simulator@1.0.0 - amplify-ui-tests@2.0.0 - amplify-util-mock@3.0.0 - amplify-velocity-template@1.0.0 - graphql-auth-transformer@6.0.0 - graphql-connection-transformer@4.0.0 - graphql-dynamodb-transformer@6.0.0 - graphql-elasticsearch-transformer@4.0.0 - graphql-function-transformer@2.0.0 - graphql-http-transformer@4.0.0 - graphql-key-transformer@2.0.0 - graphql-mapping-template@4.0.0 - graphql-predictions-transformer@2.0.0 - graphql-relational-schema-transformer@2.0.0 - graphql-transformer-common@4.0.0 - graphql-transformer-core@6.0.0 - graphql-transformers-e2e-tests@6.0.0 - graphql-versioned-transformer@4.0.0 * chore: change release back to minor --- packages/amplify-category-api/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index dfed909797..5235c909af 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "1.30.0", + "version": "2.0.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "1.30.0", - "amplify-category-function": "1.30.0", - "amplify-category-storage": "1.31.0", + "amplify-category-auth": "2.0.0", + "amplify-category-function": "2.0.0", + "amplify-category-storage": "2.0.0", "aws-sdk": "^2.577.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "1.24.0", - "graphql-transformer-core": "5.18.0", + "graphql-relational-schema-transformer": "2.0.0", "graphql-tag-pluck": "^0.8.4", + "graphql-transformer-core": "6.0.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 7e94b3cbccab907e78fc828c900502aef90c3807 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Mon, 25 Nov 2019 13:57:11 -0800 Subject: [PATCH 256/587] API Workflow Changes (#2804) * fix(cli): add default value for confirm fn in prompt * fix(graphql-auth-transformer): added additional check for models checking if models exists in the config before assesing if the model exists in the list * add default value to prompt * Update context-extensions.ts add a default value to confirm prompt * Update context-extensions.ts --- .../service-walkthroughs/appSync-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b86036aa5d..7cce12908d 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -531,7 +531,7 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { // 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?')) { + if (await context.prompt.confirm('Do you want to override default per model settings?', false)) { const modelTypeQuestion = { type: 'checkbox', name: 'selectedModelTypes', From 8054934c3a46d0e2b0b760e4d9e2a02e874b36e4 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 25 Nov 2019 15:09:24 -0800 Subject: [PATCH 257/587] Custom Transformer loading enhancement and fixes (#2814) * feat: enhance custom transformer loading * fix: lint fixes * fix: update snapshots * feat: enhance custom transformer loading * fix: lint fixes * fix: update snapshots * fix: yarn.lock update --- .../service-walkthroughs/apigw-walkthrough.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index c3f566e2b8..20bf538669 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -476,12 +476,14 @@ async function askPaths(context, answers, currentPath) { break; } - addAnotherPath = (await inquirer.prompt({ - name: 'anotherPath', - type: 'confirm', - message: 'Do you want to add another path?', - default: false, - })).anotherPath; + addAnotherPath = ( + await inquirer.prompt({ + name: 'anotherPath', + type: 'confirm', + message: 'Do you want to add another path?', + default: false, + }) + ).anotherPath; } while (addAnotherPath); const { dependsOn, functionArns } = await findDependsOn(paths, context); From 86cfff34fd5eee7b4a78e6667a6cc7d826ec79f6 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 27 Nov 2019 06:26:44 +0000 Subject: [PATCH 258/587] chore(release): Publish [ci skip] - amplify-app@2.1.0 - amplify-appsync-simulator@1.1.0 - amplify-category-analytics@2.1.0 - amplify-category-api@2.1.0 - amplify-category-auth@2.1.0 - amplify-category-function@2.1.0 - amplify-category-hosting@2.0.1 - amplify-category-interactions@2.0.1 - amplify-category-notifications@2.1.0 - amplify-category-predictions@2.0.1 - amplify-category-storage@2.0.1 - amplify-category-xr@2.0.1 - @aws-amplify/cli@4.1.0 - amplify-codegen-appsync-model-plugin@1.1.0 - amplify-codegen@2.1.0 - amplify-dynamodb-simulator@1.1.0 - amplify-e2e-tests@2.1.0 - amplify-frontend-android@2.1.0 - amplify-frontend-ios@2.1.0 - amplify-frontend-javascript@2.1.0 - amplify-graphiql-explorer@1.0.1 - amplify-graphql-docs-generator@2.0.1 - amplify-graphql-types-generator@2.0.1 - amplify-provider-awscloudformation@4.1.0 - amplify-storage-simulator@1.0.1 - amplify-ui-tests@2.1.0 - amplify-util-mock@3.1.0 - amplify-velocity-template@1.0.1 - graphql-auth-transformer@6.1.0 - graphql-connection-transformer@4.1.0 - graphql-dynamodb-transformer@6.1.0 - graphql-elasticsearch-transformer@4.0.1 - graphql-function-transformer@2.0.1 - graphql-http-transformer@4.1.0 - graphql-key-transformer@2.1.0 - graphql-mapping-template@4.1.0 - graphql-predictions-transformer@2.0.1 - graphql-relational-schema-transformer@2.1.0 - graphql-transformer-common@4.1.0 - graphql-transformer-core@6.1.0 - graphql-transformers-e2e-tests@6.1.0 - graphql-versioned-transformer@4.1.0 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f1cfb0607f..12bd4a609e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5235c909af..4ec84eae12 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.0.0", + "version": "2.1.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.0.0", - "amplify-category-function": "2.0.0", - "amplify-category-storage": "2.0.0", + "amplify-category-auth": "2.1.0", + "amplify-category-function": "2.1.0", + "amplify-category-storage": "2.0.1", "aws-sdk": "^2.577.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.0.0", + "graphql-relational-schema-transformer": "2.1.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.0.0", + "graphql-transformer-core": "6.1.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 965a63b916b0709493b34c608f697b7f02d2a688 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 27 Nov 2019 06:35:11 +0000 Subject: [PATCH 259/587] chore(release): Publish [ci skip] - amplify-app@2.1.1 - amplify-appsync-simulator@1.1.1 - amplify-category-analytics@2.1.1 - amplify-category-api@2.1.1 - amplify-category-auth@2.1.1 - amplify-category-function@2.1.1 - amplify-category-hosting@2.0.2 - amplify-category-interactions@2.0.2 - amplify-category-notifications@2.1.1 - amplify-category-predictions@2.0.2 - amplify-category-storage@2.0.2 - amplify-category-xr@2.0.2 - @aws-amplify/cli@4.1.1 - amplify-codegen-appsync-model-plugin@1.1.1 - amplify-codegen@2.1.1 - amplify-dynamodb-simulator@1.1.1 - amplify-e2e-tests@2.1.1 - amplify-frontend-android@2.1.1 - amplify-frontend-ios@2.1.1 - amplify-frontend-javascript@2.1.1 - amplify-graphiql-explorer@1.0.2 - amplify-graphql-docs-generator@2.0.2 - amplify-graphql-types-generator@2.0.2 - amplify-provider-awscloudformation@4.1.1 - amplify-storage-simulator@1.0.2 - amplify-ui-tests@2.1.1 - amplify-util-mock@3.1.1 - amplify-velocity-template@1.0.2 - graphql-auth-transformer@6.1.1 - graphql-connection-transformer@4.1.1 - graphql-dynamodb-transformer@6.1.1 - graphql-elasticsearch-transformer@4.0.2 - graphql-function-transformer@2.0.2 - graphql-http-transformer@4.1.1 - graphql-key-transformer@2.1.1 - graphql-mapping-template@4.1.1 - graphql-predictions-transformer@2.0.2 - graphql-relational-schema-transformer@2.1.1 - graphql-transformer-common@4.1.1 - graphql-transformer-core@6.1.1 - graphql-transformers-e2e-tests@6.1.1 - graphql-versioned-transformer@4.1.1 --- packages/amplify-category-api/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4ec84eae12..b80097ed70 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.1.0", + "version": "2.1.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.1.0", - "amplify-category-function": "2.1.0", - "amplify-category-storage": "2.0.1", + "amplify-category-auth": "2.1.1", + "amplify-category-function": "2.1.1", + "amplify-category-storage": "2.0.2", "aws-sdk": "^2.577.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.1.0", + "graphql-relational-schema-transformer": "2.1.1", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.1.0", + "graphql-transformer-core": "6.1.1", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 010ef59b5ffd72d89d17c68cb33f861823c08f35 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 27 Nov 2019 10:19:54 -0800 Subject: [PATCH 260/587] chore: cloudform update, typescript version lock (#2816) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b80097ed70..681abc1c6d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,7 +13,7 @@ "amplify-category-auth": "2.1.1", "amplify-category-function": "2.1.1", "amplify-category-storage": "2.0.2", - "aws-sdk": "^2.577.0", + "aws-sdk": "^2.580.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", "graphql-relational-schema-transformer": "2.1.1", From ab15c3d8a18fe2be9591d5d6b07e82e9bbc97480 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Wed, 27 Nov 2019 17:36:03 -0800 Subject: [PATCH 261/587] Release merge (#2874) --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 12bd4a609e..18d27ffdbd 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 681abc1c6d..8359c4b0d6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.1.1", + "version": "2.2.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.1.1", - "amplify-category-function": "2.1.1", - "amplify-category-storage": "2.0.2", + "amplify-category-auth": "2.2.0", + "amplify-category-function": "2.2.0", + "amplify-category-storage": "2.0.3", "aws-sdk": "^2.580.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.1.1", + "graphql-relational-schema-transformer": "2.2.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.1.1", + "graphql-transformer-core": "6.2.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 069721c47272890884725b03eb700b7d7ddabbc7 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Sun, 1 Dec 2019 17:15:03 -0800 Subject: [PATCH 262/587] chore(release): Publish [ci skip] (#2896) - amplify-app@2.3.0 - amplify-appsync-simulator@1.3.0 - amplify-category-analytics@2.3.0 - amplify-category-api@2.3.0 - amplify-category-auth@2.3.0 - amplify-category-function@2.3.0 - amplify-category-hosting@2.0.4 - amplify-category-interactions@2.0.4 - amplify-category-notifications@2.3.0 - amplify-category-predictions@2.0.4 - amplify-category-storage@2.0.4 - amplify-category-xr@2.0.4 - @aws-amplify/cli@4.3.0 - amplify-codegen-appsync-model-plugin@1.3.0 - amplify-codegen@2.3.0 - amplify-dynamodb-simulator@1.3.0 - amplify-e2e-tests@2.3.0 - amplify-frontend-android@2.3.0 - amplify-frontend-ios@2.3.0 - amplify-frontend-javascript@2.3.0 - amplify-graphiql-explorer@1.0.4 - amplify-graphql-docs-generator@2.0.4 - amplify-graphql-types-generator@2.0.4 - amplify-provider-awscloudformation@4.3.0 - amplify-storage-simulator@1.0.4 - amplify-ui-tests@2.3.0 - amplify-util-mock@3.3.0 - amplify-velocity-template@1.0.4 - graphql-auth-transformer@6.3.0 - graphql-connection-transformer@4.3.0 - graphql-dynamodb-transformer@6.3.0 - graphql-elasticsearch-transformer@4.0.4 - graphql-function-transformer@2.0.4 - graphql-http-transformer@4.3.0 - graphql-key-transformer@2.3.0 - graphql-mapping-template@4.3.0 - graphql-predictions-transformer@2.0.4 - graphql-relational-schema-transformer@2.3.0 - graphql-transformer-common@4.3.0 - graphql-transformer-core@6.3.0 - graphql-transformers-e2e-tests@6.3.0 - graphql-versioned-transformer@4.3.0 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 18d27ffdbd..7e7731bb70 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8359c4b0d6..59f27ad112 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.2.0", + "version": "2.3.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,15 +10,15 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.2.0", - "amplify-category-function": "2.2.0", - "amplify-category-storage": "2.0.3", + "amplify-category-auth": "2.3.0", + "amplify-category-function": "2.3.0", + "amplify-category-storage": "2.0.4", "aws-sdk": "^2.580.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.2.0", + "graphql-relational-schema-transformer": "2.3.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.2.0", + "graphql-transformer-core": "6.3.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 00916c4d83512eb26f2ff2fcba4732e35e17c206 Mon Sep 17 00:00:00 2001 From: SwaySway Date: Mon, 2 Dec 2019 22:31:41 -0800 Subject: [PATCH 263/587] docs(amplify-category-api): added datastore learnmore added learn more description for Amplify DataStore --- packages/amplify-category-api/package.json | 1 + .../appSync-walkthrough.js | 12 +++++------ .../syncAssets.js | 20 +++++++++++++++++++ 3 files changed, 26 insertions(+), 7 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 59f27ad112..ae224dd583 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,6 +13,7 @@ "amplify-category-auth": "2.3.0", "amplify-category-function": "2.3.0", "amplify-category-storage": "2.0.4", + "chalk": "^2.4.2", "aws-sdk": "^2.580.0", "fs-extra": "^8.1.0", "graphql": "^0.13.2", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 7cce12908d..9216e99f87 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,3 +1,5 @@ +import { getDataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; + const inquirer = require('inquirer'); const fs = require('fs-extra'); const uuid = require('uuid'); @@ -478,13 +480,6 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { let conflictResolutionStrategy; do { - if (conflictResolutionStrategy === 'Learn More') { - // Todo: Update the help text - context.print.info(''); - context.print.info('DataStore help text'); - context.print.info(''); - } - const conflictResolutionQuestion = { type: 'list', name: 'conflictResolutionStrategy', @@ -509,6 +504,9 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { }, ], }; + if (conflictResolutionStrategy === 'Learn More') { + conflictResolutionQuestion.prefix = getDataStoreLearnMore(); + } ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js new file mode 100644 index 0000000000..f8824853f9 --- /dev/null +++ b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js @@ -0,0 +1,20 @@ +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 function getDataStoreLearnMore() { + return chalk.green(learnMore); +} + +export default {}; From b68514e466a43c3cd44daa1fb7b21c879727f77f Mon Sep 17 00:00:00 2001 From: SwaySway Date: Mon, 2 Dec 2019 22:35:52 -0800 Subject: [PATCH 264/587] remove ds env var check and update e2e api test --- .../service-walkthroughs/appSync-walkthrough.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 9216e99f87..8fb5b37be2 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -464,9 +464,7 @@ async function askAdditionalQuestions(context, parameters, authConfig, defaultAu if (advancedSettingsAnswer.advancedSettings) { authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); - if (process.env.AMPLIFY_DATASTORE_SYNC === 'true') { - resolverConfig = await askResolverConflictQuestion(context, parameters, modelTypes); - } + resolverConfig = await askResolverConflictQuestion(context, parameters, modelTypes); } return { authConfig, resolverConfig }; From 0cfed5037f632f9eaa68b847e7e9ee56ba64b63e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 3 Dec 2019 19:54:24 +0000 Subject: [PATCH 265/587] chore(release): Publish [ci skip] - amplify-app@2.4.0 - amplify-appsync-simulator@1.4.0 - amplify-category-analytics@2.4.0 - amplify-category-api@2.4.0 - amplify-category-auth@2.4.0 - amplify-category-function@2.4.0 - amplify-category-hosting@2.0.5 - amplify-category-interactions@2.0.5 - amplify-category-notifications@2.4.0 - amplify-category-predictions@2.0.5 - amplify-category-storage@2.0.5 - amplify-category-xr@2.0.5 - @aws-amplify/cli@4.4.0 - amplify-codegen-appsync-model-plugin@1.4.0 - amplify-codegen@2.4.0 - amplify-dynamodb-simulator@1.4.0 - amplify-e2e-tests@2.4.0 - amplify-frontend-android@2.4.0 - amplify-frontend-ios@2.4.0 - amplify-frontend-javascript@2.4.0 - amplify-graphiql-explorer@1.0.5 - amplify-graphql-docs-generator@2.0.5 - amplify-graphql-types-generator@2.0.5 - amplify-provider-awscloudformation@4.4.0 - amplify-storage-simulator@1.0.5 - amplify-ui-tests@2.4.0 - amplify-util-mock@3.4.0 - amplify-velocity-template@1.0.5 - graphql-auth-transformer@6.4.0 - graphql-connection-transformer@4.4.0 - graphql-dynamodb-transformer@6.4.0 - graphql-elasticsearch-transformer@4.0.5 - graphql-function-transformer@2.0.5 - graphql-http-transformer@4.4.0 - graphql-key-transformer@2.4.0 - graphql-mapping-template@4.4.0 - graphql-predictions-transformer@2.0.5 - graphql-relational-schema-transformer@2.4.0 - graphql-transformer-common@4.4.0 - graphql-transformer-core@6.4.0 - graphql-transformers-e2e-tests@6.4.0 - graphql-versioned-transformer@4.4.0 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 14 +++++++------- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7e7731bb70..7230ffc8e5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ae224dd583..667b74cf88 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.3.0", + "version": "2.4.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.3.0", - "amplify-category-function": "2.3.0", - "amplify-category-storage": "2.0.4", - "chalk": "^2.4.2", + "amplify-category-auth": "2.4.0", + "amplify-category-function": "2.4.0", + "amplify-category-storage": "2.0.5", "aws-sdk": "^2.580.0", + "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.3.0", + "graphql-relational-schema-transformer": "2.4.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.3.0", + "graphql-transformer-core": "6.4.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From cc0e428f8aeec73d47dce2b4c8cf32c1cc5bdbc7 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Mon, 9 Dec 2019 10:25:59 -0800 Subject: [PATCH 266/587] fix(amplify-category-api): fix conflict resolution learn more (#2954) --- .../service-walkthroughs/appSync-walkthrough.js | 5 ++--- .../sync-conflict-handler-assets/syncAssets.js | 6 ++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 8fb5b37be2..bc28d693d7 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -1,5 +1,4 @@ -import { getDataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; - +const syncAssets = require('../sync-conflict-handler-assets/syncAssets'); const inquirer = require('inquirer'); const fs = require('fs-extra'); const uuid = require('uuid'); @@ -503,7 +502,7 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { ], }; if (conflictResolutionStrategy === 'Learn More') { - conflictResolutionQuestion.prefix = getDataStoreLearnMore(); + conflictResolutionQuestion.prefix = syncAssets.getDataStoreLearnMore(); } ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js index f8824853f9..54ccc059cd 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js @@ -13,8 +13,10 @@ Other writers are rejected and must handle merges through other means, such as a 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 function getDataStoreLearnMore() { +function getDataStoreLearnMore() { return chalk.green(learnMore); } -export default {}; +module.exports = { + getDataStoreLearnMore, +}; From 4660768a9fd6dc99f7e907765bec1a2e236f39ec Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Mon, 9 Dec 2019 19:58:12 -0800 Subject: [PATCH 267/587] chore: manually bumping up minor versions (#2960) --- packages/amplify-category-api/package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 667b74cf88..f2bf4b8642 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.4.0", + "version": "2.5.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.4.0", - "amplify-category-function": "2.4.0", - "amplify-category-storage": "2.0.5", + "amplify-category-auth": "^2.5.0", + "amplify-category-function": "^2.5.0", + "amplify-category-storage": "^2.1.0", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.4.0", + "graphql-relational-schema-transformer": "^2.5.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.4.0", + "graphql-transformer-core": "^6.5.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 5fbee50866a888008a9b7fc21f34d6d0f100ed42 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Tue, 10 Dec 2019 12:31:21 -0800 Subject: [PATCH 268/587] chore(release): Publish [ci skip] (#2968) - amplify-app@2.6.0 - amplify-appsync-simulator@1.6.0 - amplify-category-analytics@2.6.0 - amplify-category-api@2.6.0 - amplify-category-auth@2.6.0 - amplify-category-function@2.6.0 - amplify-category-hosting@2.1.1 - amplify-category-interactions@2.1.1 - amplify-category-notifications@2.6.0 - amplify-category-predictions@2.1.1 - amplify-category-storage@2.1.1 - amplify-category-xr@2.1.1 - @aws-amplify/cli@4.6.0 - amplify-codegen-appsync-model-plugin@1.6.0 - amplify-codegen@2.6.0 - amplify-dynamodb-simulator@1.6.0 - amplify-e2e-tests@2.6.0 - amplify-frontend-android@2.6.0 - amplify-frontend-ios@2.6.0 - amplify-frontend-javascript@2.6.0 - amplify-graphiql-explorer@1.1.1 - amplify-graphql-docs-generator@2.1.1 - amplify-graphql-types-generator@2.1.1 - amplify-provider-awscloudformation@4.6.0 - amplify-storage-simulator@1.1.1 - amplify-ui-tests@2.6.0 - amplify-util-mock@3.6.0 - amplify-velocity-template@1.1.1 - graphql-auth-transformer@6.6.0 - graphql-connection-transformer@4.6.0 - graphql-dynamodb-transformer@6.6.0 - graphql-elasticsearch-transformer@4.1.1 - graphql-function-transformer@2.1.1 - graphql-http-transformer@4.6.0 - graphql-key-transformer@2.6.0 - graphql-mapping-template@4.6.0 - graphql-predictions-transformer@2.1.1 - graphql-relational-schema-transformer@2.6.0 - graphql-transformer-common@4.6.0 - graphql-transformer-core@6.6.0 - graphql-transformers-e2e-tests@6.6.0 - graphql-versioned-transformer@4.6.0 --- packages/amplify-category-api/CHANGELOG.md | 18 ++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7230ffc8e5..aa1ad0d804 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f2bf4b8642..ba3f6ee447 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.5.0", + "version": "2.6.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "^2.5.0", - "amplify-category-function": "^2.5.0", - "amplify-category-storage": "^2.1.0", + "amplify-category-auth": "2.6.0", + "amplify-category-function": "2.6.0", + "amplify-category-storage": "2.1.1", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "^2.5.0", + "graphql-relational-schema-transformer": "2.6.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "^6.5.0", + "graphql-transformer-core": "6.6.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 085d96f0f3e6a363445735e0337eea2b96624b45 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Wed, 18 Dec 2019 15:00:57 -0800 Subject: [PATCH 269/587] resolver config workflow change + e2e tests (#3017) * fix(amplify-category-api): fix resolver config in add api workflow resolver config was not being added in the add workflow for api and made sure to add if project or models config exists --- .../service-walkthroughs/appSync-walkthrough.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index bc28d693d7..f83af7870e 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -146,6 +146,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // During API add, make sure we're creating a transform.conf.json file with the latest version the CLI supports. await updateTransformerConfigVersion(resourceDir); + if (resolverConfig.project || resolverConfig.models) { + await writeResolverConfig(context, resolverConfig, resourceDir); + } + // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); @@ -429,7 +433,7 @@ async function updateWalkthrough(context) { jsonString = JSON.stringify(backendConfig, null, '\t'); fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); - if (resolverConfig) { + if (resolverConfig.project || resolverConfig.models) { await writeResolverConfig(context, resolverConfig, resourceDir); } From 22e6e9b78e6e47b6bed7070002e1d082a290dae4 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Thu, 19 Dec 2019 17:54:17 -0800 Subject: [PATCH 270/587] fix(amplify-category-api): add config check in writeResolverConfig * fix(amplify-category-api): add config check in writeResolverConfig if resolver config exists and it either has syncconfig for a project for model(s) then write it to the transform conf --- .../appSync-walkthrough.js | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index f83af7870e..f45901cd7b 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -146,9 +146,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // During API add, make sure we're creating a transform.conf.json file with the latest version the CLI supports. await updateTransformerConfigVersion(resourceDir); - if (resolverConfig.project || resolverConfig.models) { - await writeResolverConfig(context, resolverConfig, resourceDir); - } + await writeResolverConfig(resolverConfig, resourceDir); // Write the default custom resources stack out to disk. const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); @@ -256,10 +254,6 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat fs.copyFileSync(schemaFilePath, targetSchemaFilePath); - if (resolverConfig) { - await writeResolverConfig(context, resolverConfig, resourceDir); - } - if (editSchemaChoice) { return context.amplify.openEditor(context, targetSchemaFilePath).then(async () => { let notCompiled = true; @@ -296,11 +290,13 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; } - -async function writeResolverConfig(context, syncConfig, resourceDir) { - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - localTransformerConfig.ResolverConfig = syncConfig; - await writeTransformerConfiguration(resourceDir, localTransformerConfig); +// write to the transformer conf if the resolverConfig is valid +async function writeResolverConfig(resolverConfig, resourceDir) { + if (resolverConfig && (resolverConfig.project || resolverConfig.models)) { + const localTransformerConfig = await readTransformerConfiguration(resourceDir); + localTransformerConfig.ResolverConfig = resolverConfig; + await writeTransformerConfiguration(resourceDir, localTransformerConfig); + } } async function updateTransformerConfigVersion(resourceDir) { @@ -433,9 +429,7 @@ async function updateWalkthrough(context) { jsonString = JSON.stringify(backendConfig, null, '\t'); fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); - if (resolverConfig.project || resolverConfig.models) { - await writeResolverConfig(context, resolverConfig, resourceDir); - } + await writeResolverConfig(resolverConfig, resourceDir); await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, From 217795da1630e220c740b6404c205c8a9a75f82b Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 20 Dec 2019 14:36:24 -0800 Subject: [PATCH 271/587] chore(release): Publish [ci skip] (#3051) - amplify-app@2.7.0 - amplify-appsync-simulator@1.7.0 - amplify-category-analytics@2.7.0 - amplify-category-api@2.7.0 - amplify-category-auth@2.7.0 - amplify-category-function@2.7.0 - amplify-category-hosting@2.1.2 - amplify-category-interactions@2.1.2 - amplify-category-notifications@2.7.0 - amplify-category-predictions@2.1.2 - amplify-category-storage@2.1.2 - amplify-category-xr@2.1.2 - @aws-amplify/cli@4.7.0 - amplify-codegen-appsync-model-plugin@1.7.0 - amplify-codegen@2.7.0 - amplify-dynamodb-simulator@1.7.0 - amplify-e2e-tests@2.7.0 - amplify-frontend-android@2.7.0 - amplify-frontend-ios@2.7.0 - amplify-frontend-javascript@2.7.0 - amplify-graphiql-explorer@1.1.2 - amplify-graphql-docs-generator@2.1.2 - amplify-graphql-types-generator@2.1.2 - amplify-provider-awscloudformation@4.7.0 - amplify-storage-simulator@1.1.2 - amplify-ui-tests@2.7.0 - amplify-util-mock@3.7.0 - amplify-velocity-template@1.1.2 - graphql-auth-transformer@6.7.0 - graphql-connection-transformer@4.7.0 - graphql-dynamodb-transformer@6.7.0 - graphql-elasticsearch-transformer@4.1.2 - graphql-function-transformer@2.1.2 - graphql-http-transformer@4.7.0 - graphql-key-transformer@2.7.0 - graphql-mapping-template@4.7.0 - graphql-predictions-transformer@2.1.2 - graphql-relational-schema-transformer@2.7.0 - graphql-transformer-common@4.7.0 - graphql-transformer-core@6.7.0 - graphql-transformers-e2e-tests@6.7.0 - graphql-versioned-transformer@4.7.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index aa1ad0d804..17c2105645 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ba3f6ee447..64810d69f3 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.6.0", + "version": "2.7.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.6.0", - "amplify-category-function": "2.6.0", - "amplify-category-storage": "2.1.1", + "amplify-category-auth": "2.7.0", + "amplify-category-function": "2.7.0", + "amplify-category-storage": "2.1.2", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.6.0", + "graphql-relational-schema-transformer": "2.7.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.6.0", + "graphql-transformer-core": "6.7.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 7819499fff8e62370b30d15425380043f715a209 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Thu, 26 Dec 2019 10:07:56 -0800 Subject: [PATCH 272/587] chore: v4.8 release - amplify-app@2.8.0 - amplify-appsync-simulator@1.8.0 - amplify-category-analytics@2.8.0 - amplify-category-api@2.8.0 - amplify-category-auth@2.8.0 - amplify-category-function@2.8.0 - amplify-category-hosting@2.1.3 - amplify-category-interactions@2.1.3 - amplify-category-notifications@2.8.0 - amplify-category-predictions@2.1.3 - amplify-category-storage@2.1.3 - amplify-category-xr@2.1.3 - @aws-amplify/cli@4.8.0 - amplify-codegen-appsync-model-plugin@1.8.0 - amplify-codegen@2.8.0 - amplify-dynamodb-simulator@1.8.0 - amplify-e2e-tests@2.8.0 - amplify-frontend-android@2.8.0 - amplify-frontend-ios@2.8.0 - amplify-frontend-javascript@2.8.0 - amplify-graphiql-explorer@1.1.3 - amplify-graphql-docs-generator@2.1.3 - amplify-graphql-types-generator@2.1.3 - amplify-provider-awscloudformation@4.8.0 - amplify-storage-simulator@1.1.3 - amplify-ui-tests@2.8.0 - amplify-util-mock@3.8.0 - amplify-velocity-template@1.1.3 - graphql-auth-transformer@6.8.0 - graphql-connection-transformer@4.8.0 - graphql-dynamodb-transformer@6.8.0 - graphql-elasticsearch-transformer@4.1.3 - graphql-function-transformer@2.1.3 - graphql-http-transformer@4.8.0 - graphql-key-transformer@2.8.0 - graphql-mapping-template@4.8.0 - graphql-predictions-transformer@2.1.3 - graphql-relational-schema-transformer@2.8.0 - graphql-transformer-common@4.8.0 - graphql-transformer-core@6.8.0 - graphql-transformers-e2e-tests@6.8.0 - graphql-versioned-transformer@4.8.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 17c2105645..6634091dd3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 64810d69f3..2298d3c746 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.7.0", + "version": "2.8.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.7.0", - "amplify-category-function": "2.7.0", - "amplify-category-storage": "2.1.2", + "amplify-category-auth": "2.8.0", + "amplify-category-function": "2.8.0", + "amplify-category-storage": "2.1.3", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.7.0", + "graphql-relational-schema-transformer": "2.8.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.7.0", + "graphql-transformer-core": "6.8.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From b3a883dca5e3546ed2542c8840b6a78ed7877f47 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 27 Dec 2019 15:14:58 -0800 Subject: [PATCH 273/587] chore: release v4.9 - amplify-app@2.9.0 - amplify-appsync-simulator@1.9.0 - amplify-category-analytics@2.9.0 - amplify-category-api@2.9.0 - amplify-category-auth@2.9.0 - amplify-category-function@2.9.0 - amplify-category-hosting@2.1.4 - amplify-category-interactions@2.1.4 - amplify-category-notifications@2.9.0 - amplify-category-predictions@2.1.4 - amplify-category-storage@2.1.4 - amplify-category-xr@2.1.4 - @aws-amplify/cli@4.9.0 - amplify-codegen-appsync-model-plugin@1.9.0 - amplify-codegen@2.9.0 - amplify-dynamodb-simulator@1.9.0 - amplify-e2e-tests@2.9.0 - amplify-frontend-android@2.9.0 - amplify-frontend-ios@2.9.0 - amplify-frontend-javascript@2.9.0 - amplify-graphiql-explorer@1.1.4 - amplify-graphql-docs-generator@2.1.4 - amplify-graphql-types-generator@2.1.4 - amplify-provider-awscloudformation@4.9.0 - amplify-storage-simulator@1.1.4 - amplify-ui-tests@2.9.0 - amplify-util-mock@3.9.0 - amplify-velocity-template@1.1.4 - graphql-auth-transformer@6.9.0 - graphql-connection-transformer@4.9.0 - graphql-dynamodb-transformer@6.9.0 - graphql-elasticsearch-transformer@4.1.4 - graphql-function-transformer@2.1.4 - graphql-http-transformer@4.9.0 - graphql-key-transformer@2.9.0 - graphql-mapping-template@4.9.0 - graphql-predictions-transformer@2.1.4 - graphql-relational-schema-transformer@2.9.0 - graphql-transformer-common@4.9.0 - graphql-transformer-core@6.9.0 - graphql-transformers-e2e-tests@6.9.0 - graphql-versioned-transformer@4.9.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6634091dd3..9b3dea222b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 2298d3c746..d9206fa985 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.8.0", + "version": "2.9.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.8.0", - "amplify-category-function": "2.8.0", - "amplify-category-storage": "2.1.3", + "amplify-category-auth": "2.9.0", + "amplify-category-function": "2.9.0", + "amplify-category-storage": "2.1.4", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.8.0", + "graphql-relational-schema-transformer": "2.9.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.8.0", + "graphql-transformer-core": "6.9.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 2ae06486ec75fc70eff834f85f446d26ee5ac9d3 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 27 Dec 2019 17:17:50 -0800 Subject: [PATCH 274/587] chore(release): Publish [ci skip] (#3090) - amplify-app@2.10.0 - amplify-appsync-simulator@1.10.0 - amplify-category-analytics@2.10.0 - amplify-category-api@2.10.0 - amplify-category-auth@2.10.0 - amplify-category-function@2.10.0 - amplify-category-hosting@2.1.5 - amplify-category-interactions@2.1.5 - amplify-category-notifications@2.10.0 - amplify-category-predictions@2.1.5 - amplify-category-storage@2.1.5 - amplify-category-xr@2.1.5 - @aws-amplify/cli@4.10.0 - amplify-codegen-appsync-model-plugin@1.10.0 - amplify-codegen@2.10.0 - amplify-dynamodb-simulator@1.10.0 - amplify-e2e-tests@2.10.0 - amplify-frontend-android@2.10.0 - amplify-frontend-ios@2.10.0 - amplify-frontend-javascript@2.10.0 - amplify-graphiql-explorer@1.1.5 - amplify-graphql-docs-generator@2.1.5 - amplify-graphql-types-generator@2.1.5 - amplify-provider-awscloudformation@4.10.0 - amplify-storage-simulator@1.1.5 - amplify-ui-tests@2.10.0 - amplify-util-mock@3.10.0 - amplify-velocity-template@1.1.5 - graphql-auth-transformer@6.10.0 - graphql-connection-transformer@4.10.0 - graphql-dynamodb-transformer@6.10.0 - graphql-elasticsearch-transformer@4.1.5 - graphql-function-transformer@2.1.5 - graphql-http-transformer@4.10.0 - graphql-key-transformer@2.10.0 - graphql-mapping-template@4.10.0 - graphql-predictions-transformer@2.1.5 - graphql-relational-schema-transformer@2.10.0 - graphql-transformer-common@4.10.0 - graphql-transformer-core@6.10.0 - graphql-transformers-e2e-tests@6.10.0 - graphql-versioned-transformer@4.10.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9b3dea222b..ff1b0727ca 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d9206fa985..caf695aa37 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.9.0", + "version": "2.10.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.9.0", - "amplify-category-function": "2.9.0", - "amplify-category-storage": "2.1.4", + "amplify-category-auth": "2.10.0", + "amplify-category-function": "2.10.0", + "amplify-category-storage": "2.1.5", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.9.0", + "graphql-relational-schema-transformer": "2.10.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.9.0", + "graphql-transformer-core": "6.10.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From f297a14c4854ae9eb13b46b802ce97769e2bf1f8 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Tue, 31 Dec 2019 12:34:21 -0800 Subject: [PATCH 275/587] chore(release): Publish [ci skip] (#3103) - amplify-app@2.11.0 - amplify-appsync-simulator@1.11.0 - amplify-category-analytics@2.11.0 - amplify-category-api@2.11.0 - amplify-category-auth@2.11.0 - amplify-category-function@2.11.0 - amplify-category-hosting@2.1.6 - amplify-category-interactions@2.1.6 - amplify-category-notifications@2.11.0 - amplify-category-predictions@2.1.6 - amplify-category-storage@2.1.6 - amplify-category-xr@2.1.6 - @aws-amplify/cli@4.11.0 - amplify-codegen-appsync-model-plugin@1.11.0 - amplify-codegen@2.11.0 - amplify-dynamodb-simulator@1.11.0 - amplify-e2e-tests@2.11.0 - amplify-frontend-android@2.11.0 - amplify-frontend-ios@2.11.0 - amplify-frontend-javascript@2.11.0 - amplify-graphiql-explorer@1.1.6 - amplify-graphql-docs-generator@2.1.6 - amplify-graphql-types-generator@2.1.6 - amplify-provider-awscloudformation@4.11.0 - amplify-storage-simulator@1.1.6 - amplify-ui-tests@2.11.0 - amplify-util-mock@3.11.0 - amplify-velocity-template@1.1.6 - graphql-auth-transformer@6.11.0 - graphql-connection-transformer@4.11.0 - graphql-dynamodb-transformer@6.11.0 - graphql-elasticsearch-transformer@4.1.6 - graphql-function-transformer@2.1.6 - graphql-http-transformer@4.11.0 - graphql-key-transformer@2.11.0 - graphql-mapping-template@4.11.0 - graphql-predictions-transformer@2.1.6 - graphql-relational-schema-transformer@2.11.0 - graphql-transformer-common@4.11.0 - graphql-transformer-core@6.11.0 - graphql-transformers-e2e-tests@6.11.0 - graphql-versioned-transformer@4.11.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ff1b0727ca..2e34b8faf5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index caf695aa37..db35efeeaa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.10.0", + "version": "2.11.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.10.0", - "amplify-category-function": "2.10.0", - "amplify-category-storage": "2.1.5", + "amplify-category-auth": "2.11.0", + "amplify-category-function": "2.11.0", + "amplify-category-storage": "2.1.6", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.10.0", + "graphql-relational-schema-transformer": "2.11.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.10.0", + "graphql-transformer-core": "6.11.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 60aeabc330c420569692ed7a0243de1e78df863b Mon Sep 17 00:00:00 2001 From: ammarkarachi <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 9 Jan 2020 16:06:53 -0800 Subject: [PATCH 276/587] chore(release): Publish [ci skip] (#3156) - amplify-app@2.12.0 - amplify-appsync-simulator@1.12.0 - amplify-category-analytics@2.12.0 - amplify-category-api@2.12.0 - amplify-category-auth@2.12.0 - amplify-category-function@2.12.0 - amplify-category-hosting@2.1.7 - amplify-category-interactions@2.1.7 - amplify-category-notifications@2.12.0 - amplify-category-predictions@2.1.7 - amplify-category-storage@2.1.7 - amplify-category-xr@2.1.7 - @aws-amplify/cli@4.12.0 - amplify-codegen-appsync-model-plugin@1.12.0 - amplify-codegen@2.12.0 - amplify-dynamodb-simulator@1.12.0 - amplify-e2e-tests@2.12.0 - amplify-frontend-android@2.12.0 - amplify-frontend-ios@2.12.0 - amplify-frontend-javascript@2.12.0 - amplify-graphiql-explorer@1.1.7 - amplify-graphql-docs-generator@2.1.7 - amplify-graphql-types-generator@2.1.7 - amplify-provider-awscloudformation@4.12.0 - amplify-storage-simulator@1.1.7 - amplify-ui-tests@2.12.0 - amplify-util-mock@3.12.0 - amplify-velocity-template@1.1.7 - graphql-auth-transformer@6.12.0 - graphql-connection-transformer@4.12.0 - graphql-dynamodb-transformer@6.12.0 - graphql-elasticsearch-transformer@4.2.0 - graphql-function-transformer@2.1.7 - graphql-http-transformer@4.12.0 - graphql-key-transformer@2.12.0 - graphql-mapping-template@4.12.0 - graphql-predictions-transformer@2.1.7 - graphql-relational-schema-transformer@2.12.0 - graphql-transformer-common@4.12.0 - graphql-transformer-core@6.12.0 - graphql-transformers-e2e-tests@6.12.0 - graphql-versioned-transformer@4.12.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2e34b8faf5..9fc29a6975 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index db35efeeaa..e8d649d41a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.11.0", + "version": "2.12.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", @@ -10,16 +10,16 @@ "lint-fix": "eslint . --fix" }, "dependencies": { - "amplify-category-auth": "2.11.0", - "amplify-category-function": "2.11.0", - "amplify-category-storage": "2.1.6", + "amplify-category-auth": "2.12.0", + "amplify-category-function": "2.12.0", + "amplify-category-storage": "2.1.7", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^0.13.2", - "graphql-relational-schema-transformer": "2.11.0", + "graphql-relational-schema-transformer": "2.12.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.11.0", + "graphql-transformer-core": "6.12.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From e8f73d02fe6269e83ac1e19a7ca36e17d19bfde6 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 13 Jan 2020 11:15:19 -0800 Subject: [PATCH 277/587] chore: update to latest graphql.js package (#3150) * fix: update graphqljs to latest version * fix: add back repeatable that was removed somehow * fix: add back repeatable that was removed somehow --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e8d649d41a..e69e627d5a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -16,7 +16,7 @@ "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", - "graphql": "^0.13.2", + "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.12.0", "graphql-tag-pluck": "^0.8.4", "graphql-transformer-core": "6.12.0", From dbc8778cc3dd71f69c951fb4833dc3e3cfcfa40d Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 20 Jan 2020 16:05:42 -0800 Subject: [PATCH 278/587] chore: Consolidate linting to eslint (#3195) * chore: eslint cleanup wip * chore: eslint rules completion to make eslint pass for existing code * chore: add tslint rules and temporary disabled rules to make it line * fix: failing s3 simulator code because of lint update --- packages/amplify-category-api/.eslintignore | 4 ---- packages/amplify-category-api/.eslintrc.json | 15 --------------- packages/amplify-category-api/.gitignore | 7 ------- packages/amplify-category-api/package.json | 9 --------- 4 files changed, 35 deletions(-) delete mode 100644 packages/amplify-category-api/.eslintignore delete mode 100644 packages/amplify-category-api/.eslintrc.json delete mode 100644 packages/amplify-category-api/.gitignore diff --git a/packages/amplify-category-api/.eslintignore b/packages/amplify-category-api/.eslintignore deleted file mode 100644 index 1980e044ef..0000000000 --- a/packages/amplify-category-api/.eslintignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules -__tests__ -__mockes__ -coverage \ No newline at end of file diff --git a/packages/amplify-category-api/.eslintrc.json b/packages/amplify-category-api/.eslintrc.json deleted file mode 100644 index f010567e49..0000000000 --- a/packages/amplify-category-api/.eslintrc.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "extends": ["airbnb-base", "plugin:prettier/recommended"], - "rules": { - "no-param-reassign": "off", - "no-return-await": "off", - "no-constant-condition": "off", - "no-continue": "off", - "no-await-in-loop": "off", - "no-use-before-define": "off", - "no-console": "off", - "global-require": "off", - "import/no-dynamic-require": "off", - "consistent-return": "off" - } -} diff --git a/packages/amplify-category-api/.gitignore b/packages/amplify-category-api/.gitignore deleted file mode 100644 index 5b7ebfc0d5..0000000000 --- a/packages/amplify-category-api/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -.DS_Store -node_modules -npm-debug.log -coverage -.nyc_output -yarn.lock -package-lock.json diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e69e627d5a..993fbc68a5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -5,10 +5,6 @@ "main": "index.js", "author": "Amazon Web Services", "license": "Apache-2.0", - "scripts": { - "lint": "eslint .", - "lint-fix": "eslint . --fix" - }, "dependencies": { "amplify-category-auth": "2.12.0", "amplify-category-function": "2.12.0", @@ -26,10 +22,5 @@ "open": "^6.4.0", "ora": "^3.4.0", "uuid": "^3.3.2" - }, - "devDependencies": { - "eslint": "^4.19.1", - "eslint-config-airbnb-base": "^12.1.0", - "eslint-plugin-import": "^2.12.0" } } From bc06c49c48b270df666081a5a527e92e3621c603 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 23 Jan 2020 03:25:19 +0000 Subject: [PATCH 279/587] chore(release): Publish [ci skip] - amplify-app@2.13.0 - amplify-appsync-simulator@1.13.0 - amplify-category-analytics@2.13.0 - amplify-category-api@2.13.0 - amplify-category-auth@2.13.0 - amplify-category-function@2.13.0 - amplify-category-hosting@2.1.8 - amplify-category-interactions@2.1.8 - amplify-category-notifications@2.13.0 - amplify-category-predictions@2.1.8 - amplify-category-storage@2.1.8 - amplify-category-xr@2.1.8 - @aws-amplify/cli@4.13.0 - amplify-codegen-appsync-model-plugin@1.13.0 - amplify-codegen@2.13.0 - amplify-dynamodb-simulator@1.13.0 - amplify-e2e-tests@2.13.0 - amplify-frontend-android@2.13.0 - amplify-frontend-ios@2.13.0 - amplify-frontend-javascript@2.13.0 - amplify-graphiql-explorer@1.1.8 - amplify-graphql-docs-generator@2.1.8 - amplify-graphql-types-generator@2.1.8 - amplify-provider-awscloudformation@4.13.0 - amplify-storage-simulator@1.1.8 - amplify-ui-tests@2.13.0 - amplify-util-mock@3.13.0 - amplify-velocity-template@1.1.8 - graphql-auth-transformer@6.13.0 - graphql-connection-transformer@4.13.0 - graphql-dynamodb-transformer@6.13.0 - graphql-elasticsearch-transformer@4.3.0 - graphql-function-transformer@2.1.8 - graphql-http-transformer@4.13.0 - graphql-key-transformer@2.13.0 - graphql-mapping-template@4.13.0 - graphql-predictions-transformer@2.1.8 - graphql-relational-schema-transformer@2.13.0 - graphql-transformer-common@4.13.0 - graphql-transformer-core@6.13.0 - graphql-transformers-e2e-tests@6.13.0 - graphql-versioned-transformer@4.13.0 --- packages/amplify-category-api/CHANGELOG.md | 19 +++++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9fc29a6975..f6fa38ae9d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 993fbc68a5..37f5f001f7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,21 +1,21 @@ { "name": "amplify-category-api", - "version": "2.12.0", + "version": "2.13.0", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", "license": "Apache-2.0", "dependencies": { - "amplify-category-auth": "2.12.0", - "amplify-category-function": "2.12.0", - "amplify-category-storage": "2.1.7", + "amplify-category-auth": "2.13.0", + "amplify-category-function": "2.13.0", + "amplify-category-storage": "2.1.8", "aws-sdk": "^2.580.0", "chalk": "^2.4.2", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.12.0", + "graphql-relational-schema-transformer": "2.13.0", "graphql-tag-pluck": "^0.8.4", - "graphql-transformer-core": "6.12.0", + "graphql-transformer-core": "6.13.0", "inquirer": "^6.5.1", "merge-graphql-schemas": "^1.7.0", "moment": "^2.24.0", From 8313093922a6badb7f725f26c6ff472d6f6a1b9a Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Thu, 23 Jan 2020 11:41:29 -0800 Subject: [PATCH 280/587] fix(amplify-category-api): edit auth workflow if cognito is not used (#3232) removes the fine grain auth schema option if aws cognito is not selected as an auth mode re #2967 --- .../service-walkthroughs/appSync-walkthrough.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index f45901cd7b..b92fabf83e 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -70,7 +70,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat if (resourceName) { context.print.warning( - 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.' + 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.', ); process.exit(0); } @@ -220,11 +220,11 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Guided creation of the transform schema const authTypes = getAuthTypes(authConfig); - const onlyApiKeyAuthEnabled = authTypes.includes('API_KEY') && authTypes.length === 1; + const cognitoNotEnabled = !authTypes.includes('AMAZON_COGNITO_USER_POOLS'); let templateSchemaChoices = inputs[4].options; - if (onlyApiKeyAuthEnabled) { + if (cognitoNotEnabled) { templateSchemaChoices = templateSchemaChoices.filter(schema => schema.value !== 'single-object-auth-schema.graphql'); } @@ -363,7 +363,7 @@ async function updateWalkthrough(context) { 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}` + `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); @@ -538,7 +538,7 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { resolverConfig.models = {}; for (let i = 0; i < selectedModelTypes.length; i += 1) { resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( - `Select the resolution strategy for ${selectedModelTypes[i]} model` + `Select the resolution strategy for ${selectedModelTypes[i]} model`, ); } } @@ -634,7 +634,7 @@ async function askAdditionalAuthQuestions(context, parameters, authConfig, defau async function checkForCognitoUserPools(context, parameters, authConfig) { const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter( - provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS' + provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS', ); const additionalUserPoolProvider = additionalUserPoolProviders.length > 0 ? additionalUserPoolProviders[0] : undefined; @@ -801,7 +801,7 @@ function validateDays(input) { function validateIssuerUrl(input) { const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( - input + input, ); if (!isValid) { From 0ef87309a645ae15e2a35148ad3b1ca626610f6a Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Fri, 24 Jan 2020 09:47:55 -0800 Subject: [PATCH 281/587] chore: update dependencies, remove unused packages, apply required test fixes (#3250) * chore: remove unused dependencies * chore: consolidate to single versions of deps * chore: update packages to latest version in most cases * fix: update snapshots and fix test * fix: hanging mock subscription tests * refactor(amplify-codegen-appsync-model-plugin): rebased master Co-authored-by: Josue Ruiz --- packages/amplify-category-api/CHANGELOG.md | 548 +++++---------------- packages/amplify-category-api/package.json | 16 +- 2 files changed, 129 insertions(+), 435 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f6fa38ae9d..3df9d000e8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -5,856 +5,554 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline # [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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - - - - +- 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)) - - - - +- 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)) - - - - +- 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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - +- **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)) - - - - +- 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)) - - - - +- 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)) - - - - +- 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)) - - - - +- 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) - - - - +- **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) - - - - +- **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)) - +- 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) - - - - +- 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)) - - - - +- 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) - - - - +- 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)) - - - - +- 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) - - - - +- **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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) +## [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)) - - - +- **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) - - +## [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) +## [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)) - - - +- 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) - - +## [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) - - +## [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) - - +## [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) +## [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)) - - - +- 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) - - +## [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) +## [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)) - - - +- 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) - - +## [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) +## [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)) - - - +- 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) +## [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)) - - - +- 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) - - +## [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) +## [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)) - - - +- 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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## [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) - - +## 0.1.4 (2018-08-23) **Note:** Version bump only for package amplify-category-api -## 0.1.3 (2018-08-23) - - +## 0.1.3 (2018-08-23) **Note:** Version bump only for package amplify-category-api -## 0.1.2 (2018-08-23) - - +## 0.1.2 (2018-08-23) **Note:** Version bump only for package amplify-category-api -## 0.1.1 (2018-08-23) - - +## 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 index 37f5f001f7..7332702fed 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -8,19 +8,15 @@ "dependencies": { "amplify-category-auth": "2.13.0", "amplify-category-function": "2.13.0", - "amplify-category-storage": "2.1.8", - "aws-sdk": "^2.580.0", - "chalk": "^2.4.2", + "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.13.0", - "graphql-tag-pluck": "^0.8.4", "graphql-transformer-core": "6.13.0", - "inquirer": "^6.5.1", - "merge-graphql-schemas": "^1.7.0", - "moment": "^2.24.0", - "open": "^6.4.0", - "ora": "^3.4.0", - "uuid": "^3.3.2" + "inquirer": "^7.0.3", + "merge-graphql-schemas": "^1.7.6", + "open": "^7.0.0", + "ora": "^4.0.3", + "uuid": "^3.4.0" } } From b453fd1b0449e15e39ae40f345a52aaa4c3e032b Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 24 Jan 2020 21:04:04 +0000 Subject: [PATCH 282/587] chore(release): Publish [ci skip] - amplify-app@2.13.1 - amplify-appsync-simulator@1.13.1 - amplify-category-analytics@2.13.1 - amplify-category-api@2.13.1 - amplify-category-auth@2.13.1 - amplify-category-function@2.13.1 - amplify-category-hosting@2.1.9 - amplify-category-interactions@2.1.9 - amplify-category-notifications@2.13.1 - amplify-category-predictions@2.1.9 - amplify-category-storage@2.1.9 - amplify-category-xr@2.1.9 - @aws-amplify/cli@4.13.1 - amplify-codegen-appsync-model-plugin@1.13.1 - amplify-codegen@2.13.1 - amplify-dynamodb-simulator@1.13.1 - amplify-e2e-tests@2.13.1 - amplify-frontend-android@2.13.1 - amplify-frontend-ios@2.13.1 - amplify-frontend-javascript@2.13.1 - amplify-graphiql-explorer@1.1.9 - amplify-graphql-docs-generator@2.1.9 - amplify-graphql-types-generator@2.1.9 - amplify-provider-awscloudformation@4.13.1 - amplify-storage-simulator@1.1.9 - amplify-ui-tests@2.13.1 - amplify-util-mock@3.13.1 - amplify-velocity-template@1.1.9 - graphql-auth-transformer@6.13.1 - graphql-connection-transformer@4.13.1 - graphql-dynamodb-transformer@6.13.1 - graphql-elasticsearch-transformer@4.3.1 - graphql-function-transformer@2.1.9 - graphql-http-transformer@4.13.1 - graphql-key-transformer@2.13.1 - graphql-mapping-template@4.13.1 - graphql-predictions-transformer@2.1.9 - graphql-relational-schema-transformer@2.13.1 - graphql-transformer-common@4.13.1 - graphql-transformer-core@6.13.1 - graphql-transformers-e2e-tests@6.13.1 - graphql-versioned-transformer@4.13.1 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3df9d000e8..77795e3d2a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7332702fed..a1e4ea2dc0 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,18 +1,18 @@ { "name": "amplify-category-api", - "version": "2.13.0", + "version": "2.13.1", "description": "amplify-cli api plugin", "main": "index.js", "author": "Amazon Web Services", "license": "Apache-2.0", "dependencies": { - "amplify-category-auth": "2.13.0", - "amplify-category-function": "2.13.0", + "amplify-category-auth": "2.13.1", + "amplify-category-function": "2.13.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.13.0", - "graphql-transformer-core": "6.13.0", + "graphql-relational-schema-transformer": "2.13.1", + "graphql-transformer-core": "6.13.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 63172affbf247b138bc50038b7209b12caa23ae9 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 3 Feb 2020 14:41:15 -0800 Subject: [PATCH 283/587] chore: Move to shared TypeScript config in projects where possible, standardize packages (#3315) * wip * wip * chore: fix remaining package files * fix: remaining test and imports --- packages/amplify-category-api/.npmignore | 5 +++++ packages/amplify-category-api/package.json | 7 ++++++- 2 files changed, 11 insertions(+), 1 deletion(-) create mode 100644 packages/amplify-category-api/.npmignore diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore new file mode 100644 index 0000000000..3ee5d55b0b --- /dev/null +++ b/packages/amplify-category-api/.npmignore @@ -0,0 +1,5 @@ +**/__mocks__/** +**/__tests__/** +src +tsconfig.json +tsconfig.tsbuildinfo diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a1e4ea2dc0..ac6bbabab1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -2,9 +2,14 @@ "name": "amplify-category-api", "version": "2.13.1", "description": "amplify-cli api plugin", - "main": "index.js", + "repository": { + "type": "git", + "url": "https://github.com/aws-amplify/amplify-cli.git", + "directory": "packages/amplify-category-api" + }, "author": "Amazon Web Services", "license": "Apache-2.0", + "main": "index.js", "dependencies": { "amplify-category-auth": "2.13.1", "amplify-category-function": "2.13.1", From e3debf129b8493e6e3274ac318bb8e1236817068 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 7 Feb 2020 18:56:10 +0000 Subject: [PATCH 284/587] chore(release): Publish [ci skip] - amplify-app@2.13.2 - amplify-appsync-simulator@1.13.2 - amplify-category-analytics@2.13.2 - amplify-category-api@2.13.2 - amplify-category-auth@2.13.2 - amplify-category-function@2.13.2 - amplify-category-hosting@2.1.10 - amplify-category-interactions@2.1.10 - amplify-category-notifications@2.13.2 - amplify-category-predictions@2.1.10 - amplify-category-storage@2.1.10 - amplify-category-xr@2.1.10 - @aws-amplify/cli@4.13.2 - amplify-codegen-appsync-model-plugin@1.13.2 - amplify-codegen@2.13.2 - amplify-dynamodb-simulator@1.13.2 - amplify-e2e-tests@2.13.2 - amplify-frontend-android@2.13.2 - amplify-frontend-ios@2.13.2 - amplify-frontend-javascript@2.13.2 - amplify-graphiql-explorer@1.1.10 - amplify-graphql-docs-generator@2.1.10 - amplify-graphql-types-generator@2.1.10 - amplify-provider-awscloudformation@4.13.2 - amplify-storage-simulator@1.1.10 - amplify-ui-tests@2.13.2 - amplify-util-mock@3.13.2 - amplify-velocity-template@1.1.10 - graphql-auth-transformer@6.13.2 - graphql-connection-transformer@4.13.2 - graphql-dynamodb-transformer@6.13.2 - graphql-elasticsearch-transformer@4.3.2 - graphql-function-transformer@2.1.10 - graphql-http-transformer@4.13.2 - graphql-key-transformer@2.13.2 - graphql-mapping-template@4.13.2 - graphql-predictions-transformer@2.1.10 - graphql-relational-schema-transformer@2.13.2 - graphql-transformer-common@4.13.2 - graphql-transformer-core@6.13.2 - graphql-transformers-e2e-tests@6.13.2 - graphql-versioned-transformer@4.13.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 77795e3d2a..cbab83ac18 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ac6bbabab1..c9c83a63aa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.13.1", + "version": "2.13.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -11,13 +11,13 @@ "license": "Apache-2.0", "main": "index.js", "dependencies": { - "amplify-category-auth": "2.13.1", - "amplify-category-function": "2.13.1", + "amplify-category-auth": "2.13.2", + "amplify-category-function": "2.13.2", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.13.1", - "graphql-transformer-core": "6.13.1", + "graphql-relational-schema-transformer": "2.13.2", + "graphql-transformer-core": "6.13.2", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 4898425e3c99eaf86f23f778293275795379c69f Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 13 Feb 2020 22:52:49 +0000 Subject: [PATCH 285/587] chore(release): Publish [ci skip] - amplify-app@2.13.3 - amplify-appsync-simulator@1.13.3 - amplify-category-analytics@2.13.3 - amplify-category-api@2.13.3 - amplify-category-auth@2.13.3 - amplify-category-function@2.13.3 - amplify-category-hosting@2.1.11 - amplify-category-interactions@2.1.11 - amplify-category-notifications@2.13.3 - amplify-category-predictions@2.1.11 - amplify-category-storage@2.1.11 - amplify-category-xr@2.1.11 - @aws-amplify/cli@4.13.3 - amplify-codegen-appsync-model-plugin@1.13.3 - amplify-codegen@2.13.3 - amplify-dynamodb-simulator@1.13.3 - amplify-e2e-tests@2.13.3 - amplify-graphql-docs-generator@2.1.11 - amplify-graphql-types-generator@2.1.11 - amplify-provider-awscloudformation@4.13.3 - amplify-ui-tests@2.13.3 - amplify-util-mock@3.14.0 - graphql-auth-transformer@6.13.3 - graphql-connection-transformer@4.13.3 - graphql-dynamodb-transformer@6.13.3 - graphql-elasticsearch-transformer@4.3.3 - graphql-function-transformer@2.1.11 - graphql-http-transformer@4.13.3 - graphql-key-transformer@2.13.3 - graphql-mapping-template@4.13.3 - graphql-predictions-transformer@2.1.11 - graphql-relational-schema-transformer@2.13.3 - graphql-transformer-common@4.13.3 - graphql-transformer-core@6.13.3 - graphql-transformers-e2e-tests@6.13.3 - graphql-versioned-transformer@4.13.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index cbab83ac18..7e158889bd 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c9c83a63aa..2563c8f6d2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.13.2", + "version": "2.13.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -11,13 +11,13 @@ "license": "Apache-2.0", "main": "index.js", "dependencies": { - "amplify-category-auth": "2.13.2", - "amplify-category-function": "2.13.2", + "amplify-category-auth": "2.13.3", + "amplify-category-function": "2.13.3", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.13.2", - "graphql-transformer-core": "6.13.2", + "graphql-relational-schema-transformer": "2.13.3", + "graphql-transformer-core": "6.13.3", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 1bea98120d244220a82f4e2d6f4310313ac15635 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 21 Feb 2020 12:54:34 -0800 Subject: [PATCH 286/587] feat(amplify-category-api): support path parameters in REST APIs (#3394) --- packages/amplify-category-api/package.json | 18 +++++ .../__tests__/apigw-walkthroughs.test.js | 51 +++++++++++++ .../service-walkthroughs/apigw-walkthrough.js | 73 ++++++++----------- 3 files changed, 98 insertions(+), 44 deletions(-) create mode 100644 packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 2563c8f6d2..b9ed3cf59c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -23,5 +23,23 @@ "open": "^7.0.0", "ora": "^4.0.3", "uuid": "^3.4.0" + }, + "devDependencies": { + "rewire":"^4.0.1" + }, + "jest": { + "testURL": "http://localhost", + "testRegex": "(.*/__tests__/.*.test.js)$", + "moduleFileExtensions": [ + "js", + "jsx", + "json", + "node" + ], + "collectCoverage": true, + "coverageReporters": [ + "json", + "html" + ] } } diff --git a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js new file mode 100644 index 0000000000..a107361c3c --- /dev/null +++ b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js @@ -0,0 +1,51 @@ +const rewire = require('rewire'); + +const walkthrough = rewire('../awscloudformation/service-walkthroughs/apigw-walkthrough.js'); + +const validatePathName = walkthrough.__get__('validatePathName'); +const stubOtherPaths = [{name: '/other/path'}, {name: '/sub/path'}] + +test('validatePathName_validPath', () => { + expect(validatePathName('/some/path', stubOtherPaths)).toBeTruthy(); + expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBeTruthy(); +}); + +test('validatePath_empty', () => { + expect(validatePathName('', stubOtherPaths)).toStrictEqual('The path must not be empty') +}) + +test('validatePathName_noLeadingSlash', () => { + expect(validatePathName('no/leading/slash', stubOtherPaths)).toStrictEqual('The path must begin with / e.g. /items'); +}); + +test('validatePathName_hasTrailingSlash', () => { + expect(validatePathName('/has/trailing/slash/', stubOtherPaths)).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}', stubOtherPaths)).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{char@}', stubOtherPaths)).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{param', stubOtherPaths)).toStrictEqual(errorMessage); +}); + +test('validatePathName_subPathMatch', () => { + expect(validatePathName('/sub/path/match', stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /sub/path'); +}); + +test('validatePathName_pathMatch', () => { + expect(validatePathName(stubOtherPaths[0].name, stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /other/path') +}); + +test('formatCFNPathParamsForExpressJs', () => { + // setup + const formatCFNPathParamsForExpressJs = walkthrough.__get__('formatCFNPathParamsForExpressJs'); + + // test + expect(formatCFNPathParamsForExpressJs('/path')).toStrictEqual('/path'); + expect(formatCFNPathParamsForExpressJs('/path/{param}')).toStrictEqual('/path/:param'); + expect(formatCFNPathParamsForExpressJs('/path/{param}/suffix')).toStrictEqual('/path/:param/suffix'); +}) \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 20bf538669..6187d2eef4 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -66,7 +66,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { if (updateApi.resourceName === 'AdminQueries') { context.print.warning( - `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command` + `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`, ); process.exit(0); } @@ -211,7 +211,7 @@ async function askPrivacy(context, answers, currentPath) { if (permissionSelected === 'Learn more') { context.print.info(''); context.print.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.' + '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.', ); context.print.info(''); } @@ -438,15 +438,9 @@ async function askPaths(context, answers, currentPath) { { name: 'name', type: 'input', - message: 'Provide a path (e.g., /items)', + message: 'Provide a path (e.g., /book/{isbn}):', default: currentPath ? currentPath.name : '/items', - validate(value) { - const err = validatePathName(value, answers.paths); - if (err) { - return err; - } - return true; - }, + validate: (value) => validatePathName(value, answers.paths), }, { name: 'functionType', @@ -492,53 +486,36 @@ async function askPaths(context, answers, currentPath) { } function validatePathName(name, paths) { - const err = null; - - if (name.length === 0 || name.substring(name.length - 1) === '/') { - return 'Each sub-path must begin with a letter or number.'; + if (name.length === 0) { + return 'The path must not be empty'; } - // Set / as a first character of path name - if (name.substring(0, 1) !== '/') { - return 'Path must begin with / e.g. /items'; - } - if (/[^a-zA-Z0-9\-/]/.test(name)) { - return 'You can use the following characters: a-z A-Z 0-9 - /'; + if (name.charAt(name.length - 1) === '/') { + return 'The path must not end with /'; } - // If the are is something like /asasd//asa must be detected - // Splitting the string with / to find empty sub-path - const split = name.split('/'); - for (let i = 1; i < split.length; i += 1) { - const val = split[i]; - if (val.length === 0) { - return 'Each sub-path must begin with a letter or number'; - } + if (name.charAt(0) !== '/') { + return 'The path must begin with / e.g. /items'; } - // Checking if there is already that path created on the API - if (paths.find(path => path.name === name)) { - return 'Path name already exists'; + // 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.'; } - // Create subpath from the beginning to find a match on existing paths - const findSubPath = (path, subpath) => path.name === subpath; + const split = name.split('/').filter(sub => sub !== ''); // because name starts with a /, this filters out the first empty element + // Check if any prefix of this path matches an existing path let subpath = ''; - split.forEach(sub => { + const subMatch = split.some(sub => { subpath = `${subpath}/${sub}`; - const subpathFind = paths.find(path => findSubPath(path, subpath)); - if (subpathFind) { - return `A different path already matches this sub-path: ${subpath}`; - } + return paths.map(path => path.name).find(name => name === subpath) !== undefined; }); - - // Check if other paths are a subpath of the new path - subpath = paths.find(path => path.name.indexOf(name) === 0); - if (subpath) { - return `An existing path already match with the one provided: ${subpath.name}`; + if (subMatch) { + return `An existing path already matches this sub-path: ${subpath}`; } - return err; + return true; } async function findDependsOn(paths, context) { @@ -645,6 +622,8 @@ function newLambdaFunction(context, path) { } context.api = { path, + // ExpressJS represents path parameters as /:param instead of /{param}. This expression performs this replacement. + expressPath: formatCFNPathParamsForExpressJs(path), functionTemplate: 'serverless', }; return add(context, 'awscloudformation', 'Lambda').then(resourceName => { @@ -653,6 +632,12 @@ function newLambdaFunction(context, path) { }); } +// Convert a CloudFormation parameterized path to an ExpressJS parameterized path +// /library/{libraryId}/book/{isbn} => /library/:libraryId/book/:isbn +function formatCFNPathParamsForExpressJs(path) { + return path.replace(/{([a-zA-Z0-9\-]+)}/g, ':$1'); +} + async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; From 7d04381fe8aabdda322589058209b27181390c28 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Mon, 2 Mar 2020 11:44:55 -0800 Subject: [PATCH 287/587] fix(amplify-category-api): plumb api id to resources that require it (#3464) fix #3431, fix #3386 --- .../__tests__/apigw-walkthrough.test.js | 6 +++ packages/amplify-category-api/package.json | 11 +++- .../__tests__/apigw-walkthroughs.test.js | 51 ++++++++++--------- ...w-cloudformation-template-default.json.ejs | 4 ++ .../service-walkthroughs/apigw-walkthrough.js | 4 +- 5 files changed, 49 insertions(+), 27 deletions(-) create mode 100644 packages/amplify-category-api/__tests__/apigw-walkthrough.test.js diff --git a/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js b/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js new file mode 100644 index 0000000000..49c8d5e0da --- /dev/null +++ b/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js @@ -0,0 +1,6 @@ +const { getIAMPolicies } = require('../provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough'); + +test('getIAMPolicies', () => { + output = getIAMPolicies('resourceName', ['read']) + expect(output.attributes).toStrictEqual(['ApiName', 'ApiId']) +}) \ No newline at end of file diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b9ed3cf59c..e54a94866a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -10,6 +10,10 @@ "author": "Amazon Web Services", "license": "Apache-2.0", "main": "index.js", + "scripts": { + "test": "jest", + "test-ci": "jest --ci -i" + }, "dependencies": { "amplify-category-auth": "2.13.3", "amplify-category-function": "2.13.3", @@ -29,8 +33,13 @@ }, "jest": { "testURL": "http://localhost", - "testRegex": "(.*/__tests__/.*.test.js)$", + "transform": { + "^.+\\.tsx?$": "ts-jest" + }, + "testRegex": "(.*/__tests__/.*.test.(js|ts))$", "moduleFileExtensions": [ + "ts", + "tsx", "js", "jsx", "json", diff --git a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js index a107361c3c..2f25657178 100644 --- a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js +++ b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js @@ -3,49 +3,52 @@ const rewire = require('rewire'); const walkthrough = rewire('../awscloudformation/service-walkthroughs/apigw-walkthrough.js'); const validatePathName = walkthrough.__get__('validatePathName'); -const stubOtherPaths = [{name: '/other/path'}, {name: '/sub/path'}] +const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }]; test('validatePathName_validPath', () => { - expect(validatePathName('/some/path', stubOtherPaths)).toBeTruthy(); - expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBeTruthy(); + expect(validatePathName('/some/path', stubOtherPaths)).toBeTruthy(); + expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBeTruthy(); }); test('validatePath_empty', () => { - expect(validatePathName('', stubOtherPaths)).toStrictEqual('The path must not be empty') -}) + expect(validatePathName('', stubOtherPaths)).toStrictEqual('The path must not be empty'); +}); test('validatePathName_noLeadingSlash', () => { - expect(validatePathName('no/leading/slash', stubOtherPaths)).toStrictEqual('The path must begin with / e.g. /items'); + expect(validatePathName('no/leading/slash', stubOtherPaths)).toStrictEqual('The path must begin with / e.g. /items'); }); test('validatePathName_hasTrailingSlash', () => { - expect(validatePathName('/has/trailing/slash/', stubOtherPaths)).toStrictEqual('The path must not end with /'); + expect(validatePathName('/has/trailing/slash/', stubOtherPaths)).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}', stubOtherPaths)).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{char@}', stubOtherPaths)).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{param', stubOtherPaths)).toStrictEqual(errorMessage); + // 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}', stubOtherPaths)).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{char@}', stubOtherPaths)).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{param', stubOtherPaths)).toStrictEqual(errorMessage); }); test('validatePathName_subPathMatch', () => { - expect(validatePathName('/sub/path/match', stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /sub/path'); + expect(validatePathName('/sub/path/match', stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /sub/path'); }); test('validatePathName_pathMatch', () => { - expect(validatePathName(stubOtherPaths[0].name, stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /other/path') + expect(validatePathName(stubOtherPaths[0].name, stubOtherPaths)).toStrictEqual( + 'An existing path already matches this sub-path: /other/path', + ); }); test('formatCFNPathParamsForExpressJs', () => { - // setup - const formatCFNPathParamsForExpressJs = walkthrough.__get__('formatCFNPathParamsForExpressJs'); - - // test - expect(formatCFNPathParamsForExpressJs('/path')).toStrictEqual('/path'); - expect(formatCFNPathParamsForExpressJs('/path/{param}')).toStrictEqual('/path/:param'); - expect(formatCFNPathParamsForExpressJs('/path/{param}/suffix')).toStrictEqual('/path/:param/suffix'); -}) \ No newline at end of file + // setup + const formatCFNPathParamsForExpressJs = walkthrough.__get__('formatCFNPathParamsForExpressJs'); + + // test + 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/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 28974b62bf..d25cb258e2 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -711,6 +711,10 @@ "ApiName": { "Description": "API Friendly name", "Value": "<%= props.resourceName %>" + }, + "ApiId": { + "Description": "API ID (prefix of API URL)", + "Value": {"Ref": "<%= props.apiName %>"} } } } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 6187d2eef4..1ef7d907ee 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -440,7 +440,7 @@ async function askPaths(context, answers, currentPath) { type: 'input', message: 'Provide a path (e.g., /book/{isbn}):', default: currentPath ? currentPath.name : '/items', - validate: (value) => validatePathName(value, answers.paths), + validate: value => validatePathName(value, answers.paths), }, { name: 'functionType', @@ -809,7 +809,7 @@ function getIAMPolicies(resourceName, crudOptions) { ], }; - const attributes = ['ApiName']; + const attributes = ['ApiName', 'ApiId']; return { policy, attributes }; } From 2c043814c0392524f486bd030a87584fb45f0027 Mon Sep 17 00:00:00 2001 From: hirochachacha Date: Tue, 3 Mar 2020 09:26:41 +1100 Subject: [PATCH 288/587] chore: drop unnecessary execute permissions on some files (#3455) --- packages/amplify-category-api/commands/api.js | 0 packages/amplify-category-api/templates/api.ejs | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 packages/amplify-category-api/commands/api.js mode change 100755 => 100644 packages/amplify-category-api/templates/api.ejs diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/commands/api.js old mode 100755 new mode 100644 diff --git a/packages/amplify-category-api/templates/api.ejs b/packages/amplify-category-api/templates/api.ejs old mode 100755 new mode 100644 From 1d8fcec1f4aebc29ddcbe249b4398fac0c9a2fc6 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Thu, 5 Mar 2020 13:05:54 -0800 Subject: [PATCH 289/587] chore: release v4.14.1 (#3597) * chore: manually bump up minor versions * chore: update forntend js package in amplify-app * chore(release): Publish [ci skip] - amplify-app@2.13.6-beta.0 - amplify-appsync-simulator@1.14.2-beta.0 - amplify-category-analytics@2.13.5-beta.0 - amplify-category-api@2.13.5-beta.0 - amplify-category-auth@2.13.5-beta.0 - amplify-category-function@2.13.5-beta.0 - amplify-category-hosting@2.1.13-beta.0 - amplify-category-interactions@2.1.13-beta.0 - amplify-category-notifications@2.13.5-beta.0 - amplify-category-predictions@2.1.14-beta.0 - amplify-category-storage@2.1.13-beta.0 - amplify-category-xr@2.1.13-beta.0 - @aws-amplify/cli@4.13.6-beta.0 - amplify-codegen@2.13.5-beta.0 - amplify-console-hosting@1.0.2-beta.0 - amplify-console-integration@1.0.2-beta.0 - amplify-e2e-tests@2.13.5-beta.0 - amplify-frontend-javascript@2.13.4-beta.0 - amplify-graphiql-explorer@1.1.12-beta.0 - amplify-graphql-types-generator@2.1.13-beta.0 - amplify-provider-awscloudformation@4.13.6-beta.0 - amplify-storage-simulator@1.1.12-beta.0 - amplify-util-mock@3.14.3-beta.0 - graphql-auth-transformer@6.13.6-beta.0 - graphql-connection-transformer@4.13.6-beta.0 - graphql-dynamodb-transformer@6.13.6-beta.0 - graphql-elasticsearch-transformer@4.3.6-beta.0 - graphql-function-transformer@2.1.13-beta.0 - graphql-http-transformer@4.13.5-beta.0 - graphql-key-transformer@2.13.6-beta.0 - graphql-predictions-transformer@2.1.13-beta.0 - graphql-relational-schema-transformer@2.13.5-beta.0 - graphql-transformer-core@6.13.5-beta.0 - graphql-transformers-e2e-tests@6.13.6-beta.0 - graphql-versioned-transformer@4.13.6-beta.0 * chore: change formatting of serviceSelectPrompt function * chore(release): Publish [ci skip] - @aws-amplify/cli@4.13.6-beta.1 * chore(cli): remove stale esm cache postinstall (#3596) updated post install script to remove the stale esm cache * chore: bump up minor version number * chore(release): Publish [ci skip] - amplify-app@2.14.1 - amplify-appsync-simulator@1.15.1 - amplify-category-analytics@2.14.1 - amplify-category-api@2.14.1 - amplify-category-auth@2.14.1 - amplify-category-function@2.14.1 - amplify-category-hosting@2.2.1 - amplify-category-interactions@2.2.1 - amplify-category-notifications@2.14.1 - amplify-category-predictions@2.2.1 - amplify-category-storage@2.2.1 - amplify-category-xr@2.2.1 - @aws-amplify/cli@4.14.1 - amplify-codegen@2.14.1 - amplify-console-hosting@1.1.1 - amplify-console-integration@1.1.1 - amplify-e2e-tests@2.14.1 - amplify-frontend-javascript@2.14.1 - amplify-graphiql-explorer@1.2.1 - amplify-graphql-types-generator@2.2.1 - amplify-provider-awscloudformation@4.14.1 - amplify-storage-simulator@1.2.1 - amplify-util-mock@3.15.1 - graphql-auth-transformer@6.14.1 - graphql-connection-transformer@4.14.1 - graphql-dynamodb-transformer@6.14.1 - graphql-elasticsearch-transformer@4.4.1 - graphql-function-transformer@2.2.1 - graphql-http-transformer@4.14.1 - graphql-key-transformer@2.14.1 - graphql-predictions-transformer@2.2.1 - graphql-relational-schema-transformer@2.14.1 - graphql-transformer-core@6.14.1 - graphql-transformers-e2e-tests@6.14.1 - graphql-versioned-transformer@4.14.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7e158889bd..6f8267750b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e54a94866a..d36a3727f3 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.13.3", + "version": "2.14.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.13.3", - "amplify-category-function": "2.13.3", + "amplify-category-auth": "2.14.1", + "amplify-category-function": "2.14.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.13.3", - "graphql-transformer-core": "6.13.3", + "graphql-relational-schema-transformer": "2.14.1", + "graphql-transformer-core": "6.14.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", @@ -29,7 +29,7 @@ "uuid": "^3.4.0" }, "devDependencies": { - "rewire":"^4.0.1" + "rewire": "^4.0.1" }, "jest": { "testURL": "http://localhost", From 1c97cf2ec266bee60db6d1e60f8fb79314727aff Mon Sep 17 00:00:00 2001 From: Ghosh Date: Fri, 6 Mar 2020 22:18:53 -0800 Subject: [PATCH 290/587] chore: version bmp to 4.15.1 --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d36a3727f3..5b2b8b741d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.14.1", + "version": "2.15.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.14.1", - "amplify-category-function": "2.14.1", + "amplify-category-auth": "^2.15.0", + "amplify-category-function": "^2.15.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.14.1", - "graphql-transformer-core": "6.14.1", + "graphql-relational-schema-transformer": "^2.15.0", + "graphql-transformer-core": "^6.15.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From a9254e3f472f82121d238b8573387643d5605d73 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 7 Mar 2020 06:30:25 +0000 Subject: [PATCH 291/587] chore(release): Publish [ci skip] - amplify-app@2.15.1 - amplify-appsync-simulator@1.17.0 - amplify-category-analytics@2.16.0 - amplify-category-api@2.16.0 - amplify-category-auth@2.15.1 - amplify-category-function@2.16.0 - amplify-category-hosting@2.3.1 - amplify-category-interactions@2.3.1 - amplify-category-notifications@2.15.1 - amplify-category-predictions@2.3.1 - amplify-category-storage@2.4.0 - amplify-category-xr@2.3.1 - @aws-amplify/cli@4.16.0 - amplify-codegen@2.15.1 - amplify-console-hosting@1.3.0 - amplify-console-integration@1.2.1 - amplify-e2e-tests@2.16.0 - amplify-frontend-javascript@2.15.1 - amplify-graphiql-explorer@1.3.1 - amplify-graphql-types-generator@2.3.1 - amplify-provider-awscloudformation@4.16.0 - amplify-storage-simulator@1.3.1 - amplify-util-mock@3.16.1 - graphql-auth-transformer@6.15.1 - graphql-connection-transformer@4.15.1 - graphql-dynamodb-transformer@6.15.1 - graphql-elasticsearch-transformer@4.5.1 - graphql-function-transformer@2.3.1 - graphql-http-transformer@4.15.1 - graphql-key-transformer@2.15.1 - graphql-predictions-transformer@2.3.1 - graphql-relational-schema-transformer@2.15.1 - graphql-transformer-core@6.16.0 - graphql-transformers-e2e-tests@6.15.1 - graphql-versioned-transformer@4.15.1 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6f8267750b..da7bf6a2d9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5b2b8b741d..5614706845 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.15.0", + "version": "2.16.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "^2.15.0", - "amplify-category-function": "^2.15.0", + "amplify-category-auth": "2.15.1", + "amplify-category-function": "2.16.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "^2.15.0", - "graphql-transformer-core": "^6.15.0", + "graphql-relational-schema-transformer": "2.15.1", + "graphql-transformer-core": "6.16.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 16ef24350452e33cea6292a2577ba74820b3ea6d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 10 Mar 2020 07:07:19 +0000 Subject: [PATCH 292/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.16.1 - amplify-category-api@2.16.1 - amplify-category-auth@2.15.2 - amplify-category-function@2.16.1 - amplify-category-interactions@2.3.2 - amplify-category-notifications@2.15.2 - amplify-category-predictions@2.3.2 - amplify-category-storage@2.4.1 - amplify-category-xr@2.3.2 - @aws-amplify/cli@4.16.1 - amplify-codegen-appsync-model-plugin@1.13.4 - amplify-codegen@2.15.2 - amplify-e2e-tests@2.16.1 - amplify-provider-awscloudformation@4.16.1 - amplify-util-mock@3.16.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index da7bf6a2d9..e382c3eb0c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5614706845..8eb996f698 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.16.0", + "version": "2.16.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.1", - "amplify-category-function": "2.16.0", + "amplify-category-auth": "2.15.2", + "amplify-category-function": "2.16.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From c4de09e8477b04c509b294fbf78b1baac8320cd8 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Tue, 17 Mar 2020 16:25:37 -0700 Subject: [PATCH 293/587] feat(amplify-category-function): refactor to support runtime and template plugins (#3517) Does not implement any new functionality but lays groundwork for allowing pluggable runtimes and function templates. --- .../service-walkthroughs/apigw-walkthrough.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 1ef7d907ee..4862c27bdb 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -626,7 +626,15 @@ function newLambdaFunction(context, path) { expressPath: formatCFNPathParamsForExpressJs(path), functionTemplate: 'serverless', }; - return add(context, 'awscloudformation', 'Lambda').then(resourceName => { + let params = { + functionTemplate: { + parameters: { + path, + expressPath: formatCFNPathParamsForExpressJs(path) + } + } + } + return add(context, 'awscloudformation', 'Lambda', params).then(resourceName => { context.print.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; }); From 1428403b7e96eaae0117252566430c20e67c1c14 Mon Sep 17 00:00:00 2001 From: ammarkarachi <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 19 Mar 2020 16:34:14 -0700 Subject: [PATCH 294/587] fix(cli): deleting the amplify app on delete (#3568) * fix(cli): deleting the amplify app on delete `amplify delete` deletes the amplify app now #3239 * refactor(cli): removed console logs * fix(cli): graceful exit when app not found * refactor(cli): removed unused * Revert "refactor(cli): removed unused" This reverts commit 0b5f892637c47f4a7a9cb2729608fdb07554a153. * Revert "fix(cli): graceful exit when app not found" This reverts commit 2cd87b6d511dd3552ca74482d3dee62e0f9ee7d6. * fix(cli): graceful exit after fail * fix(cli): graceful exit * fix(cli): misspelled failed * fix(cli): env check before delete app checking for any external environments to before deleting app --- .../service-walkthroughs/apigw-walkthrough.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 4862c27bdb..7eecca9156 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -630,10 +630,10 @@ function newLambdaFunction(context, path) { functionTemplate: { parameters: { path, - expressPath: formatCFNPathParamsForExpressJs(path) - } - } - } + expressPath: formatCFNPathParamsForExpressJs(path), + }, + }, + }; return add(context, 'awscloudformation', 'Lambda', params).then(resourceName => { context.print.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; From 886c77f12b81efd49ac478759cfef0c56a9df23a Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 20 Mar 2020 11:33:11 -0700 Subject: [PATCH 295/587] fix: update graphql schema to match docs (#3652) * fix: update graphql schema to match docs Update the one-to-many schema to reflect the newer @connection directive style #3513 * Update relationship in schema to be bi-directional --- .../many-relationship-schema.graphql | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql index bb3c4c7d11..02224d1f95 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql @@ -1,16 +1,20 @@ type Blog @model { id: ID! name: String! - posts: [Post] @connection(name: "BlogPosts") + posts: [Post] @connection(keyName: "byBlog", fields: ["id"]) } -type Post @model { + +type Post @model @key(name: "byBlog", fields: ["blogID"]) { id: ID! title: String! - blog: Blog @connection(name: "BlogPosts") - comments: [Comment] @connection(name: "PostComments") + blogID: String! + blog: Blog @connection(fields: ["blogID"]) + comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) } -type Comment @model { + +type Comment @model @key(name: "byPost", fields: ["postID", "content"]) { id: ID! - content: String - post: Post @connection(name: "PostComments") -} \ No newline at end of file + postID: ID! + post: Post @connection(fields: ["postID"]) + content: String! +} From ca78270d123982e03d942afe69ec6fce501427a2 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Sat, 21 Mar 2020 13:24:29 -0700 Subject: [PATCH 296/587] fix(graphql-elasticsearch-transformer): fix duplicate records in es lambda (#3712) * fix(graphql-elasticsearch-transformer): fix es lambda on duplicate docs fixed document to remove duplicates based on changes introduced supporting @key re #3602 #3705 * update version check logic * checked for version mismatch and santity check that version added is supported * added elasticsearch warning flag * remove unused errors * removed unused dependencies * fix bugs and address PR comments Co-authored-by: Ghosh --- .../service-walkthroughs/appSync-walkthrough.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index b92fabf83e..3cf8719419 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -302,6 +302,7 @@ async function writeResolverConfig(resolverConfig, resourceDir) { async function updateTransformerConfigVersion(resourceDir) { const localTransformerConfig = await readTransformerConfiguration(resourceDir); localTransformerConfig.Version = TRANSFORM_CURRENT_VERSION; + localTransformerConfig.ElasticsearchWarning = true; await writeTransformerConfiguration(resourceDir, localTransformerConfig); } From 67ebb87b8b955e66a8279ad65502423b44c9be5f Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 22 Mar 2020 00:25:18 +0000 Subject: [PATCH 297/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.18.0 - amplify-category-analytics@2.16.2 - amplify-category-api@2.17.0 - amplify-category-auth@2.15.3 - amplify-category-function@2.17.0 - amplify-category-interactions@2.3.3 - amplify-category-notifications@2.15.3 - amplify-category-predictions@2.3.3 - amplify-category-storage@2.4.2 - amplify-category-xr@2.3.3 - @aws-amplify/cli@4.17.0 - amplify-codegen-appsync-model-plugin@1.13.5 - amplify-codegen@2.15.3 - amplify-console-hosting@1.3.1 - amplify-dynamodb-simulator@1.14.0 - amplify-e2e-core@1.0.1 - amplify-e2e-tests@2.16.2 - amplify-function-plugin-interface@1.1.0 - amplify-graphql-docs-generator@2.1.12 - amplify-graphql-types-generator@2.3.2 - amplify-nodejs-runtime-provider@1.1.0 - amplify-nodejs-template-provider@1.1.0 - amplify-provider-awscloudformation@4.17.0 - amplify-util-mock@3.17.0 - graphql-auth-transformer@6.15.2 - graphql-connection-transformer@4.15.2 - graphql-dynamodb-transformer@6.16.0 - graphql-elasticsearch-transformer@4.5.2 - graphql-function-transformer@2.3.2 - graphql-http-transformer@4.15.2 - graphql-key-transformer@2.15.2 - graphql-predictions-transformer@2.3.2 - graphql-relational-schema-transformer@2.15.2 - graphql-transformer-common@4.14.0 - graphql-transformer-core@6.16.1 - graphql-transformers-e2e-tests@6.15.2 - graphql-versioned-transformer@4.15.2 --- packages/amplify-category-api/CHANGELOG.md | 18 ++++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e382c3eb0c..fb40b132aa 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,24 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8eb996f698..b53144044e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.16.1", + "version": "2.17.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.2", - "amplify-category-function": "2.16.1", + "amplify-category-auth": "2.15.3", + "amplify-category-function": "2.17.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.1", - "graphql-transformer-core": "6.16.0", + "graphql-relational-schema-transformer": "2.15.2", + "graphql-transformer-core": "6.16.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 4998de59ecc5823d57e6a609273d0f68f8ff6565 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 26 Mar 2020 16:59:27 +0000 Subject: [PATCH 298/587] chore(release): Publish [ci skip] - amplify-category-api@2.17.1 - amplify-category-function@2.18.0 - amplify-category-predictions@2.3.4 - @aws-amplify/cli@4.17.2 - amplify-codegen-appsync-model-plugin@1.14.0 - amplify-codegen@2.15.4 - amplify-function-plugin-interface@1.2.0 - amplify-nodejs-runtime-provider@1.1.1 - amplify-nodejs-template-provider@1.1.1 - amplify-provider-awscloudformation@4.17.1 - amplify-util-mock@3.17.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fb40b132aa..9f051f1955 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b53144044e..adb8395797 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.17.0", + "version": "2.17.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,7 +16,7 @@ }, "dependencies": { "amplify-category-auth": "2.15.3", - "amplify-category-function": "2.17.0", + "amplify-category-function": "2.18.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From c5be4a02d5f157861261b75765c4ff8b3e3121f0 Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Mon, 30 Mar 2020 20:33:57 -0700 Subject: [PATCH 299/587] feat: uplevel enabling of datastore and update of auth configs to top (#3495) * feat: uplevel enabling of datastore and update of auth configs to top * remove console log statements * updates based on pr comments --- .../appSync-walkthrough.js | 82 +++++++++++++------ 1 file changed, 58 insertions(+), 24 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 3cf8719419..4d3d1e7d17 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -107,11 +107,9 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat // Ask additonal questions - /* eslint-disable */ ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType)); await checkForCognitoUserPools(context, parameters, authConfig); - /* eslint-disable */ // Ask schema file question @@ -355,7 +353,9 @@ async function updateWalkthrough(context) { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; - let authConfig, defaultAuthType, resolverConfig; + let authConfig; + let defaultAuthType; + let resolverConfig; const resources = allResources.filter(resource => resource.service === 'AppSync'); // There can only be one appsync resource @@ -402,35 +402,69 @@ async function updateWalkthrough(context) { }); } - /* eslint-disable */ - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); - ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes)); - await checkForCognitoUserPools(context, parameters, authConfig); - /* eslint-disable */ + const updateOptionQuestion = { + type: 'list', + name: 'updateOption', + message: 'Select from the options below', + choices: [ + { + name: 'Walkthrough all configurations', + value: 'all', + }, + { + name: 'Update auth settings', + value: 'authUpdate', + }, + { + name: 'Enable DataStore for entire API', + value: 'enableDatastore', + }, + ], + }; - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); + let { updateOption } = await inquirer.prompt([updateOptionQuestion]); - if (amplifyMeta[category][resourceName].output.securityType) { - delete amplifyMeta[category][resourceName].output.securityType; + if (updateOption === 'enableDatastore') { + resolverConfig = { + project: { ConflictHandler: 'AUTOMERGE', ConflictDetection: 'VERSION' }, + }; + } else if (updateOption === 'authUpdate') { + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); + authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); + await checkForCognitoUserPools(context, parameters, authConfig); + } else if (updateOption === 'all') { + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); + ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes)); + await checkForCognitoUserPools(context, parameters, authConfig); } - amplifyMeta[category][resourceName].output.authConfig = authConfig; - let jsonString = JSON.stringify(amplifyMeta, null, '\t'); - fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); + if (authConfig) { + const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); + const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); - const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); + if (amplifyMeta[category][resourceName].output.securityType) { + delete amplifyMeta[category][resourceName].output.securityType; + } - if (backendConfig[category][resourceName].output.securityType) { - delete backendConfig[category][resourceName].output.securityType; - } + amplifyMeta[category][resourceName].output.authConfig = authConfig; + let jsonString = JSON.stringify(amplifyMeta, null, 4); + fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); - backendConfig[category][resourceName].output.authConfig = authConfig; - jsonString = JSON.stringify(backendConfig, null, '\t'); - fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); + const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); + const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); - await writeResolverConfig(resolverConfig, resourceDir); + if (backendConfig[category][resourceName].output.securityType) { + delete backendConfig[category][resourceName].output.securityType; + } + + backendConfig[category][resourceName].output.authConfig = authConfig; + jsonString = JSON.stringify(backendConfig, null, 4); + fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); + } + + if (resolverConfig) { + await writeResolverConfig(resolverConfig, resourceDir); + } await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { resourceDir, From 0015c49e472c8d7d05a323a2c98b28df6d10b739 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 6 Apr 2020 15:45:10 +0000 Subject: [PATCH 300/587] chore(release): Publish [ci skip] - amplify-app@2.16.0 - amplify-appsync-simulator@1.19.0 - amplify-category-analytics@2.16.3 - amplify-category-api@2.18.0 - amplify-category-auth@2.15.4 - amplify-category-function@2.19.0 - amplify-category-interactions@2.3.4 - amplify-category-notifications@2.15.4 - amplify-category-predictions@2.3.5 - amplify-category-storage@2.4.3 - amplify-category-xr@2.3.4 - @aws-amplify/cli@4.18.0 - amplify-codegen-appsync-model-plugin@1.15.0 - amplify-codegen@2.15.5 - amplify-console-integration-tests@1.2.2 - amplify-dotnet-function-runtime-provider@1.0.1 - amplify-dotnet-function-template-provider@1.0.1 - amplify-e2e-core@1.1.0 - amplify-e2e-tests@2.17.0 - amplify-function-plugin-interface@1.3.0 - amplify-go-function-runtime-provider@1.1.0 - amplify-go-function-template-provider@1.1.0 - amplify-java-function-runtime-provider@1.1.0 - amplify-java-function-template-provider@1.1.0 - amplify-nodejs-function-runtime-provider@1.0.1 - amplify-nodejs-function-template-provider@1.0.1 - amplify-provider-awscloudformation@4.18.0 - amplify-python-function-runtime-provider@1.1.0 - amplify-python-function-template-provider@1.1.0 - amplify-util-mock@3.18.0 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9f051f1955..622ed4fe8c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index adb8395797..6a8761c6aa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.17.1", + "version": "2.18.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.3", - "amplify-category-function": "2.18.0", + "amplify-category-auth": "2.15.4", + "amplify-category-function": "2.19.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From e7bee305f49e7f21d18369530c75f9c755ba533c Mon Sep 17 00:00:00 2001 From: Meiring de Wet <50661574+mdw2000@users.noreply.github.com> Date: Thu, 9 Apr 2020 22:26:38 +0400 Subject: [PATCH 301/587] feat(amplify-category-api): allow minified CF stack templates (#3520) Allow minified stack templates to be generated to circumvent the 460800 bytes size limit fix #2914 Co-authored-by: Meiring --- packages/amplify-category-api/commands/api/gql-compile.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 5b499cc553..09564f5305 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -4,7 +4,13 @@ module.exports = { name: subcommand, run: async context => { try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); + const { + parameters: { options }, + } = context; + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + forceCompile: true, + minify: options['minify'], + }); } catch (err) { context.print.error(err.toString()); } From d742288daa9ba31b7a6a21ab86b7f1a2e1a96445 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 23 Apr 2020 18:02:36 +0000 Subject: [PATCH 302/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.20.0 - amplify-category-api@2.19.0 - amplify-category-function@2.20.0 - amplify-category-interactions@2.3.5 - amplify-category-predictions@2.3.6 - @aws-amplify/cli@4.18.1 - amplify-codegen-appsync-model-plugin@1.16.0 - amplify-codegen@2.15.6 - amplify-console-integration-tests@1.2.3 - amplify-dotnet-function-runtime-provider@1.0.2 - amplify-dotnet-function-template-provider@1.1.0 - amplify-e2e-core@1.1.1 - amplify-e2e-tests@2.17.1 - amplify-frontend-javascript@2.15.2 - amplify-graphiql-explorer@1.3.2 - amplify-graphql-docs-generator@2.1.13 - amplify-graphql-types-generator@2.3.3 - amplify-java-function-runtime-provider@1.1.1 - amplify-nodejs-function-runtime-provider@1.0.2 - amplify-provider-awscloudformation@4.19.0 - amplify-util-mock@3.19.0 - graphql-auth-transformer@6.15.3 - graphql-connection-transformer@4.15.3 - graphql-dynamodb-transformer@6.16.1 - graphql-elasticsearch-transformer@4.5.3 - graphql-function-transformer@2.3.3 - graphql-http-transformer@4.15.3 - graphql-key-transformer@2.15.3 - graphql-predictions-transformer@2.3.3 - graphql-transformer-core@6.17.0 - graphql-transformers-e2e-tests@6.15.3 - graphql-versioned-transformer@4.15.3 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 622ed4fe8c..ca9391d43e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 6a8761c6aa..298b1bebfc 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.18.0", + "version": "2.19.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,12 +16,12 @@ }, "dependencies": { "amplify-category-auth": "2.15.4", - "amplify-category-function": "2.19.0", + "amplify-category-function": "2.20.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.2", - "graphql-transformer-core": "6.16.1", + "graphql-transformer-core": "6.17.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 8bd0e4e6c87cdc31d87b951ed429a02835a7e977 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 24 Apr 2020 15:12:17 -0700 Subject: [PATCH 303/587] fix: incorrect type on graphql boilerplate schema (#4070) --- .../appsync-schemas/many-relationship-schema.graphql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql index 02224d1f95..cf765373f8 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql +++ b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql @@ -7,7 +7,7 @@ type Blog @model { type Post @model @key(name: "byBlog", fields: ["blogID"]) { id: ID! title: String! - blogID: String! + blogID: ID! blog: Blog @connection(fields: ["blogID"]) comments: [Comment] @connection(keyName: "byPost", fields: ["id"]) } From 3bb9c65613a9f0ed1ad7185ef7f3d806aec19bdd Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 8 May 2020 16:31:15 +0000 Subject: [PATCH 304/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.20.1 - amplify-category-analytics@2.16.4 - amplify-category-api@2.19.1 - amplify-category-auth@2.15.5 - amplify-category-function@2.20.1 - amplify-category-interactions@2.3.6 - amplify-category-notifications@2.15.5 - amplify-category-predictions@2.3.7 - amplify-category-storage@2.4.4 - amplify-category-xr@2.3.5 - @aws-amplify/cli@4.19.0 - amplify-codegen-appsync-model-plugin@1.17.0 - amplify-codegen@2.15.7 - amplify-console-integration-tests@1.2.4 - amplify-dotnet-function-runtime-provider@1.1.0 - amplify-dotnet-function-template-provider@1.2.0 - amplify-e2e-core@1.1.2 - amplify-e2e-tests@2.17.2 - amplify-function-plugin-interface@1.3.1 - amplify-go-function-runtime-provider@1.1.1 - amplify-go-function-template-provider@1.1.1 - amplify-java-function-runtime-provider@1.1.2 - amplify-java-function-template-provider@1.1.1 - amplify-migration-tests@2.17.1 - amplify-nodejs-function-runtime-provider@1.0.3 - amplify-nodejs-function-template-provider@1.0.2 - amplify-provider-awscloudformation@4.19.1 - amplify-python-function-runtime-provider@1.1.1 - amplify-python-function-template-provider@1.1.1 - amplify-storage-simulator@1.4.0 - amplify-util-mock@3.19.1 - graphql-auth-transformer@6.15.4 - graphql-connection-transformer@4.16.0 - graphql-dynamodb-transformer@6.17.0 - graphql-elasticsearch-transformer@4.6.0 - graphql-function-transformer@2.3.4 - graphql-http-transformer@4.15.4 - graphql-key-transformer@2.16.0 - graphql-mapping-template@4.13.4 - graphql-predictions-transformer@2.3.4 - graphql-relational-schema-transformer@2.15.3 - graphql-transformer-common@4.15.0 - graphql-transformer-core@6.17.1 - graphql-transformers-e2e-tests@6.15.4 - graphql-versioned-transformer@4.15.4 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ca9391d43e..f880577b1c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 298b1bebfc..0ef049a667 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.0", + "version": "2.19.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.4", - "amplify-category-function": "2.20.0", + "amplify-category-auth": "2.15.5", + "amplify-category-function": "2.20.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.2", - "graphql-transformer-core": "6.17.0", + "graphql-relational-schema-transformer": "2.15.3", + "graphql-transformer-core": "6.17.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 8daf6567a63c806dec01dee5b6c3bbd658c0dae7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 15 May 2020 01:21:42 +0000 Subject: [PATCH 305/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.20.2 - amplify-category-analytics@2.16.5 - amplify-category-api@2.19.2 - amplify-category-auth@2.15.6 - amplify-category-function@2.20.2 - amplify-category-interactions@2.3.7 - amplify-category-notifications@2.15.6 - amplify-category-predictions@2.3.8 - amplify-category-storage@2.4.5 - amplify-category-xr@2.3.6 - @aws-amplify/cli@4.20.0 - amplify-codegen-appsync-model-plugin@1.18.0 - amplify-codegen@2.15.8 - amplify-console-hosting@1.3.2 - amplify-console-integration-tests@1.2.5 - amplify-dotnet-function-runtime-provider@1.1.1 - amplify-e2e-core@1.1.3 - amplify-e2e-tests@2.17.3 - amplify-frontend-javascript@2.15.3 - amplify-graphql-types-generator@2.3.4 - amplify-migration-tests@2.17.2 - amplify-nodejs-function-runtime-provider@1.0.4 - amplify-provider-awscloudformation@4.20.0 - amplify-util-mock@3.20.0 - graphql-auth-transformer@6.16.0 - graphql-connection-transformer@4.17.0 - graphql-dynamodb-transformer@6.18.0 - graphql-elasticsearch-transformer@4.7.0 - graphql-function-transformer@2.3.5 - graphql-http-transformer@4.15.5 - graphql-key-transformer@2.17.0 - graphql-predictions-transformer@2.3.5 - graphql-transformer-core@6.18.0 - graphql-transformers-e2e-tests@6.16.0 - graphql-versioned-transformer@4.15.5 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f880577b1c..ba53fb245a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0ef049a667..3db699986b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.1", + "version": "2.19.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.5", - "amplify-category-function": "2.20.1", + "amplify-category-auth": "2.15.6", + "amplify-category-function": "2.20.2", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.3", - "graphql-transformer-core": "6.17.1", + "graphql-transformer-core": "6.18.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 0feefcdcbef1939ff1ad0a9f57da35d8249e67ce Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Thu, 21 May 2020 15:19:48 -0700 Subject: [PATCH 306/587] fix(amplify-category-api): toggle datastore in update (#4276) * fix(amplify-category-api): toggle datastore in update added option to toggle datastore for the api re #4058 * remove authConfig logic check * test(amplify-e2e-tests): add e2e for datastore toggle update --- .../appSync-walkthrough.js | 34 +++++++++++-------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 4d3d1e7d17..8b2057083d 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -401,25 +401,28 @@ async function updateWalkthrough(context) { } }); } + const updateChoices = [ + { + name: 'Walkthrough all configurations', + value: 'all', + }, + { + name: 'Update auth settings', + value: 'authUpdate', + }, + ]; + // check if DataStore is enabled for the entire API + if (project.config && project.config.ResolverConfig) { + updateChoices.push({ name: 'Disable DataStore for entire API', value: 'disableDatastore' }); + } else { + updateChoices.push({ name: 'Enable DataStore for entire API', value: 'enableDatastore' }); + } const updateOptionQuestion = { type: 'list', name: 'updateOption', message: 'Select from the options below', - choices: [ - { - name: 'Walkthrough all configurations', - value: 'all', - }, - { - name: 'Update auth settings', - value: 'authUpdate', - }, - { - name: 'Enable DataStore for entire API', - value: 'enableDatastore', - }, - ], + choices: updateChoices, }; let { updateOption } = await inquirer.prompt([updateOptionQuestion]); @@ -428,6 +431,9 @@ async function updateWalkthrough(context) { resolverConfig = { project: { ConflictHandler: 'AUTOMERGE', ConflictDetection: 'VERSION' }, }; + } else if (updateOption === 'disableDatastore') { + delete project.config.ResolverConfig; + await writeTransformerConfiguration(resourceDir, project.config); } else if (updateOption === 'authUpdate') { ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); From 6a5508fbc311ae7b4932fe35ac66ac2691e9e4f7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 26 May 2020 14:45:53 +0000 Subject: [PATCH 307/587] chore(release): Publish [ci skip] - amplify-app@2.17.0 - amplify-category-analytics@2.16.6 - amplify-category-api@2.19.3 - amplify-category-auth@2.15.7 - amplify-category-function@2.20.3 - amplify-category-interactions@2.3.8 - amplify-category-notifications@2.15.7 - amplify-category-predictions@2.3.9 - amplify-category-storage@2.4.6 - amplify-category-xr@2.3.7 - @aws-amplify/cli@4.21.0 - amplify-codegen-appsync-model-plugin@1.19.0 - amplify-codegen@2.15.9 - amplify-console-integration-tests@1.2.6 - amplify-e2e-core@1.1.4 - amplify-e2e-tests@2.18.0 - amplify-frontend-android@2.13.4 - amplify-frontend-ios@2.13.4 - amplify-migration-tests@2.17.3 - amplify-provider-awscloudformation@4.20.1 - amplify-util-mock@3.20.1 - graphql-auth-transformer@6.16.1 - graphql-connection-transformer@4.17.1 - graphql-dynamodb-transformer@6.18.1 - graphql-elasticsearch-transformer@4.7.1 - graphql-function-transformer@2.3.6 - graphql-http-transformer@4.15.6 - graphql-key-transformer@2.17.1 - graphql-predictions-transformer@2.3.6 - graphql-transformer-core@6.18.1 - graphql-transformers-e2e-tests@6.16.1 - graphql-versioned-transformer@4.15.6 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ba53fb245a..f38f6cea3b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3db699986b..5672fee192 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.2", + "version": "2.19.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.6", - "amplify-category-function": "2.20.2", + "amplify-category-auth": "2.15.7", + "amplify-category-function": "2.20.3", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.3", - "graphql-transformer-core": "6.18.0", + "graphql-transformer-core": "6.18.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 69bb7340fdbfedebce3e76823ceee7d507bd0637 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 2 Jun 2020 20:44:35 +0000 Subject: [PATCH 308/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.20.3 - amplify-category-api@2.19.4 - amplify-category-function@2.20.4 - amplify-category-predictions@2.3.10 - @aws-amplify/cli@4.21.1 - amplify-console-integration-tests@1.2.7 - amplify-e2e-core@1.1.5 - amplify-e2e-tests@2.18.1 - amplify-migration-tests@2.17.4 - amplify-provider-awscloudformation@4.20.2 - amplify-util-mock@3.20.2 - graphql-auth-transformer@6.17.0 - graphql-connection-transformer@4.17.2 - graphql-dynamodb-transformer@6.19.0 - graphql-elasticsearch-transformer@4.7.2 - graphql-function-transformer@2.3.7 - graphql-http-transformer@4.15.7 - graphql-key-transformer@2.18.0 - graphql-predictions-transformer@2.3.7 - graphql-relational-schema-transformer@2.15.4 - graphql-transformer-common@4.16.0 - graphql-transformer-core@6.18.2 - graphql-transformers-e2e-tests@6.17.0 - graphql-versioned-transformer@4.15.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f38f6cea3b..3fc150101a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5672fee192..b8d4aa9cd1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.3", + "version": "2.19.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,12 +16,12 @@ }, "dependencies": { "amplify-category-auth": "2.15.7", - "amplify-category-function": "2.20.3", + "amplify-category-function": "2.20.4", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.3", - "graphql-transformer-core": "6.18.1", + "graphql-relational-schema-transformer": "2.15.4", + "graphql-transformer-core": "6.18.2", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 277bb144ced321dddfb0d81acfd916e4df4a688d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 10 Jun 2020 00:53:19 +0000 Subject: [PATCH 309/587] chore(release): Publish [ci skip] - amplify-category-api@2.19.5 - amplify-category-function@2.20.5 - amplify-category-hosting@2.3.2 - amplify-category-predictions@2.3.11 - @aws-amplify/cli@4.21.2 - amplify-codegen-appsync-model-plugin@1.19.1 - amplify-codegen@2.15.10 - amplify-console-integration-tests@1.2.8 - amplify-e2e-core@1.1.6 - amplify-e2e-tests@2.18.2 - amplify-graphql-types-generator@2.3.5 - amplify-migration-tests@2.17.5 - amplify-nodejs-function-runtime-provider@1.0.5 - amplify-nodejs-function-template-provider@1.0.3 - amplify-provider-awscloudformation@4.20.3 - amplify-util-mock@3.21.0 - graphql-auth-transformer@6.18.0 - graphql-connection-transformer@4.18.0 - graphql-dynamodb-transformer@6.19.1 - graphql-elasticsearch-transformer@4.7.3 - graphql-function-transformer@2.3.8 - graphql-http-transformer@4.15.8 - graphql-key-transformer@2.19.0 - graphql-predictions-transformer@2.3.8 - graphql-relational-schema-transformer@2.15.5 - graphql-transformer-common@4.17.0 - graphql-transformer-core@6.19.0 - graphql-transformers-e2e-tests@6.18.0 - graphql-versioned-transformer@4.15.8 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3fc150101a..8bb246b94a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b8d4aa9cd1..bcd4bc8807 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.4", + "version": "2.19.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,12 +16,12 @@ }, "dependencies": { "amplify-category-auth": "2.15.7", - "amplify-category-function": "2.20.4", + "amplify-category-function": "2.20.5", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.4", - "graphql-transformer-core": "6.18.2", + "graphql-relational-schema-transformer": "2.15.5", + "graphql-transformer-core": "6.19.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From df1935c4a295f13e092fa6ef67c8d87bbb171dd5 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 11 Jun 2020 06:47:16 +0000 Subject: [PATCH 310/587] chore(release): Publish [ci skip] - amplify-app@2.17.2 - amplify-category-api@2.19.6 - amplify-category-function@2.20.6 - amplify-category-predictions@2.3.12 - @aws-amplify/cli@4.21.3 - amplify-console-integration-tests@1.2.9 - amplify-e2e-core@1.1.7 - amplify-e2e-tests@2.18.3 - amplify-frontend-ios@2.13.5 - amplify-migration-tests@2.17.6 - amplify-provider-awscloudformation@4.20.4 - amplify-util-mock@3.21.1 - graphql-auth-transformer@6.18.1 - graphql-connection-transformer@4.18.1 - graphql-dynamodb-transformer@6.19.2 - graphql-elasticsearch-transformer@4.7.4 - graphql-function-transformer@2.3.9 - graphql-http-transformer@4.15.9 - graphql-key-transformer@2.19.1 - graphql-predictions-transformer@2.3.9 - graphql-relational-schema-transformer@2.15.6 - graphql-transformer-common@4.17.1 - graphql-transformer-core@6.19.1 - graphql-transformers-e2e-tests@6.18.1 - graphql-versioned-transformer@4.15.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8bb246b94a..cb503159d5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index bcd4bc8807..07e4e8b314 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.5", + "version": "2.19.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,12 +16,12 @@ }, "dependencies": { "amplify-category-auth": "2.15.7", - "amplify-category-function": "2.20.5", + "amplify-category-function": "2.20.6", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.5", - "graphql-transformer-core": "6.19.0", + "graphql-relational-schema-transformer": "2.15.6", + "graphql-transformer-core": "6.19.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From cd2798a8cf01f592127ef0118a37722dfa8d5c26 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 17 Jun 2020 12:56:12 -0700 Subject: [PATCH 311/587] chore: fix additional spelling errors (#4596) * chore: fix additional spelling errors --- .../awscloudformation/service-walkthroughs/apigw-walkthrough.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index 7eecca9156..a3ba645994 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -635,7 +635,7 @@ function newLambdaFunction(context, path) { }, }; return add(context, 'awscloudformation', 'Lambda', params).then(resourceName => { - context.print.success('Succesfully added the Lambda function locally'); + context.print.success('Successfully added the Lambda function locally'); return { lambdaFunction: resourceName }; }); } From c0ac45ea9528eaa94c4f0d7cb210ec97f53d2ce1 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 18 Jun 2020 17:20:49 +0000 Subject: [PATCH 312/587] chore(release): Publish [ci skip] - amplify-app@2.17.3 - amplify-category-analytics@2.16.7 - amplify-category-api@2.19.7 - amplify-category-auth@2.15.8 - amplify-category-function@2.20.7 - amplify-category-hosting@2.3.3 - amplify-category-interactions@2.3.9 - amplify-category-notifications@2.15.8 - amplify-category-predictions@2.3.13 - amplify-category-storage@2.4.7 - amplify-category-xr@2.3.8 - @aws-amplify/cli@4.21.4 - amplify-codegen-appsync-model-plugin@1.19.2 - amplify-codegen@2.15.11 - amplify-console-hosting@1.3.3 - amplify-console-integration-tests@1.2.10 - amplify-dotnet-function-template-provider@1.2.1 - amplify-e2e-core@1.1.8 - amplify-e2e-tests@2.18.4 - amplify-migration-tests@2.17.7 - amplify-nodejs-function-template-provider@1.0.4 - amplify-provider-awscloudformation@4.21.0 - amplify-util-mock@3.21.2 - graphql-auth-transformer@6.18.2 - graphql-connection-transformer@4.18.2 - graphql-dynamodb-transformer@6.19.3 - graphql-elasticsearch-transformer@4.7.5 - graphql-function-transformer@2.3.10 - graphql-http-transformer@4.15.10 - graphql-key-transformer@2.19.2 - graphql-predictions-transformer@2.3.10 - graphql-relational-schema-transformer@2.15.7 - graphql-transformer-common@4.17.2 - graphql-transformer-core@6.19.2 - graphql-transformers-e2e-tests@6.18.2 - graphql-versioned-transformer@4.15.10 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index cb503159d5..213fd84e8b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 07e4e8b314..d73d068208 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.6", + "version": "2.19.7", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.7", - "amplify-category-function": "2.20.6", + "amplify-category-auth": "2.15.8", + "amplify-category-function": "2.20.7", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.6", - "graphql-transformer-core": "6.19.1", + "graphql-relational-schema-transformer": "2.15.7", + "graphql-transformer-core": "6.19.2", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From a1337eca9c577597ebfaeaaee8f61dc3079413e5 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 25 Jun 2020 20:13:38 +0000 Subject: [PATCH 313/587] chore(release): Publish [ci skip] - amplify-app@2.17.4 - amplify-category-api@2.19.8 - amplify-category-function@2.20.8 - amplify-category-predictions@2.3.14 - @aws-amplify/cli@4.22.0 - amplify-console-integration-tests@1.2.11 - amplify-e2e-core@1.1.9 - amplify-e2e-tests@2.18.5 - amplify-frontend-ios@2.13.6 - amplify-frontend-javascript@2.15.4 - amplify-migration-tests@2.17.8 - amplify-nodejs-function-runtime-provider@1.0.6 - amplify-provider-awscloudformation@4.21.1 - amplify-util-mock@3.21.3 - graphql-auth-transformer@6.18.3 - graphql-connection-transformer@4.18.3 - graphql-dynamodb-transformer@6.19.4 - graphql-elasticsearch-transformer@4.7.6 - graphql-function-transformer@2.3.11 - graphql-http-transformer@4.15.11 - graphql-key-transformer@2.19.3 - graphql-predictions-transformer@2.3.11 - graphql-relational-schema-transformer@2.15.8 - graphql-transformer-common@4.17.3 - graphql-transformer-core@6.19.3 - graphql-transformers-e2e-tests@6.18.3 - graphql-versioned-transformer@4.15.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 213fd84e8b..4872aa7840 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d73d068208..5897ba13f7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.7", + "version": "2.19.8", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,12 +16,12 @@ }, "dependencies": { "amplify-category-auth": "2.15.8", - "amplify-category-function": "2.20.7", + "amplify-category-function": "2.20.8", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.7", - "graphql-transformer-core": "6.19.2", + "graphql-relational-schema-transformer": "2.15.8", + "graphql-transformer-core": "6.19.3", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 5e081678466f91324dd1e9200c375458455c7c48 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 25 Jun 2020 14:33:15 -0700 Subject: [PATCH 314/587] feat(cli): usage measurement (#3641) --- .../commands/api/add-graphql-datasource.js | 5 +++-- packages/amplify-category-api/commands/api/add.js | 3 ++- packages/amplify-category-api/commands/api/console.js | 1 + packages/amplify-category-api/commands/api/gql-compile.js | 1 + packages/amplify-category-api/commands/api/push.js | 1 + packages/amplify-category-api/commands/api/remove.js | 1 + packages/amplify-category-api/commands/api/update.js | 1 + 7 files changed, 10 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/commands/api/add-graphql-datasource.js index 2290f6db06..502535dce1 100644 --- a/packages/amplify-category-api/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/commands/api/add-graphql-datasource.js @@ -86,7 +86,7 @@ module.exports = { answers.secretStoreArn, answers.dbClusterArn, answers.databaseName, - AWS + AWS, ); /** @@ -148,13 +148,14 @@ module.exports = { print.success('Some next steps:'); print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud' + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', ); print.info(''); }) .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the datasource'); + context.telemetry.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index cebc5de014..7e199ba9ef 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -30,13 +30,14 @@ module.exports = { print.success('Some next steps:'); print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud' + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', ); print.info(''); }) .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the API resource'); + context.telemetry.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index 6970d423e2..e487d884df 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -20,6 +20,7 @@ module.exports = { .catch(err => { context.print.error('Error opening console.'); context.print.info(err.message); + context.telemetry.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index 09564f5305..cc1b55a840 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -13,6 +13,7 @@ module.exports = { }); } catch (err) { context.print.error(err.toString()); + context.telemetry.emitError(err); } }, }; diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index 324b969e79..c25e80f69b 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -10,6 +10,7 @@ module.exports = { return amplify.pushResources(context, category, resourceName).catch(err => { context.print.error('There was an error pushing the API resource'); context.print.error(err.toString()); + context.telemetry.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index c6ae3c5c4d..aa4fcfefea 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -23,6 +23,7 @@ module.exports = { .catch(err => { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); + context.telemetry.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index 7c31d07468..3daba9911d 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -22,6 +22,7 @@ module.exports = { .catch(err => { context.print.error(err.message); console.log(err.stack); + context.telemetry.emitError(err); }); }, }; From e08dda4ca4aaadfadc2e807f7f1c5f74923e3304 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Mon, 29 Jun 2020 23:32:57 -0700 Subject: [PATCH 315/587] feat: Lambda layers (#4697) --- .../service-walkthroughs/apigw-walkthrough.js | 10 ++++++---- .../service-walkthroughs/appSync-walkthrough.js | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js index a3ba645994..488f0f1ead 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js @@ -1,6 +1,7 @@ const inquirer = require('inquirer'); const pathLib = require('path'); const fs = require('fs-extra'); +const { ServiceName: FunctionServiceName } = require('amplify-category-function'); const category = 'api'; const serviceName = 'API Gateway'; @@ -588,7 +589,7 @@ function functionsExist(context) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === 'Lambda') { + if (functionResources[resourceName].service === FunctionServiceName.LambdaFunction) { lambdaFunctions.push(resourceName); } }); @@ -634,8 +635,9 @@ function newLambdaFunction(context, path) { }, }, }; - return add(context, 'awscloudformation', 'Lambda', params).then(resourceName => { - context.print.success('Successfully added the Lambda function locally'); + + return add(context, 'awscloudformation', FunctionServiceName.LambdaFunction, params).then(resourceName => { + context.print.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; }); } @@ -650,7 +652,7 @@ async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === 'Lambda') { + if (functionResources[resourceName].service === FunctionServiceName.LambdaFunction) { lambdaFunctions.push(resourceName); } }); diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 8b2057083d..7f90276980 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -5,6 +5,7 @@ const uuid = require('uuid'); const path = require('path'); const open = require('open'); const TransformPackage = require('graphql-transformer-core'); +const { ServiceName: FunctionServiceName } = require('amplify-category-function'); const category = 'api'; const serviceName = 'AppSync'; @@ -338,7 +339,7 @@ async function createSyncFunction(context) { await context.amplify.copyBatch(context, copyJobs, functionProps, true); const backendConfigs = { - service: 'Lambda', + service: FunctionServiceName.LambdaFunction, providerPlugin: 'awscloudformation', build: true, }; From 90b1127895e698e4a365e360fe2cbcc9daaa822c Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Sun, 5 Jul 2020 16:43:32 -0700 Subject: [PATCH 316/587] Refactor/usage data (#4732) --- .../amplify-category-api/commands/api/add-graphql-datasource.js | 2 +- packages/amplify-category-api/commands/api/add.js | 2 +- packages/amplify-category-api/commands/api/console.js | 2 +- packages/amplify-category-api/commands/api/gql-compile.js | 2 +- packages/amplify-category-api/commands/api/push.js | 2 +- packages/amplify-category-api/commands/api/remove.js | 2 +- packages/amplify-category-api/commands/api/update.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/commands/api/add-graphql-datasource.js index 502535dce1..51c5880810 100644 --- a/packages/amplify-category-api/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/commands/api/add-graphql-datasource.js @@ -155,7 +155,7 @@ module.exports = { .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the datasource'); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/commands/api/add.js index 7e199ba9ef..efa1675d2d 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/commands/api/add.js @@ -37,7 +37,7 @@ module.exports = { .catch(err => { context.print.info(err.stack); context.print.error('There was an error adding the API resource'); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/commands/api/console.js index e487d884df..3296bc418b 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/commands/api/console.js @@ -20,7 +20,7 @@ module.exports = { .catch(err => { context.print.error('Error opening console.'); context.print.info(err.message); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/commands/api/gql-compile.js index cc1b55a840..a7d6f1a641 100644 --- a/packages/amplify-category-api/commands/api/gql-compile.js +++ b/packages/amplify-category-api/commands/api/gql-compile.js @@ -13,7 +13,7 @@ module.exports = { }); } catch (err) { context.print.error(err.toString()); - context.telemetry.emitError(err); + context.usageData.emitError(err); } }, }; diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/commands/api/push.js index c25e80f69b..06dcc8de26 100644 --- a/packages/amplify-category-api/commands/api/push.js +++ b/packages/amplify-category-api/commands/api/push.js @@ -10,7 +10,7 @@ module.exports = { return amplify.pushResources(context, category, resourceName).catch(err => { context.print.error('There was an error pushing the API resource'); context.print.error(err.toString()); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/commands/api/remove.js index aa4fcfefea..4a1df2b088 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/commands/api/remove.js @@ -23,7 +23,7 @@ module.exports = { .catch(err => { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/commands/api/update.js index 3daba9911d..1264a2ca42 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/commands/api/update.js @@ -22,7 +22,7 @@ module.exports = { .catch(err => { context.print.error(err.message); console.log(err.stack); - context.telemetry.emitError(err); + context.usageData.emitError(err); }); }, }; From f458c480a736bbbb985cb1dbfff8292daf91b82f Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 7 Jul 2020 07:24:28 +0000 Subject: [PATCH 317/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.21.0 - amplify-category-analytics@2.17.0 - amplify-category-api@2.20.0 - amplify-category-auth@2.16.0 - amplify-category-function@2.21.0 - amplify-category-hosting@2.4.0 - amplify-category-interactions@2.4.0 - amplify-category-notifications@2.15.9 - amplify-category-predictions@2.4.0 - amplify-category-storage@2.5.0 - amplify-category-xr@2.4.0 - @aws-amplify/cli@4.23.0 - amplify-codegen-appsync-model-plugin@1.20.0 - amplify-codegen@2.15.12 - amplify-console-hosting@1.4.0 - amplify-console-integration-tests@1.2.12 - amplify-dotnet-function-runtime-provider@1.2.0 - amplify-dotnet-function-template-provider@1.3.0 - amplify-e2e-core@1.2.0 - amplify-e2e-tests@2.19.0 - amplify-function-plugin-interface@1.4.0 - amplify-go-function-runtime-provider@1.2.0 - amplify-go-function-template-provider@1.2.0 - amplify-java-function-runtime-provider@1.2.0 - amplify-java-function-template-provider@1.2.0 - amplify-migration-tests@2.17.9 - amplify-nodejs-function-runtime-provider@1.1.0 - amplify-nodejs-function-template-provider@1.1.0 - amplify-provider-awscloudformation@4.22.0 - amplify-python-function-runtime-provider@1.2.0 - amplify-python-function-template-provider@1.2.0 - amplify-util-mock@3.22.0 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4872aa7840..97807208ca 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5897ba13f7..c18edc5789 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.19.8", + "version": "2.20.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.15.8", - "amplify-category-function": "2.20.8", + "amplify-category-auth": "2.16.0", + "amplify-category-function": "2.21.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From 936ee53860716545fb3cf11fd1b9ff914f9f614f Mon Sep 17 00:00:00 2001 From: Viljami Kuosmanen Date: Tue, 7 Jul 2020 21:30:25 +0200 Subject: [PATCH 318/587] fix: validatePathName_validPath matcher (#4559) --- .../provider-utils/__tests__/apigw-walkthroughs.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js index 2f25657178..0a4f81cac5 100644 --- a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js +++ b/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js @@ -6,8 +6,8 @@ const validatePathName = walkthrough.__get__('validatePathName'); const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }]; test('validatePathName_validPath', () => { - expect(validatePathName('/some/path', stubOtherPaths)).toBeTruthy(); - expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBeTruthy(); + expect(validatePathName('/some/path', stubOtherPaths)).toBe(true); + expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBe(true); }); test('validatePath_empty', () => { From 59f3ce7465b634d08648a3de5a50ab23bef63c9a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 9 Jul 2020 20:24:13 +0000 Subject: [PATCH 319/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.1 - amplify-category-api@2.20.1 - amplify-category-auth@2.16.1 - amplify-category-function@2.21.1 - amplify-category-interactions@2.4.1 - amplify-category-notifications@2.15.10 - amplify-category-predictions@2.4.1 - amplify-category-storage@2.5.1 - amplify-category-xr@2.4.1 - @aws-amplify/cli@4.23.1 - amplify-provider-awscloudformation@4.22.1 - amplify-util-mock@3.22.1 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 97807208ca..8a9eb9e8e2 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c18edc5789..a2e2674a4d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.0", + "version": "2.20.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.16.0", - "amplify-category-function": "2.21.0", + "amplify-category-auth": "2.16.1", + "amplify-category-function": "2.21.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From ae49ffcd845ae5047366d6b501321ce55f81c4a8 Mon Sep 17 00:00:00 2001 From: Sebastian Crossa Date: Thu, 9 Jul 2020 15:05:10 -0600 Subject: [PATCH 320/587] fix(cli): remove unnecessary stack trace log when adding services (#4610) --- packages/amplify-category-api/index.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 6099279fdd..2796a3c516 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -22,7 +22,7 @@ async function migrate(context, serviceName) { if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( - providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName) + providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName), ); } } @@ -149,7 +149,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { context, amplifyMeta[category][resourceName].service, resourceName, - resourceOpsMapping[resourceName] + resourceOpsMapping[resourceName], ); permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); @@ -171,7 +171,6 @@ async function executeAmplifyCommand(context) { } else { commandPath = path.join(commandPath, category, context.input.command); } - const commandModule = require(commandPath); await commandModule.run(context); } From ab69fc3c2684e7495ffb9e847e9bf2def65589f9 Mon Sep 17 00:00:00 2001 From: UnleashedMind Date: Fri, 10 Jul 2020 14:05:09 -0700 Subject: [PATCH 321/587] Revert problematic PRs (#4803) * feat(amplify-provider-awscloudformation): add region ca-central-1 * fix test * Revert "Add region ca-central-1 (#4796)" This reverts commit af29f359f14989fdc89112e96ebed08644296914. * Revert "feat: add check for extra command line args provided with amplify delete (#4576)" This reverts commit 48b27b79698b33ee62a01df2ad00b701f79029d8. * Revert "perf: fulfill promises to upload files to S3 concurrently (#4575)" This reverts commit 9fbee8a71b4bf941dbda9d2f76fbedd73ab754ef. * Revert "fix(cli): remove unnecessary stack trace log when adding services (#4610)" This reverts commit ae49ffcd845ae5047366d6b501321ce55f81c4a8. * Revert "fix test" This reverts commit 50a8073fbbdb56931191912938fb50f542197832. Co-authored-by: UnleashedMind --- packages/amplify-category-api/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/index.js index 2796a3c516..6099279fdd 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/index.js @@ -22,7 +22,7 @@ async function migrate(context, serviceName) { if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( - providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName), + providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName) ); } } @@ -149,7 +149,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { context, amplifyMeta[category][resourceName].service, resourceName, - resourceOpsMapping[resourceName], + resourceOpsMapping[resourceName] ); permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); @@ -171,6 +171,7 @@ async function executeAmplifyCommand(context) { } else { commandPath = path.join(commandPath, category, context.input.command); } + const commandModule = require(commandPath); await commandModule.run(context); } From d878817925ade99ececed04484dd78f9b0b680f0 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 11 Jul 2020 01:19:05 +0000 Subject: [PATCH 322/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.2 - amplify-category-api@2.20.2 - amplify-category-auth@2.16.2 - amplify-category-function@2.21.2 - amplify-category-interactions@2.4.2 - amplify-category-notifications@2.15.11 - amplify-category-predictions@2.4.2 - amplify-category-storage@2.5.2 - amplify-category-xr@2.4.2 - @aws-amplify/cli@4.24.0 - amplify-console-integration-tests@1.2.13 - amplify-e2e-core@1.2.1 - amplify-e2e-tests@2.19.1 - amplify-migration-tests@2.17.10 - amplify-provider-awscloudformation@4.22.2 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8a9eb9e8e2..9bab999b60 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a2e2674a4d..72e0d81224 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.1", + "version": "2.20.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.16.1", - "amplify-category-function": "2.21.1", + "amplify-category-auth": "2.16.2", + "amplify-category-function": "2.21.2", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From e161a36b5685398b44b6001bf0c810ad0e323bc1 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 14 Jul 2020 03:00:06 +0000 Subject: [PATCH 323/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.3 - amplify-category-api@2.20.3 - amplify-category-auth@2.16.3 - amplify-category-function@2.21.3 - amplify-category-interactions@2.4.3 - amplify-category-notifications@2.15.12 - amplify-category-predictions@2.4.3 - amplify-category-storage@2.5.3 - amplify-category-xr@2.4.3 - @aws-amplify/cli@4.24.1 - amplify-provider-awscloudformation@4.22.3 - amplify-python-function-runtime-provider@1.2.1 - amplify-util-mock@3.22.2 - graphql-auth-transformer@6.18.4 - graphql-transformers-e2e-tests@6.18.4 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9bab999b60..fad05c5a77 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 72e0d81224..9246c1dca2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.2", + "version": "2.20.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,8 +15,8 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.16.2", - "amplify-category-function": "2.21.2", + "amplify-category-auth": "2.16.3", + "amplify-category-function": "2.21.3", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From 6c980fa4e6e535d6e8224ffa419b788512064dd1 Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Tue, 14 Jul 2020 13:03:09 -0700 Subject: [PATCH 324/587] fix(graphql-auth-transformer): add a time delay when creating apiKey (#4493) --- .../service-walkthroughs/appSync-walkthrough.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js index 7f90276980..28884c4859 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js @@ -779,6 +779,8 @@ async function askApiKeyQuestions() { message: 'After how many days from now the API key should expire (1-365):', default: 7, validate: validateDays, + // adding filter to ensure parsing input as int -> https://github.com/SBoudrias/Inquirer.js/issues/866 + filter: value => (isNaN(parseInt(value, 10)) ? value : parseInt(value, 10)), }, ]; @@ -833,7 +835,6 @@ async function askOpenIDConnectQuestions() { function validateDays(input) { const isValid = /^\d+$/.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.'; } From a6afe16f46324d635b2d96b61fca924d8a7fd8a1 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 15 Jul 2020 22:37:55 +0000 Subject: [PATCH 325/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.4 - amplify-category-api@2.20.4 - amplify-category-auth@2.16.4 - amplify-category-function@2.21.4 - amplify-category-interactions@2.4.4 - amplify-category-notifications@2.15.13 - amplify-category-predictions@2.4.4 - amplify-category-storage@2.5.4 - amplify-category-xr@2.4.4 - @aws-amplify/cli@4.24.2 - amplify-codegen@2.15.13 - amplify-console-hosting@1.4.1 - amplify-console-integration-tests@1.2.14 - amplify-e2e-core@1.2.2 - amplify-e2e-tests@2.19.2 - amplify-migration-tests@2.17.11 - amplify-provider-awscloudformation@4.22.4 - amplify-util-mock@3.22.3 - graphql-auth-transformer@6.18.5 - graphql-connection-transformer@4.18.4 - graphql-dynamodb-transformer@6.19.5 - graphql-elasticsearch-transformer@4.7.7 - graphql-function-transformer@2.3.12 - graphql-http-transformer@4.15.12 - graphql-key-transformer@2.19.4 - graphql-predictions-transformer@2.3.12 - graphql-relational-schema-transformer@2.15.9 - graphql-transformer-common@4.17.4 - graphql-transformer-core@6.19.4 - graphql-transformers-e2e-tests@6.18.5 - graphql-versioned-transformer@4.15.12 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fad05c5a77..4347c30ba1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9246c1dca2..a412db4716 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.3", + "version": "2.20.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.16.3", - "amplify-category-function": "2.21.3", + "amplify-category-auth": "2.16.4", + "amplify-category-function": "2.21.4", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.8", - "graphql-transformer-core": "6.19.3", + "graphql-relational-schema-transformer": "2.15.9", + "graphql-transformer-core": "6.19.4", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 3d62735eb73321868e6932bd877375e354ae44ee Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 18 Jul 2020 23:50:31 +0000 Subject: [PATCH 326/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.21.1 - amplify-category-analytics@2.17.5 - amplify-category-api@2.20.5 - amplify-category-auth@2.16.5 - amplify-category-function@2.21.5 - amplify-category-interactions@2.4.5 - amplify-category-notifications@2.15.14 - amplify-category-predictions@2.4.5 - amplify-category-storage@2.5.5 - amplify-category-xr@2.4.5 - @aws-amplify/cli@4.24.3 - amplify-console-integration-tests@1.2.15 - amplify-e2e-core@1.2.3 - amplify-e2e-tests@2.19.3 - amplify-migration-tests@2.17.12 - amplify-provider-awscloudformation@4.22.5 - amplify-util-mock@3.22.4 - graphql-auth-transformer@6.18.6 - graphql-connection-transformer@4.18.5 - graphql-dynamodb-transformer@6.19.6 - graphql-elasticsearch-transformer@4.7.8 - graphql-function-transformer@2.3.13 - graphql-http-transformer@4.15.13 - graphql-key-transformer@2.19.5 - graphql-mapping-template@4.13.5 - graphql-predictions-transformer@2.3.13 - graphql-relational-schema-transformer@2.15.10 - graphql-transformer-common@4.17.5 - graphql-transformer-core@6.19.5 - graphql-transformers-e2e-tests@6.18.6 - graphql-versioned-transformer@4.15.13 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4347c30ba1..fa39ec5156 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a412db4716..0c17b04768 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.4", + "version": "2.20.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -15,13 +15,13 @@ "test-ci": "jest --ci -i" }, "dependencies": { - "amplify-category-auth": "2.16.4", - "amplify-category-function": "2.21.4", + "amplify-category-auth": "2.16.5", + "amplify-category-function": "2.21.5", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.9", - "graphql-transformer-core": "6.19.4", + "graphql-relational-schema-transformer": "2.15.10", + "graphql-transformer-core": "6.19.5", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 7d6104753cdf6a1a9cf576f9704a269427e8c457 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Tue, 21 Jul 2020 09:43:05 -0700 Subject: [PATCH 327/587] feat: headless mode for API category (#4834) Add / update / remove AppSync resources headlessly (intentionally not documented yet) --- .../__tests__/apigw-walkthrough.test.js | 6 - packages/amplify-category-api/package.json | 10 +- .../appsync-schemas/basic-schema.graphql.ejs | 7 - .../single-object-auth-schema.graphql | 19 - ...ync-cloudformation-template-custom.yml.ejs | 182 ------ ...nc-cloudformation-template-default.yml.ejs | 542 ------------------ .../provider-utils/awscloudformation/index.js | 177 ------ .../defaultCustomResources.json | 61 -- .../provider-utils/supported-datasources.json | 36 -- .../provider-utils/supported-services.json | 157 ----- ...w-cloudformation-template-default.json.ejs | 0 .../defaultCustomResources.json | 58 ++ .../many-relationship-schema.graphql | 0 .../single-object-auth-schema.graphql | 17 + .../single-object-schema.graphql | 2 +- .../sync-conflict-handler-index.js.ejs | 0 .../sync-conflict-handler-package.json.ejs | 0 .../sync-conflict-handler-template.json.ejs | 0 .../cfn-api-artifact-handler.test.ts.snap | 51 ++ .../cfn-api-artifact-handler.test.ts | 225 ++++++++ .../apigw-walkthrough.test.ts | 6 + ...p-sync-auth-type-bi-di-mapper.test.ts.snap | 71 +++ ...flict-resolution-bi-di-mapper.test.ts.snap | 45 ++ ...ugh-result-to-add-api-request.test.ts.snap | 21 + ...to-app-sync-auth-type-bi-di-mapper.test.ts | 102 ++++ ...o-conflict-resolution-bi-di-mapper.test.ts | 72 +++ .../utils/rest-api-path-utils.test.ts} | 9 +- ...kthrough-result-to-add-api-request.test.ts | 28 + .../src/category-constants.ts | 1 + .../{ => src}/commands/api.js | 0 .../commands/api/add-graphql-datasource.js | 2 +- .../{ => src}/commands/api/add.js | 2 +- .../{ => src}/commands/api/console.js | 2 +- .../{ => src}/commands/api/gql-compile.js | 0 .../{ => src}/commands/api/push.js | 0 .../{ => src}/commands/api/remove.js | 1 + .../{ => src}/commands/api/update.js | 2 +- .../{index.js => src/index.ts} | 46 +- .../provider-utils/api-artifact-handler.ts | 6 + .../awscloudformation/aws-constants.ts | 8 + .../cfn-api-artifact-handler.ts | 262 +++++++++ .../default-values/apigw-defaults.js | 0 .../default-values/appSync-defaults.js | 0 .../provider-utils/awscloudformation/index.ts | 95 +++ .../awscloudformation/legacy-add-resource.ts | 69 +++ .../legacy-update-resource.ts | 35 ++ .../apigw-walkthrough.ts} | 106 +--- .../appSync-rds-walkthrough.js | 4 +- .../appSync-walkthrough.ts} | 495 ++++------------ .../syncAssets.js | 8 +- .../utils/amplify-meta-utils.ts | 40 ++ ...nfig-to-app-sync-auth-type-bi-di-mapper.ts | 79 +++ .../utils/dynamic-imports.ts | 4 + .../utils/edit-schema-flow.ts | 18 + ...fig-to-conflict-resolution-bi-di-mapper.ts | 105 ++++ .../utils/rest-api-path-utils.ts | 37 ++ ...e-walkthrough-result-to-add-api-request.ts | 18 + .../provider-utils/supported-datasources.ts | 36 ++ .../src/provider-utils/supported-services.ts | 152 +++++ .../amplify-category-api/templates/api.ejs | 382 ------------ packages/amplify-category-api/tsconfig.json | 19 + 61 files changed, 1865 insertions(+), 2073 deletions(-) delete mode 100644 packages/amplify-category-api/__tests__/apigw-walkthrough.test.js delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/index.js delete mode 100644 packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json delete mode 100644 packages/amplify-category-api/provider-utils/supported-datasources.json delete mode 100644 packages/amplify-category-api/provider-utils/supported-services.json rename packages/amplify-category-api/{provider-utils => resources}/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs (100%) create mode 100644 packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json rename packages/amplify-category-api/{provider-utils/awscloudformation/appsync-schemas => resources/awscloudformation/graphql-schemas}/many-relationship-schema.graphql (100%) create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql rename packages/amplify-category-api/{provider-utils/awscloudformation/appsync-schemas => resources/awscloudformation/graphql-schemas}/single-object-schema.graphql (97%) rename packages/amplify-category-api/{provider-utils/awscloudformation/sync-conflict-handler-assets => resources/awscloudformation/sync-conflict-handler}/sync-conflict-handler-index.js.ejs (100%) rename packages/amplify-category-api/{provider-utils/awscloudformation/sync-conflict-handler-assets => resources/awscloudformation/sync-conflict-handler}/sync-conflict-handler-package.json.ejs (100%) rename packages/amplify-category-api/{provider-utils/awscloudformation/sync-conflict-handler-assets => resources/awscloudformation/sync-conflict-handler}/sync-conflict-handler-template.json.ejs (100%) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts create 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 create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts rename packages/amplify-category-api/{provider-utils/__tests__/apigw-walkthroughs.test.js => src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts} (86%) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts create mode 100644 packages/amplify-category-api/src/category-constants.ts rename packages/amplify-category-api/{ => src}/commands/api.js (100%) rename packages/amplify-category-api/{ => src}/commands/api/add-graphql-datasource.js (98%) rename packages/amplify-category-api/{ => src}/commands/api/add.js (92%) rename packages/amplify-category-api/{ => src}/commands/api/console.js (87%) rename packages/amplify-category-api/{ => src}/commands/api/gql-compile.js (100%) rename packages/amplify-category-api/{ => src}/commands/api/push.js (100%) rename packages/amplify-category-api/{ => src}/commands/api/remove.js (88%) rename packages/amplify-category-api/{ => src}/commands/api/update.js (88%) rename packages/amplify-category-api/{index.js => src/index.ts} (83%) create mode 100644 packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts rename packages/amplify-category-api/{ => src}/provider-utils/awscloudformation/default-values/apigw-defaults.js (100%) rename packages/amplify-category-api/{ => src}/provider-utils/awscloudformation/default-values/appSync-defaults.js (100%) create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts rename packages/amplify-category-api/{provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js => src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts} (87%) rename packages/amplify-category-api/{ => src}/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js (99%) rename packages/amplify-category-api/{provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js => src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts} (54%) rename packages/amplify-category-api/{ => src}/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js (90%) create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts create mode 100644 packages/amplify-category-api/src/provider-utils/supported-datasources.ts create mode 100644 packages/amplify-category-api/src/provider-utils/supported-services.ts delete mode 100644 packages/amplify-category-api/templates/api.ejs create mode 100644 packages/amplify-category-api/tsconfig.json diff --git a/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js b/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js deleted file mode 100644 index 49c8d5e0da..0000000000 --- a/packages/amplify-category-api/__tests__/apigw-walkthrough.test.js +++ /dev/null @@ -1,6 +0,0 @@ -const { getIAMPolicies } = require('../provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough'); - -test('getIAMPolicies', () => { - output = getIAMPolicies('resourceName', ['read']) - expect(output.attributes).toStrictEqual(['ApiName', 'ApiId']) -}) \ No newline at end of file diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0c17b04768..83051ceb03 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -9,14 +9,17 @@ }, "author": "Amazon Web Services", "license": "Apache-2.0", - "main": "index.js", + "main": "lib/index.js", "scripts": { + "build": "tsc", + "clean": "rimraf lib tsconfig.tsbuildinfo", "test": "jest", "test-ci": "jest --ci -i" }, "dependencies": { "amplify-category-auth": "2.16.5", "amplify-category-function": "2.21.5", + "amplify-util-headless-input": "1.0.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", @@ -28,15 +31,12 @@ "ora": "^4.0.3", "uuid": "^3.4.0" }, - "devDependencies": { - "rewire": "^4.0.1" - }, "jest": { "testURL": "http://localhost", "transform": { "^.+\\.tsx?$": "ts-jest" }, - "testRegex": "(.*/__tests__/.*.test.(js|ts))$", + "testRegex": "(src/__tests__/.*.test.ts)$", "moduleFileExtensions": [ "ts", "tsx", diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs deleted file mode 100644 index eeb1032c39..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/basic-schema.graphql.ejs +++ /dev/null @@ -1,7 +0,0 @@ -type <%= props.typeName %> @model { - id: ID! - title: String! - content: String! - price: Int - rating: Float -} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql b/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql deleted file mode 100644 index 16a419d6f3..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-auth-schema.graphql +++ /dev/null @@ -1,19 +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! -} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs deleted file mode 100644 index 23d9590a11..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-custom.yml.ejs +++ /dev/null @@ -1,182 +0,0 @@ ---- -<%if (props.dependsOn && props.dependsOn.length > 0) { %> -Parameters: -<% 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] %> -<% } %> -<% } %> -<% } %> - -Resources: - GraphQLApi: - Type: "AWS::AppSync::GraphQLApi" - Properties: - Name: <%= props.apiName %> - <%if (props.securitySetting.type == 'iam') { %> - AuthenticationType: AWS_IAM - <% } %> - <%if (props.securitySetting.type == 'apiKey') { %> - AuthenticationType: API_KEY - <% } %> - <%if (props.securitySetting.type == 'cognito') { %> - AuthenticationType: AMAZON_COGNITO_USER_POOLS - UserPoolConfig: - AwsRegion: <%= props.securitySetting.options.cognitoUserPoolRegion %> - UserPoolId: <%= props.securitySetting.options.cognitoUserPoolId %> - DefaultAction: <%= props.securitySetting.options.cognitoAction %> - <%if (props.securitySetting.options.appClientRegex) { %> - AppIdClientRegex: <%= props.securitySetting.options.appClientRegex %> - <% } %> - <% } %> - <%if (props.securitySetting.type == 'openId') { %> - AuthenticationType: OPENID_CONNECT - OpenIDConnectConfig: - Issuer: <%= props.securitySetting.options.openIdUrl %> - <%if (props.securitySetting.options.clientId) { %> - ClientId: <%= props.securitySetting.options.clientId %> - <% } %> - <%if (props.securitySetting.options.issueTTL) { %> - IatTTL: <%= props.securitySetting.options.issueTTL %> - <% } %> - <%if (props.securitySetting.options.authTTL) { %> - AuthTTL: <%= props.securitySetting.options.authTTL %> - <% } %> - <% } %> - - <%if (props.securitySetting.type == 'apiKey') { %> - AppSyncApiKey: - Type: "AWS::AppSync::ApiKey" - Properties: - Expires: <%= props.securitySetting.options.apiKeyExpiryDays %> - ApiId: !GetAtt GraphQLApi.ApiId - <% } %> - - ServiceRole: - Type: 'AWS::IAM::Role' - Properties: - RoleName: <%= props.serviceRoleName %> - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Sid: '' - Effect: Allow - Principal: - Service: appsync.amazonaws.com - Action: 'sts:AssumeRole' - <%if (props.dataSources && props.dataSources.dynamoDb) { %> - ServicePolicyDynamo: - Type: 'AWS::IAM::Policy' - Properties: - PolicyName: <%= props.servicePolicyName %> - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - 'dynamodb:Query' - - 'dynamodb:BatchWriteItem' - - 'dynamodb:GetItem' - - 'dynamodb:DeleteItem' - - 'dynamodb:PutItem' - - 'dynamodb:Scan' - - 'dynamodb:UpdateItem' - Resource: - <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> - <%if (props.dataSources.dynamoDb[i].Arn) { %> - - <%= props.dataSources.dynamoDb[i].Arn %> - <% } else{ %> - - !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Arn - <% } %> - <% } %> - Roles: - - !Ref ServiceRole - <% } %> - - <%if (props.dataSources && props.dataSources.lambda) { %> - ServicePolicyLambda: - Type: 'AWS::IAM::Policy' - Properties: - PolicyName: <%= props.servicePolicyName %> - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - 'lambda:invokeFunction' - Resource: - <% for(var i=0; i < props.dataSources.lambda.length; i++) { %> - <%if (props.dataSources.lambda[i].Arn) { %> - - <%= props.dataSources.lambda[i].Arn %> - <% } else{ %> - - !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn - <% } %> - <% } %> - Roles: - - !Ref ServiceRole - <% } %> - - <%if (props.dataSources && props.dataSources.dynamoDb) { %> - <% for(var i=0; i < props.dataSources.dynamoDb.length; i++) { %> - <%= props.dataSources.dynamoDb[i].resourceName %>DataSource: - Type: "AWS::AppSync::DataSource" - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - <%if (props.dataSources.dynamoDb[i].Arn) { %> - Name: <%= props.dataSources.dynamoDb[i].resourceName %> - <% } else { %> - Name: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name - <% } %> - ServiceRoleArn: !GetAtt ServiceRole.Arn - Type: AMAZON_DYNAMODB - DynamoDBConfig: - <%if (props.dataSources.dynamoDb[i].Arn) { %> - AwsRegion: <%= props.dataSources.dynamoDb[i].region %> - TableName: <%= props.dataSources.dynamoDb[i].TableName %> - <% } else { %> - AwsRegion: <%= props.region %> - TableName: !Ref <%= props.dataSources.dynamoDb[i].category %><%= props.dataSources.dynamoDb[i].resourceName %>Name - <% } %> - <% } %> - <% } %> - - <%if (props.dataSources && props.dataSources.lambda) { %> - <% for(var i=0; i < props.dataSources.lambda.length; i++) { %> - <%= props.dataSources.lambda[i].resourceName %>DataSource: - Type: "AWS::AppSync::DataSource" - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - <%if (props.dataSources.lambda[i].Arn) { %> - Name: <%= props.dataSources.lambda[i].resourceName %> - <% } else { %> - Name: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Name - <% } %> - ServiceRoleArn: !GetAtt ServiceRole.Arn - Type: AWS_LAMBDA - LambdaConfig: - <%if (props.dataSources.lambda[i].Arn) { %> - LambdaFunctionArn: <%= props.dataSources.lambda[i].Arn %> - <% } else { %> - LambdaFunctionArn: !Ref <%= props.dataSources.lambda[i].category %><%= props.dataSources.lambda[i].resourceName %>Arn - <% } %> - <% } %> - <% } %> - -Outputs: - Region: - Value: !Ref 'AWS::Region' - GraphQLApiARN: - Description: The App ID of the GraphQL endpoint. - Value: !Ref GraphQLApi - GraphQLApiId: - Description: The App ID of the GraphQL endpoint. - Value: !GetAtt GraphQLApi.ApiId - GraphQLApiEndpoint: - Description: The URL for the GraphQL endpoint. - Value: !GetAtt GraphQLApi.GraphQLUrl - <%if (props.securitySetting.type == 'apiKey') { %> - ApiKey: - Value: !GetAtt AppSyncApiKey.ApiKey - <% } %> diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs b/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs deleted file mode 100644 index 09f10cc0f1..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/appSync-cloudformation-template-default.yml.ejs +++ /dev/null @@ -1,542 +0,0 @@ ---- -Description: AWSAppSync DynamoDB Example -Resources: - GraphQLApi: - Type: "AWS::AppSync::GraphQLApi" - Properties: - Name: <%= props.apiName %> - AuthenticationType: AWS_IAM - - ServiceRole: - Type: 'AWS::IAM::Role' - Properties: - RoleName: <%= props.serviceRoleName %> - AssumeRolePolicyDocument: - Version: 2012-10-17 - Statement: - - Sid: '' - Effect: Allow - Principal: - Service: appsync.amazonaws.com - Action: 'sts:AssumeRole' - - DynamoDbTable: - Type: 'AWS::DynamoDB::Table' - Properties: - AttributeDefinitions: - - AttributeName: id - AttributeType: S - KeySchema: - - AttributeName: id - KeyType: HASH - ProvisionedThroughput: - ReadCapacityUnits: '5' - WriteCapacityUnits: '5' - TableName: <%= props.defaultTableName %> - - ServicePolicy: - Type: 'AWS::IAM::Policy' - Properties: - PolicyName: <%= props.servicePolicyName %> - PolicyDocument: - Version: 2012-10-17 - Statement: - - Effect: Allow - Action: - - 'dynamodb:Query' - - 'dynamodb:BatchWriteItem' - - 'dynamodb:GetItem' - - 'dynamodb:DeleteItem' - - 'dynamodb:PutItem' - - 'dynamodb:Scan' - - 'dynamodb:UpdateItem' - Resource: - - !GetAtt DynamoDbTable.Arn - Roles: - - !Ref ServiceRole - - PostDynamoDBTableDataSource: - Type: "AWS::AppSync::DataSource" - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - Name: PostDynamoDBTable - Description: The Post DynamoDB table in <%= props.region %> - Type: AMAZON_DYNAMODB - ServiceRoleArn: !GetAtt ServiceRole.Arn - DynamoDBConfig: - AwsRegion: <%= props.region %> - TableName: !Ref DynamoDbTable - - QueryGetPostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Query - FieldName: getPost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "GetItem", - "key" : { - "id" : $util.dynamodb.toDynamoDBJson($ctx.args.id) - } - } - ResponseMappingTemplate: "$utils.toJson($ctx.result)" - - QueryAllPostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Query - FieldName: allPost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "Scan", - #if( $ctx.args.count ) - "limit": $ctx.args.count, - #end - #if( ${ctx.args.nextToken} ) - "nextToken": "${ctx.args.nextToken}" - #end - } - ResponseMappingTemplate: | - { - "posts": $utils.toJson($ctx.result.items), - #if( ${ctx.result.nextToken} ) - "nextToken": "${ctx.result.nextToken}", - #end - }ctx - QueryAllPostsByAuthorResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Query - FieldName: allPostsByAuthor - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "Query", - "index" : "author-index", - "query" : { - "expression": "author = :author", - "expressionValues" : { - ":author" : $util.dynamodb.toDynamoDBJson($ctx.args.author) - } - }, - #if( $ctx.args.count ) - "limit": $ctx.args.count, - #end - #if( ${ctx.args.nextToken} ) - "nextToken": "${ctx.args.nextToken}", - #end - } - ResponseMappingTemplate: | - { - "posts": $utils.toJson($ctx.result.items), - #if( ${ctx.result.nextToken} ) - "nextToken": "${ctx.result.nextToken}", - #end - } - QueryAllPostsByTagResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Query - FieldName: allPostsByTag - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "Scan", - "filter": { - "expression": "contains (tags, :tag)", - "expressionValues": { - ":tag": $util.dynamodb.toStringJson($ctx.args.tag) - } - }, - #if( $ctx.args.count ) - "limit": $ctx.args.count, - #end - #if( ${ctx.args.nextToken} ) - "nextToken": "${ctx.args.nextToken}" - #end - } - ResponseMappingTemplate: | - { - "posts": $utils.toJson($ctx.result.items), - #if( ${ctx.result.nextToken} ) - "nextToken": "${ctx.result.nextToken}", - #end - } - MutationaddPostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: addPost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - #set( $d = $util.dynamodb ) - #set( $values = $d.toMapValues($ctx.args)) - $!{values.put("ups", $d.toNumber(1))} - $!{values.put("downs", $d.toNumber(0))} - $!{values.put("version", $d.toNumber(1))} - $!{values.put("created", $d.toDynamoDB($util.time.nowISO8601()))} - $!{values.put("lastUpdated", $values.get("created"))} - { - "version" : "2017-02-28", - "operation" : "PutItem", - "key" : { - "id" : $d.toStringJson($utils.autoId()) - }, - "attributeValues" : $util.toJson($values), - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationAddCommentResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: addComment - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $util.dynamodb.toStringJson($ctx.args.id) - }, - "update" : { - "expression" : "SET comments = list_append(if_not_exists(comments, :emptyList), :newComment), lastUpdated = :lastUpdated ADD version :plusOne", - "expressionValues" : { - ":emptyList": $util.dynamodb.toListJson([]), - ":newComment" : $util.dynamodb.toListJson([$util.map.copyAndRetainAllKeys($ctx.args, ["author","comment"])]), - ":plusOne" : $util.dynamodb.toNumberJson(1), - ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()) - } - }, - "condition" : { - "expression" : "attribute_exists(id)" - }, - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationAddTagResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: addTag - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $util.dynamodb.toStringJson($ctx.args.id) - }, - "update" : { - "expression" : "ADD tags :tags, version :plusOne SET lastUpdated = :lastUpdated", - "expressionValues" : { - ":tags" : $util.dynamodb.toStringSetJson([$ctx.args.tag]), - ":plusOne" : $util.dynamodb.toNumberJson(1), - ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), - } - }, - "condition" : { - "expression" : "attribute_exists(id)" - }, - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationRemoveTagResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: removeTag - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $util.dynamodb.toStringJson($ctx.args.id) - }, - "update" : { - "expression" : "DELETE tags :tags ADD version :plusOne SET lastUpdated = :lastUpdated", - "expressionValues" : { - ":tags" : $util.dynamodb.toStringSetJson([$ctx.args.tag]), - ":plusOne" : $util.dynamodb.toNumberJson(1), - ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), - } - }, - "condition" : { - "expression" : "attribute_exists(id)" - }, - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationDeletePostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: deletePost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "DeleteItem", - "key": { - "id": $util.dynamodb.toStringJson($ctx.args.id) - }, - #if( $ctx.args.containsKey("expectedVersion") ) - "condition" : { - "expression" : "attribute_not_exists(id) OR version = :expectedVersion", - "expressionValues" : { - ":expectedVersion" : $util.dynamodb.toNumberJson($ctx.args.expectedVersion) - } - }, - #end - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationUpvotePostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: upvotePost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $util.dynamodb.toStringJson($ctx.args.id) - }, - "update" : { - "expression" : "ADD ups :plusOne, version :plusOne SET lastUpdated = :lastUpdated", - "expressionValues" : { - ":plusOne" : $util.dynamodb.toNumberJson(1), - ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()) - } - }, - "condition" : { - "expression" : "attribute_exists(id)" - }, - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationDownvotePostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: downvotePost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $util.dynamodb.toStringJson($ctx.args.id) - }, - "update" : { - "expression" : "ADD downs :plusOne, version :plusOne SET lastUpdated = :lastUpdated", - "expressionValues" : { - ":plusOne" : $util.dynamodb.toNumberJson(1), - ":lastUpdated" : $util.dynamodb.toDynamoDBJson($util.time.nowISO8601()), - } - }, - "condition" : { - "expression" : "attribute_exists(id)" - }, - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - MutationUpdatePostResolver: - Type: "AWS::AppSync::Resolver" - DependsOn: Schema - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - TypeName: Mutation - FieldName: updatePost - DataSourceName: !GetAtt PostDynamoDBTableDataSource.Name - RequestMappingTemplate: | - #set( $ddb = $util.dynamodb ) - { - "version" : "2017-02-28", - "operation" : "UpdateItem", - "key" : { - "id" : $ddb.toDynamoDBJson($ctx.args.id) - }, - ## Set up some space to keep track of things we're updating ** - #set( $expNames = {} ) - #set( $expValues = {} ) - #set( $expSet = {} ) - #set( $expAdd = {} ) - #set( $expRemove = [] ) - ## Increment "version" by 1 ** - $!{expAdd.put("version", ":one")} - $!{expValues.put(":one", $ddb.toDynamoDB(1))} - ## Set the "lastUpdated" timestamp ** - $!{expSet.put("lastUpdated", ":lastUpdated")} - $!{expValues.put(":lastUpdated", $ddb.toDynamoDB($util.time.nowISO8601()))} - ## Iterate through each argument, skipping "id" and "expectedVersion" ** - #foreach( $entry in $util.map.copyAndRemoveAllKeys($ctx.args, ["id","expectedVersion"]).entrySet() ) - #if( $util.isNull($entry.value) ) - ## If the argument is set to "null", then remove that attribute from the item in DynamoDB ** - #set( $discard = ${expRemove.add("#${entry.key}")} ) - $!{expNames.put("#${entry.key}", "${entry.key}")} - #else - ## Otherwise set (or update) the attribute on the item in DynamoDB ** - $!{expSet.put("#${entry.key}", ":${entry.key}")} - $!{expNames.put("#${entry.key}", "${entry.key}")} - $!{expValues.put(":${entry.key}", $ddb.toDynamoDB($entry.value))} - #end - #end - ## Start building the update expression, starting with attributes we're going to SET ** - #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 - ## Continue building the update expression, adding attributes we're going to ADD ** - #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 - ## Continue building the update expression, adding attributes we're going to REMOVE ** - #if( !${expRemove.isEmpty()} ) - #set( $expression = "${expression} REMOVE" ) - #foreach( $entry in $expRemove ) - #set( $expression = "${expression} ${entry}" ) - #if ( $foreach.hasNext ) - #set( $expression = "${expression}," ) - #end - #end - #end - ## Finally, write the update expression into the document, along with any expressionNames and expressionValues ** - "update" : { - "expression" : "${expression}", - #if( !${expNames.isEmpty()} ) - "expressionNames" : $utils.toJson($expNames), - #end - #if( !${expValues.isEmpty()} ) - "expressionValues" : $utils.toJson($expValues), - #end - }, - "condition" : { - "expression" : "attribute_exists(id) and version = :expectedVersion", - "expressionValues" : { - ":expectedVersion" : $ddb.toDynamoDBJson($context.arguments.expectedVersion) - } - } - } - ResponseMappingTemplate: "$util.toJson($ctx.result)" - - Schema: - Type: "AWS::AppSync::GraphQLSchema" - Properties: - ApiId: !GetAtt GraphQLApi.ApiId - Definition: | - type Comment { - author: String! - comment: String! - } - type Mutation { - addComment(id: ID!, author: String!, comment: String!): Post - addTag(id: ID!, tag: String!): Post - removeTag(id: ID!, tag: String!): Post - deletePost(id: ID!, expectedVersion: Int): Post - upvotePost(id: ID!): Post - downvotePost(id: ID!): Post - updatePost( - id: ID!, - author: String, - title: String, - content: String, - url: String, - expectedVersion: Int! - ): Post - addPost( - author: String!, - title: String!, - content: String!, - url: String! - ): Post! - } - type PaginatedPosts { - posts: [Post!]! - nextToken: String - } - type Post { - id: ID! - author: String - title: String - content: String - url: String - ups: Int! - downs: Int! - version: Int! - tags: [String!] - comments: [Comment!] - created: String - lastUpdated: String - } - type Query { - allPostsByTag(tag: String!, count: Int, nextToken: String): PaginatedPosts! - allPostsByAuthor(author: String!, count: Int, nextToken: String): PaginatedPosts! - allPost(count: Int, nextToken: String): PaginatedPosts! - getPost(id: ID!): Post - } - schema { - query: Query - mutation: Mutation - } -Outputs: - Region: - Value: !Ref 'AWS::Region' - GraphQLApiARN: - Description: The App ID of the GraphQL endpoint. - Value: !Ref GraphQLApi - GraphQLApiId: - Description: The App ID of the GraphQL endpoint. - Value: !GetAtt GraphQLApi.ApiId - GraphQLApiEndpoint: - Description: The URL for the GraphQL endpoint. - Value: !GetAtt GraphQLApi.GraphQLUrl - PostDynamoDBTableDataSourceARN: - Description: The ARN for the Post DynamoDB table DataSource. - Value: !Ref PostDynamoDBTableDataSource - PostDynamoDBTableDataSourceName: - Description: The ARN for the Post DynamoDB table DataSource. - Value: !GetAtt PostDynamoDBTableDataSource.Name \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/index.js b/packages/amplify-category-api/provider-utils/awscloudformation/index.js deleted file mode 100644 index 858d52498c..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/index.js +++ /dev/null @@ -1,177 +0,0 @@ -const path = require('path'); -const fs = require('fs-extra'); - -const parametersFileName = 'api-params.json'; -const cfnParametersFilename = 'parameters.json'; - -let serviceMetadata; - -function serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename) { - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { serviceWalkthrough } = require(serviceWalkthroughSrc); - - return serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); -} - -function copyCfnTemplate(context, category, options, cfnFilename) { - const { amplify } = context; - const targetDir = amplify.pathManager.getBackendDirPath(); - const pluginDir = __dirname; - - const copyJobs = [ - { - dir: pluginDir, - template: `cloudformation-templates/${cfnFilename}`, - target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, - }, - ]; - - // copy over the files - return context.amplify.copyBatch(context, copyJobs, options, true, false); -} - -function console(context, service) { - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; - const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { openConsole } = require(serviceWalkthroughSrc); - - if (!openConsole) { - context.print.error('Opening console functionality not available for this option'); - process.exit(0); - } - - return openConsole(context); -} - -function addResource(context, category, service, options) { - let answers; - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; - let { cfnFilename } = serviceMetadata; - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - - return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename).then(result => { - 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; - } - copyCfnTemplate(context, category, answers, cfnFilename); - - const parameters = { ...answers }; - const cfnParameters = { - authRoleName: { - Ref: 'AuthRoleName', - }, - unauthRoleName: { - Ref: 'UnauthRoleName', - }, - }; - const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); - fs.ensureDirSync(resourceDirPath); - - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let jsonString = JSON.stringify(parameters, null, 4); - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); - - const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - jsonString = JSON.stringify(cfnParameters, null, 4); - fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); - } - context.amplify.updateamplifyMetaAfterResourceAdd(category, answers.resourceName, options); - return answers.resourceName; - }); -} - -async function updateResource(context, category, service) { - let answers; - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; - let { cfnFilename } = serviceMetadata; - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { updateWalkthrough } = require(serviceWalkthroughSrc); - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - - if (!updateWalkthrough) { - context.print.error('Update functionality not available for this option'); - process.exit(0); - } - - return updateWalkthrough(context, defaultValuesFilename, serviceMetadata).then(result => { - const options = {}; - if (result) { - if (result.answers) { - ({ answers } = result); - options.dependsOn = result.dependsOn; - } else { - answers = result; - } - - if (!result.noCfnFile) { - if (answers.customCfnFile) { - cfnFilename = answers.customCfnFile; - } - copyCfnTemplate(context, category, answers, cfnFilename); - const parameters = { ...answers }; - const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); - fs.ensureDirSync(resourceDirPath); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - const jsonString = JSON.stringify(parameters, null, 4); - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); - context.amplify.updateamplifyMetaAfterResourceUpdate(category, answers.resourceName, 'dependsOn', answers.dependsOn); - } - } - }); -} - -async function migrateResource(context, projectPath, service, resourceName) { - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; - const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { migrate } = require(serviceWalkthroughSrc); - - if (!migrate) { - context.print.info(`No migration required for ${resourceName}`); - return; - } - - return await migrate(context, projectPath, resourceName); -} - -function addDatasource(context, category, datasource) { - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-datasources.json`)[datasource]; - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - return serviceQuestions(context, defaultValuesFilename, serviceWalkthroughFilename); -} - -function getPermissionPolicies(context, service, resourceName, crudOptions) { - serviceMetadata = context.amplify.readJsonFile(`${__dirname}/../supported-services.json`)[service]; - const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { getIAMPolicies } = require(serviceWalkthroughSrc); - - if (!getPermissionPolicies) { - context.print.info(`No policies found for ${resourceName}`); - return; - } - - return getIAMPolicies(resourceName, crudOptions); -} - -module.exports = { - addResource, - updateResource, - console, - migrateResource, - addDatasource, - getPermissionPolicies, -}; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json b/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json deleted file mode 100644 index 2d8cf0a922..0000000000 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/defaultCustomResources.json +++ /dev/null @@ -1,61 +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": "" - } - } -} \ No newline at end of file diff --git a/packages/amplify-category-api/provider-utils/supported-datasources.json b/packages/amplify-category-api/provider-utils/supported-datasources.json deleted file mode 100644 index 6916a622ab..0000000000 --- a/packages/amplify-category-api/provider-utils/supported-datasources.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "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", - "defaultValuesFilename": "appSync-rds-defaults.js", - "serviceWalkthroughFilename": "appSync-rds-walkthrough.js", - "cfnFilename": "appSync-rds-cloudformation-template-default.yml.ejs", - "provider": "awscloudformation", - "availableRegions": ["us-east-1", "us-east-2", "us-west-2", "ap-northeast-1", "eu-west-1"] - } -} diff --git a/packages/amplify-category-api/provider-utils/supported-services.json b/packages/amplify-category-api/provider-utils/supported-services.json deleted file mode 100644 index bc10d9a0c2..0000000000 --- a/packages/amplify-category-api/provider-utils/supported-services.json +++ /dev/null @@ -1,157 +0,0 @@ -{ - "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]+$", - "onErrorMsg": "You can use the following characters: a-z A-Z 0-9" - }, - "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": "What best describes your project:", - "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" - } - ], - "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, Mac OS only)", - "value": "vim" - }, - { - "name": "Emacs (via Terminal, Mac OS 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", - "defaultValuesFilename": "appSync-defaults.js", - "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", - "defaultValuesFilename": "apigw-defaults.js", - "serviceWalkthroughFilename": "apigw-walkthrough.js", - "cfnFilename": "apigw-cloudformation-template-default.json.ejs", - "provider": "awscloudformation" - } -} diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs rename to packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json new file mode 100644 index 0000000000..f95feea378 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/defaultCustomResources.json @@ -0,0 +1,58 @@ +{ + "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/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/many-relationship-schema.graphql rename to packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema.graphql 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 new file mode 100644 index 0000000000..3438d56938 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema.graphql @@ -0,0 +1,17 @@ +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/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql similarity index 97% rename from packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql rename to packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql index 1f5a301fbe..74b097ceae 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/appsync-schemas/single-object-schema.graphql +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema.graphql @@ -2,4 +2,4 @@ type Todo @model { id: ID! name: String! description: String -} \ No newline at end of file +} diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs rename to packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-index.js.ejs diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs rename to packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-package.json.ejs diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs rename to packages/amplify-category-api/resources/awscloudformation/sync-conflict-handler/sync-conflict-handler-template.json.ejs 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 new file mode 100644 index 0000000000..36f39965a9 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/cfn-api-artifact-handler.test.ts.snap @@ -0,0 +1,51 @@ +// 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 { + "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/cfn-api-artifact-handler.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts new file mode 100644 index 0000000000..65c8ba3636 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts @@ -0,0 +1,225 @@ +import path from 'path'; +import fs from 'fs-extra'; +import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; +import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; +import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; +import { category } from '../../../category-constants'; +import { writeTransformerConfiguration } from 'graphql-transformer-core'; +import { rootAssetDir } from '../../../provider-utils/awscloudformation/aws-constants'; +import { getAppSyncResourceName, getAppSyncAuthConfig } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +import _ from 'lodash'; + +jest.mock('fs-extra'); + +jest.mock('graphql-transformer-core', () => ({ + readTransformerConfiguration: jest.fn(async () => ({})), + writeTransformerConfiguration: jest.fn(), +})); + +jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ + checkIfAuthExists: jest.fn(), + getAppSyncResourceName: jest.fn(() => testApiName), + getAppSyncAuthConfig: jest.fn(() => ({})), +})); + +const fs_mock = (fs as unknown) as jest.Mocked; +const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; +const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; +const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; + +const backendDirPathStub = 'backendDirPath'; + +const testApiName = 'testApiName'; + +const context_stub = { + print: { + success: jest.fn(), + }, + amplify: { + updateamplifyMetaAfterResourceAdd: jest.fn(), + updateamplifyMetaAfterResourceUpdate: jest.fn(), + updateBackendConfigAfterResourceUpdate: jest.fn(), + executeProviderUtils: jest.fn(), + copyBatch: jest.fn(), + getProjectMeta: jest.fn(), + readJsonFile: jest.fn(), + pathManager: { + getBackendDirPath: jest.fn(() => backendDirPathStub), + }, + }, +}; + +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(() => { + fs_mock.existsSync.mockImplementation(() => false); + getAppSyncResourceName_mock.mockImplementation(() => undefined); + }); + beforeEach(() => { + jest.clearAllMocks(); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); + }); + + it('does not create a second API if one already exists', async () => { + getAppSyncResourceName_mock.mockImplementationOnce(() => testApiName); + return expect(cfnApiArtifactHandler.createArtifacts(addRequestStub)).rejects.toMatchInlineSnapshot( + `[Error: GraphQL API testApiName already exists in the project. Use 'amplify update api' to make modifications.]`, + ); + }); + + it('creates the correct directories', async () => { + await cfnApiArtifactHandler.createArtifacts(addRequestStub); + expect(fs_mock.ensureDirSync.mock.calls.length).toBe(1); + expect(fs_mock.ensureDirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName)); + expect(fs_mock.mkdirSync.mock.calls.length).toBe(2); + expect(fs_mock.mkdirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName, 'resolvers')); + expect(fs_mock.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(writeTransformerConfiguration_mock.mock.calls.length).toBe(2); + expect(writeTransformerConfiguration_mock.mock.calls[0]).toMatchSnapshot(); + }); + + it('writes the default custom resources stack', async () => { + await cfnApiArtifactHandler.createArtifacts(addRequestStub); + expect(fs_mock.copyFileSync.mock.calls.length).toBe(1); + expect(fs_mock.copyFileSync.mock.calls[0]).toEqual([ + path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), + path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'stacks', 'CustomResources.json'), + ]); + }); + + it('writes the selected template schema to project', async () => { + await cfnApiArtifactHandler.createArtifacts(addRequestStub); + expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); + expect(fs_mock.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(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); + expect(context_stub.amplify.executeProviderUtils.mock.calls[0][0]).toStrictEqual(context_stub); + expect(context_stub.amplify.executeProviderUtils.mock.calls[0][1]).toStrictEqual('awscloudformation'); + expect(context_stub.amplify.executeProviderUtils.mock.calls[0][2]).toStrictEqual('compileSchema'); + }); + + it('updates amplify meta', async () => { + await cfnApiArtifactHandler.createArtifacts(addRequestStub); + expect(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls.length).toBe(1); + expect(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][0]).toStrictEqual(category); + expect(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][1]).toStrictEqual( + addRequestStub.serviceConfiguration.apiName, + ); + }); + + 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(() => { + getAppSyncResourceName_mock.mockImplementation(() => testApiName); + getAppSyncAuthConfig_mock.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(context_stub); + }); + + it('throws error if no GQL API in project', () => { + getAppSyncResourceName_mock.mockImplementationOnce(() => undefined); + return expect(cfnApiArtifactHandler.updateArtifacts(updateRequestStub)).rejects.toMatchInlineSnapshot( + `[Error: No AppSync API configured in the project. Use 'amplify add api' to create an API.]`, + ); + }); + + it('writes new schema if specified', async () => { + const newSchemaContents = 'a new schema'; + updateRequestStub.serviceModification.transformSchema = newSchemaContents; + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); + expect(fs_mock.writeFileSync.mock.calls[0][1]).toBe(newSchemaContents); + }); + + it('updates resolver config if not empty', async () => { + updateRequestStub.serviceModification.conflictResolution = { + defaultResolutionStrategy: { + type: 'OPTIMISTIC_CONCURRENCY', + }, + }; + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(writeTransformerConfiguration_mock.mock.calls.length).toBe(1); + }); + + it('updates default auth if not empty', async () => { + updateRequestStub.serviceModification.defaultAuthType = { mode: 'AWS_IAM' }; + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); + expect(context_stub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); + }); + + it('updates additional auth if not empty', async () => { + updateRequestStub.serviceModification.additionalAuthTypes = [{ mode: 'AWS_IAM' }, { mode: 'API_KEY' }]; + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); + expect(context_stub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); + }); + + it('compiles the changes', async () => { + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); + }); + + it('updates meta files after update', async () => { + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(1); + expect(context_stub.amplify.updateBackendConfigAfterResourceUpdate.mock.calls.length).toBe(1); + }); +}); 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 new file mode 100644 index 0000000000..67f1ec32a7 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.test.ts @@ -0,0 +1,6 @@ +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/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 new file mode 100644 index 0000000000..73049e4ca9 --- /dev/null +++ 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 @@ -0,0 +1,71 @@ +// 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 { + "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 { + "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__/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 new file mode 100644 index 0000000000..9668a5c86e --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts.snap @@ -0,0 +1,45 @@ +// 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 new file mode 100644 index 0000000000..843fd5f5bc --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/service-walkthrough-result-to-add-api-request.test.ts.snap @@ -0,0 +1,21 @@ +// 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/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 new file mode 100644 index 0000000000..0b7d99a2e1 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.test.ts @@ -0,0 +1,102 @@ +import { + authConfigToAppSyncAuthType, + appSyncAuthTypeToAuthConfig, +} from '../../../../provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; +import { + AppSyncAPIKeyAuthType, + AppSyncAWSIAMAuthType, + AppSyncCognitoUserPoolsAuthType, + AppSyncOpenIDConnectAuthType, +} from 'amplify-headless-interface'; + +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/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 new file mode 100644 index 0000000000..fa18ae097e --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.test.ts @@ -0,0 +1,72 @@ +import { ConflictResolution } from 'amplify-headless-interface'; +import { + conflictResolutionToResolverConfig, + resolverConfigToConflictResolution, +} from '../../../../provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper'; +import { ResolverConfig, ConflictHandlerType } from 'graphql-transformer-core'; + +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({}); + }); +}); + +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/provider-utils/__tests__/apigw-walkthroughs.test.js b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts similarity index 86% rename from packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js rename to packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts index 0a4f81cac5..61b453ad2f 100644 --- a/packages/amplify-category-api/provider-utils/__tests__/apigw-walkthroughs.test.js +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/rest-api-path-utils.test.ts @@ -1,8 +1,5 @@ -const rewire = require('rewire'); +import { validatePathName, formatCFNPathParamsForExpressJs } from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; -const walkthrough = rewire('../awscloudformation/service-walkthroughs/apigw-walkthrough.js'); - -const validatePathName = walkthrough.__get__('validatePathName'); const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }]; test('validatePathName_validPath', () => { @@ -44,10 +41,6 @@ test('validatePathName_pathMatch', () => { }); test('formatCFNPathParamsForExpressJs', () => { - // setup - const formatCFNPathParamsForExpressJs = walkthrough.__get__('formatCFNPathParamsForExpressJs'); - - // test 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 new file mode 100644 index 0000000000..519935b7a0 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.test.ts @@ -0,0 +1,28 @@ +import { serviceWalkthroughResultToAddApiRequest } from '../../../../provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request'; +import { AppSyncAuthType, ConflictResolution } from 'amplify-headless-interface/src'; + +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 new file mode 100644 index 0000000000..83ae597bec --- /dev/null +++ b/packages/amplify-category-api/src/category-constants.ts @@ -0,0 +1 @@ +export const category = 'api'; diff --git a/packages/amplify-category-api/commands/api.js b/packages/amplify-category-api/src/commands/api.js similarity index 100% rename from packages/amplify-category-api/commands/api.js rename to packages/amplify-category-api/src/commands/api.js diff --git a/packages/amplify-category-api/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js similarity index 98% rename from packages/amplify-category-api/commands/api/add-graphql-datasource.js rename to packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 51c5880810..b467611eb4 100644 --- a/packages/amplify-category-api/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -22,7 +22,7 @@ module.exports = { name: subcommand, run: async context => { const { amplify } = context; - const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-datasources.json`); + const servicesMetadata = require('../../provider-utils/supported-datasources').supportedDatasources; let resourceName; let datasource; let databaseName; diff --git a/packages/amplify-category-api/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js similarity index 92% rename from packages/amplify-category-api/commands/api/add.js rename to packages/amplify-category-api/src/commands/api/add.js index efa1675d2d..aee1ba5953 100644 --- a/packages/amplify-category-api/commands/api/add.js +++ b/packages/amplify-category-api/src/commands/api/add.js @@ -7,7 +7,7 @@ module.exports = { name: subcommand, run: async context => { const { amplify } = context; - const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; return amplify .serviceSelectionPrompt(context, category, servicesMetadata) .then(result => { diff --git a/packages/amplify-category-api/commands/api/console.js b/packages/amplify-category-api/src/commands/api/console.js similarity index 87% rename from packages/amplify-category-api/commands/api/console.js rename to packages/amplify-category-api/src/commands/api/console.js index 3296bc418b..521c18ee97 100644 --- a/packages/amplify-category-api/commands/api/console.js +++ b/packages/amplify-category-api/src/commands/api/console.js @@ -5,7 +5,7 @@ module.exports = { name: subcommand, run: async context => { const { amplify } = context; - const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; return amplify .serviceSelectionPrompt(context, category, servicesMetadata) .then(result => { diff --git a/packages/amplify-category-api/commands/api/gql-compile.js b/packages/amplify-category-api/src/commands/api/gql-compile.js similarity index 100% rename from packages/amplify-category-api/commands/api/gql-compile.js rename to packages/amplify-category-api/src/commands/api/gql-compile.js diff --git a/packages/amplify-category-api/commands/api/push.js b/packages/amplify-category-api/src/commands/api/push.js similarity index 100% rename from packages/amplify-category-api/commands/api/push.js rename to packages/amplify-category-api/src/commands/api/push.js diff --git a/packages/amplify-category-api/commands/api/remove.js b/packages/amplify-category-api/src/commands/api/remove.js similarity index 88% rename from packages/amplify-category-api/commands/api/remove.js rename to packages/amplify-category-api/src/commands/api/remove.js index 4a1df2b088..9e3d0d5837 100644 --- a/packages/amplify-category-api/commands/api/remove.js +++ b/packages/amplify-category-api/src/commands/api/remove.js @@ -13,6 +13,7 @@ module.exports = { return amplify .removeResource(context, category, resourceName) .then(resourceValues => { + if (!resourceValues) return; // indicates that the customer selected "no" at the confirmation prompt if (resourceValues.service === 'AppSync') { const { projectPath } = amplify.getEnvInfo(); diff --git a/packages/amplify-category-api/commands/api/update.js b/packages/amplify-category-api/src/commands/api/update.js similarity index 88% rename from packages/amplify-category-api/commands/api/update.js rename to packages/amplify-category-api/src/commands/api/update.js index 1264a2ca42..74af43feaf 100644 --- a/packages/amplify-category-api/commands/api/update.js +++ b/packages/amplify-category-api/src/commands/api/update.js @@ -6,7 +6,7 @@ module.exports = { alias: ['configure'], run: async context => { const { amplify } = context; - const servicesMetadata = amplify.readJsonFile(`${__dirname}/../../provider-utils/supported-services.json`); + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; return amplify .serviceSelectionPrompt(context, category, servicesMetadata) diff --git a/packages/amplify-category-api/index.js b/packages/amplify-category-api/src/index.ts similarity index 83% rename from packages/amplify-category-api/index.js rename to packages/amplify-category-api/src/index.ts index 6099279fdd..394da3ebca 100644 --- a/packages/amplify-category-api/index.js +++ b/packages/amplify-category-api/src/index.ts @@ -1,16 +1,18 @@ -const { run } = require('./commands/api/console'); -const fs = require('fs-extra'); -const path = require('path'); +import { run } from './commands/api/console'; +import fs from 'fs-extra'; +import path from 'path'; +import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler'; +import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; const category = 'api'; const categories = 'categories'; -async function console(context) { +export async function console(context) { await run(context); } -async function migrate(context, serviceName) { +export async function migrate(context, serviceName) { const { projectPath, amplifyMeta } = context.migrationInfo; const migrateResourcePromises = []; Object.keys(amplifyMeta).forEach(categoryName => { @@ -22,7 +24,7 @@ async function migrate(context, serviceName) { if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( - providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName) + providerController.migrateResource(context, projectPath, amplifyMeta[category][resourceName].service, resourceName), ); } } @@ -40,7 +42,7 @@ async function migrate(context, serviceName) { await Promise.all(migrateResourcePromises); } -async function initEnv(context) { +export async function initEnv(context) { const datasource = 'Aurora Serverless'; const service = 'service'; const rdsInit = 'rdsInit'; @@ -135,7 +137,7 @@ async function initEnv(context) { }); } -async function getPermissionPolicies(context, resourceOpsMapping) { +export async function getPermissionPolicies(context, resourceOpsMapping) { const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); const permissionPolicies = []; @@ -149,7 +151,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { context, amplifyMeta[category][resourceName].service, resourceName, - resourceOpsMapping[resourceName] + resourceOpsMapping[resourceName], ); permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); @@ -164,7 +166,7 @@ async function getPermissionPolicies(context, resourceOpsMapping) { return { permissionPolicies, resourceAttributes }; } -async function executeAmplifyCommand(context) { +export async function executeAmplifyCommand(context) { let commandPath = path.normalize(path.join(__dirname, 'commands')); if (context.input.command === 'help') { commandPath = path.join(commandPath, category); @@ -176,16 +178,20 @@ async function executeAmplifyCommand(context) { await commandModule.run(context); } -async function handleAmplifyEvent(context, args) { +export const executeAmplifyHeadlessCommand = async (context, headlessPayload: string) => { + switch (context.input.command) { + case 'add': + await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); + break; + case 'update': + await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); + break; + default: + context.print.error(`Headless mode for ${context.input.command} api is not implemented yet`); + } +}; + +export async function handleAmplifyEvent(context, args) { context.print.info(`${category} handleAmplifyEvent to be implemented`); context.print.info(`Received event args ${args}`); } - -module.exports = { - console, - migrate, - initEnv, - getPermissionPolicies, - executeAmplifyCommand, - handleAmplifyEvent, -}; 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 new file mode 100644 index 0000000000..a3b7de27c5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts @@ -0,0 +1,6 @@ +import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; + +export interface ApiArtifactHandler { + createArtifacts(request: AddApiRequest): Promise; + updateArtifacts(request: UpdateApiRequest): Promise; +} 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 new file mode 100644 index 0000000000..824a2cafef --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts @@ -0,0 +1,8 @@ +import 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/cfn-api-artifact-handler.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts new file mode 100644 index 0000000000..8e0a695001 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cfn-api-artifact-handler.ts @@ -0,0 +1,262 @@ +import { ApiArtifactHandler } from '../api-artifact-handler'; +import { + AddApiRequest, + ConflictResolution, + AppSyncServiceConfiguration, + ResolutionStrategy, + UpdateApiRequest, +} from 'amplify-headless-interface'; +import path from 'path'; +import fs from 'fs-extra'; +import { category } from '../../category-constants'; +import { rootAssetDir, provider, gqlSchemaFilename, cfnParametersFilename } from './aws-constants'; +import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; +import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-conflict-resolution-bi-di-mapper'; +import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; +import uuid from 'uuid'; +import _ from 'lodash'; +import { ServiceName as FunctionServiceName } from 'amplify-category-function'; +import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists } from './utils/amplify-meta-utils'; + +export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { + return new CfnApiArtifactHandler(context); +}; +const resolversDirName = 'resolvers'; +const stacksDirName = 'stacks'; +const defaultStackName = 'CustomResources.json'; + +const defaultCfnParameters = (apiName: string) => ({ + AppSyncApiName: apiName, + DynamoDBBillingMode: 'PAY_PER_REQUEST', + DynamoDBEnableServerSideEncryption: false, +}); +class CfnApiArtifactHandler implements ApiArtifactHandler { + private readonly context: any; + + constructor(context) { + 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 existingApiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + if (existingApiName) { + throw new Error(`GraphQL API ${existingApiName} already exists in the project. Use 'amplify update api' to make modifications.`); + } + const serviceConfig = request.serviceConfiguration; + 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); + } + + // 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); + + // Write the default custom resources stack out to disk. + fs.copyFileSync( + path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), + path.join(resourceDir, stacksDirName, defaultStackName), + ); + + // write the template buffer to the project folder + this.writeSchema(resourceDir, serviceConfig.transformSchema); + + const authConfig = this.extractAuthConfig(serviceConfig); + + await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters: this.getCfnParameters(serviceConfig.apiName, authConfig, resourceDir), + authConfig, + }); + + this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(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): Promise => { + const updates = request.serviceModification; + const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + if (!apiName) { + throw new Error(`No AppSync API configured in the project. Use 'amplify add api' to create an API.`); + } + const resourceDir = this.getResourceDir(apiName); + if (updates.transformSchema) { + this.writeSchema(resourceDir, updates.transformSchema); + } + if (updates.conflictResolution) { + updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); + await writeResolverConfig(updates.conflictResolution, resourceDir); + } + const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); + if (updates.defaultAuthType) { + authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); + } + if (updates.additionalAuthTypes) { + authConfig.additionalAuthenticationProviders = updates.additionalAuthTypes.map(appSyncAuthTypeToAuthConfig); + } + await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters: this.getCfnParameters(apiName, authConfig, resourceDir), + authConfig, + }); + + this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); + this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); + }; + + private writeSchema = (resourceDir: string, schema: string) => { + fs.writeFileSync(path.join(resourceDir, gqlSchemaFilename), schema); + }; + + private getResourceDir = (apiName: string) => path.join(this.context.amplify.pathManager.getBackendDirPath(), category, apiName); + + private createAmplifyMeta = authConfig => ({ + service: 'AppSync', + providerPlugin: provider, + output: { + authConfig, + }, + }); + + private extractAuthConfig = (config: AppSyncServiceConfiguration) => ({ + defaultAuthentication: appSyncAuthTypeToAuthConfig(config.defaultAuthType), + additionalAuthenticationProviders: (config.additionalAuthTypes || []).map(appSyncAuthTypeToAuthConfig), + }); + + private updateTransformerConfigVersion = async resourceDir => { + const localTransformerConfig = await readTransformerConfiguration(resourceDir); + localTransformerConfig.Version = TRANSFORM_CURRENT_VERSION; + localTransformerConfig.ElasticsearchWarning = true; + await writeTransformerConfiguration(resourceDir, localTransformerConfig); + }; + + private createResolverResources = async (conflictResolution: ConflictResolution = {}) => { + const newConflictResolution = _.cloneDeep(conflictResolution); + + // if the strat is a new lambda, generate the lambda and update the strategy to reference the new lambda + const generateLambdaIfNew = async (strat: ResolutionStrategy) => { + if (strat && strat.type === 'LAMBDA' && strat.resolver.type === 'NEW') { + strat.resolver = { + type: 'EXISTING', + name: await this.createSyncFunction(), + }; + } + }; + await generateLambdaIfNew(newConflictResolution.defaultResolutionStrategy); + await Promise.all( + (newConflictResolution.perModelResolutionStrategy || []) + .map(perModelStrat => perModelStrat.resolutionStrategy) + .map(generateLambdaIfNew), + ); + return newConflictResolution; + }; + + private getCfnParameters = (apiName: string, authConfig, resourceDir: string) => { + const params = + this.context.amplify.readJsonFile(path.join(resourceDir, cfnParametersFilename), undefined, false) || defaultCfnParameters(apiName); + const cognitoPool = this.getCognitoUserPool(authConfig); + if (cognitoPool) { + params.AuthCognitoUserPoolId = cognitoPool; + } else { + delete params.AuthCognitoUserPoolId; + } + return params; + }; + + private getCognitoUserPool = authConfig => { + const additionalUserPoolProvider = (authConfig.additionalAuthenticationProviders || []).find( + provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS', + ); + const defaultAuth = authConfig.defaultAuthentication || {}; + if (defaultAuth.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { + let userPoolId; + const configuredUserPoolName = checkIfAuthExists(this.context); + + 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 () => { + const targetDir = this.context.amplify.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: `${targetDir}/function/${functionName}/src/index.js`, + }, + { + dir: assetDir, + template: 'sync-conflict-handler-package.json.ejs', + target: `${targetDir}/function/${functionName}/src/package.json`, + }, + { + dir: assetDir, + template: 'sync-conflict-handler-template.json.ejs', + target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + await this.context.amplify.copyBatch(this.context, copyJobs, functionProps, true); + + const backendConfigs = { + service: FunctionServiceName.LambdaFunction, + providerPlugin: provider, + build: true, + }; + + await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); + this.context.print.success(`Successfully added ${functionName} function locally`); + + return functionName + '-${env}'; + }; +} + +/** + * 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) => { + const localTransformerConfig = await readTransformerConfiguration(resourceDir); + localTransformerConfig.ResolverConfig = conflictResolutionToResolverConfig(conflictResolution); + await writeTransformerConfiguration(resourceDir, localTransformerConfig); +}; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/default-values/apigw-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js similarity index 100% rename from packages/amplify-category-api/provider-utils/awscloudformation/default-values/appSync-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts new file mode 100644 index 0000000000..00b98fe6d1 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -0,0 +1,95 @@ +import { serviceWalkthroughResultToAddApiRequest } from './utils/service-walkthrough-result-to-add-api-request'; +import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; +import { serviceMetadataFor, getServiceWalkthrough, datasourceMetadataFor } from './utils/dynamic-imports'; +import { legacyAddResource } from './legacy-add-resource'; +import { legacyUpdateResource } from './legacy-update-resource'; +import { UpdateApiRequest } from 'amplify-headless-interface'; +import { editSchemaFlow } from './utils/edit-schema-flow'; + +export async function console(context, service) { + const { serviceWalkthroughFilename } = await serviceMetadataFor(service); + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { openConsole } = require(serviceWalkthroughSrc); + + if (!openConsole) { + context.print.error('Opening console functionality not available for this option'); + process.exit(0); + } + + return openConsole(context); +} + +export async function addResource(context, category, service, options) { + const serviceMetadata = await serviceMetadataFor(service); + const { serviceWalkthroughFilename, defaultValuesFilename } = serviceMetadata; + const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); + + const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); + switch (service) { + case '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; + default: + return legacyAddResource(serviceWalkthroughPromise, context, category, service, options); + } +} + +export async function updateResource(context, category, service) { + const serviceMetadata = await serviceMetadataFor(service); + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { updateWalkthrough } = require(serviceWalkthroughSrc); + + if (!updateWalkthrough) { + context.print.error('Update functionality not available for this option'); + process.exit(0); + } + + const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); + + switch (service) { + case 'AppSync': + return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); + default: + return legacyUpdateResource(updateWalkthroughPromise, context, category, service); + } +} + +export async function migrateResource(context, projectPath, service, resourceName) { + const serviceMetadata = await serviceMetadataFor(service); + const { serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { migrate } = require(serviceWalkthroughSrc); + + if (!migrate) { + context.print.info(`No migration required for ${resourceName}`); + return; + } + + return await migrate(context, projectPath, resourceName); +} + +export async function addDatasource(context, category, datasource) { + const serviceMetadata = await datasourceMetadataFor(datasource); + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, defaultValuesFilename, serviceMetadata); +} + +export async function getPermissionPolicies(context, service, resourceName, crudOptions) { + const serviceMetadata = await serviceMetadataFor(service); + const { serviceWalkthroughFilename } = serviceMetadata; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { getIAMPolicies } = require(serviceWalkthroughSrc); + + if (!getIAMPolicies) { + context.print.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 new file mode 100644 index 0000000000..3e83c79497 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-add-resource.ts @@ -0,0 +1,69 @@ +import { serviceMetadataFor } from './utils/dynamic-imports'; +import fs from 'fs-extra'; +import path from 'path'; +import { parametersFileName, cfnParametersFilename, rootAssetDir } from './aws-constants'; + +// 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, category, service, options) => { + let answers; + let { cfnFilename } = await serviceMetadataFor(service); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + + 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; + } + copyCfnTemplate(context, category, answers, cfnFilename); + + const parameters = { ...answers }; + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); + + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + let jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); + jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); + } + 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, category, options, cfnFilename) => { + const { amplify } = context; + const targetDir = amplify.pathManager.getBackendDirPath(); + + const copyJobs = [ + { + dir: path.join(rootAssetDir, 'cloudformation-templates'), + template: cfnFilename, + target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + return context.amplify.copyBatch(context, copyJobs, options, true, false); +}; 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 new file mode 100644 index 0000000000..2a08cbfa61 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/legacy-update-resource.ts @@ -0,0 +1,35 @@ +import { serviceMetadataFor } from "./utils/dynamic-imports"; +import { copyCfnTemplate } from "./legacy-add-resource"; +import fs from 'fs-extra'; +import path from 'path'; +import { parametersFileName } from "./aws-constants"; + +export const legacyUpdateResource = async (updateWalkthroughPromise: Promise, context, category, service) => { + let answers; + let { cfnFilename } = await serviceMetadataFor(service); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + 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; + } + copyCfnTemplate(context, category, answers, cfnFilename); + const parameters = { ...answers }; + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + const jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + context.amplify.updateamplifyMetaAfterResourceUpdate(category, answers.resourceName, 'dependsOn', answers.dependsOn); + } + } +} diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts similarity index 87% rename from packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts index 488f0f1ead..01f95ed589 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts @@ -1,18 +1,20 @@ -const inquirer = require('inquirer'); -const pathLib = require('path'); -const fs = require('fs-extra'); -const { ServiceName: FunctionServiceName } = require('amplify-category-function'); +import inquirer from 'inquirer'; +import path from 'path'; +import fs from 'fs-extra'; +import uuid from 'uuid'; +import { rootAssetDir } from '../aws-constants'; +import { validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; +import { ServiceName as FunctionServiceName } from 'amplify-category-function'; const category = 'api'; const serviceName = 'API Gateway'; const parametersFileName = 'api-params.json'; const cfnParametersFilename = 'parameters.json'; -const uuid = require('uuid'); -async function serviceWalkthrough(context, defaultValuesFilename) { +export async function serviceWalkthrough(context, defaultValuesFilename) { const { amplify } = context; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = require(defaultValuesSrc); + const { getAllDefaults } = await import(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); let answers = { @@ -25,11 +27,11 @@ async function serviceWalkthrough(context, defaultValuesFilename) { return pathFlow(context, answers); } -async function updateWalkthrough(context, defaultValuesFilename) { +export async function updateWalkthrough(context, defaultValuesFilename) { const { amplify } = context; const { allResources } = await context.amplify.getResourceStatus(); const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = require(defaultValuesSrc); + const { getAllDefaults } = await import(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); const resources = allResources.filter(resource => resource.service === serviceName).map(resource => resource.resourceName); @@ -40,7 +42,7 @@ async function updateWalkthrough(context, defaultValuesFilename) { return; } - let answers = { + let answers: any = { paths: [], }; @@ -73,8 +75,8 @@ async function updateWalkthrough(context, defaultValuesFilename) { } const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - const resourceDirPath = pathLib.join(projectBackendDirPath, category, updateApi.resourceName); - const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); + const resourceDirPath = path.join(projectBackendDirPath, category, updateApi.resourceName as string); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); let parameters; try { parameters = context.amplify.readJsonFile(parametersFilePath); @@ -134,14 +136,15 @@ async function updateWalkthrough(context, defaultValuesFilename) { return updatedResult; } -async function pathFlow(context, answers, currentPath) { +async function pathFlow(context, answers, currentPath?) { const pathsAnswer = await askPaths(context, answers, currentPath); answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; const { dependsOn } = pathsAnswer; - const privacy = {}; - privacy.auth = pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length; - privacy.unauth = pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length; + const privacy = { + auth: pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length, + unauth: pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length, + }; answers = { ...answers, privacy, dependsOn }; @@ -165,7 +168,7 @@ async function pathFlow(context, answers, currentPath) { async function askApiNames(context, defaults) { const { amplify } = context; // TODO: Check if default name is already taken - const answer = await inquirer.prompt([ + const answer: { apiName?: string; resourceName: string } = await inquirer.prompt([ { name: 'resourceName', type: 'input', @@ -204,8 +207,8 @@ async function askPrivacy(context, answers, currentPath) { let permissionSelected = 'Auth/Guest Users'; let allowUnauthenticatedIdentities = false; - const privacy = {}; - const { checkRequirements, externalAuthEnable } = require('amplify-category-auth'); + const privacy: any = {}; + const { checkRequirements, externalAuthEnable } = await import('amplify-category-auth'); if (userPoolGroupList.length > 0) { do { @@ -486,39 +489,6 @@ async function askPaths(context, answers, currentPath) { return { paths, dependsOn, functionArns }; } -function validatePathName(name, paths) { - 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.'; - } - - const split = name.split('/').filter(sub => sub !== ''); // because name starts with a /, this filters out the first empty element - // Check if any prefix of this path matches an existing path - let subpath = ''; - const subMatch = split.some(sub => { - subpath = `${subpath}/${sub}`; - return paths.map(path => path.name).find(name => name === subpath) !== undefined; - }); - if (subMatch) { - return `An existing path already matches this sub-path: ${subpath}`; - } - - return true; -} - async function findDependsOn(paths, context) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; @@ -614,10 +584,10 @@ async function askLambdaSource(context, functionType, path, currentPath) { } } -function newLambdaFunction(context, path) { +async function newLambdaFunction(context, path) { let add; try { - ({ add } = require('amplify-category-function')); + ({ add } = await import('amplify-category-function')); } catch (e) { throw new Error('Function plugin not installed in the CLI. You need to install it to use this feature.'); } @@ -642,12 +612,6 @@ function newLambdaFunction(context, path) { }); } -// Convert a CloudFormation parameterized path to an ExpressJS parameterized path -// /library/{libraryId}/book/{isbn} => /library/:libraryId/book/:isbn -function formatCFNPathParamsForExpressJs(path) { - return path.replace(/{([a-zA-Z0-9\-]+)}/g, ':$1'); -} - async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; @@ -706,12 +670,12 @@ async function askLambdaArn(context, currentPath) { }; } -async function migrate(context, projectPath, resourceName) { +export async function migrate(context, projectPath, resourceName) { const { amplify } = context; const targetDir = amplify.pathManager.getBackendDirPath(); - const resourceDirPath = pathLib.join(targetDir, category, resourceName); - const parametersFilePath = pathLib.join(resourceDirPath, parametersFileName); + const resourceDirPath = path.join(targetDir, category, resourceName); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); let parameters; try { parameters = amplify.readJsonFile(parametersFilePath); @@ -719,11 +683,10 @@ async function migrate(context, projectPath, resourceName) { context.print.error(`Error reading api-params.json file for ${resourceName} resource`); throw e; } - const pluginDir = `${__dirname}/../`; const copyJobs = [ { - dir: pluginDir, - template: 'cloudformation-templates/apigw-cloudformation-template-default.json.ejs', + dir: path.join(rootAssetDir, 'cloudformation-templates'), + template: 'apigw-cloudformation-template-default.json.ejs', target: `${targetDir}/${category}/${resourceName}/${resourceName}-cloudformation-template.json`, }, ]; @@ -741,7 +704,7 @@ async function migrate(context, projectPath, resourceName) { }, }; - const cfnParametersFilePath = pathLib.join(resourceDirPath, cfnParametersFilename); + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); const jsonString = JSON.stringify(cfnParameters, null, 4); fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); } @@ -773,7 +736,7 @@ function convertToCRUD(privacy) { return privacy; } -function getIAMPolicies(resourceName, crudOptions) { +export function getIAMPolicies(resourceName, crudOptions) { let policy = {}; const actions = []; @@ -823,10 +786,3 @@ function getIAMPolicies(resourceName, crudOptions) { return { policy, attributes }; } - -module.exports = { - serviceWalkthrough, - updateWalkthrough, - migrate, - getIAMPolicies, -}; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js similarity index 99% rename from packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index ba68ea74da..ce274b914f 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -12,7 +12,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // Verify that an API exists in the project before proceeding. if (amplifyMeta == null || amplifyMeta[category] == null || Object.keys(amplifyMeta[category]).length === 0) { context.print.error( - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.' + 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.', ); process.exit(0); } @@ -31,7 +31,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // If an AppSync API does not exist, inform the user to create the AppSync API if (!appSyncApi) { context.print.error( - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.' + 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.', ); process.exit(0); } diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts similarity index 54% rename from packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 28884c4859..1c3c881215 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts @@ -1,27 +1,21 @@ -const syncAssets = require('../sync-conflict-handler-assets/syncAssets'); -const inquirer = require('inquirer'); -const fs = require('fs-extra'); -const uuid = require('uuid'); -const path = require('path'); -const open = require('open'); -const TransformPackage = require('graphql-transformer-core'); -const { ServiceName: FunctionServiceName } = require('amplify-category-function'); - -const category = 'api'; +import { ListQuestion, CheckboxQuestion, ListChoiceOptions } from 'inquirer'; +import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; +import inquirer from 'inquirer'; +import fs from 'fs-extra'; +import path from 'path'; +import open from 'open'; +import { rootAssetDir, cfnParametersFilename } from '../aws-constants'; +import { collectDirectivesByTypeNames, readProjectConfiguration, ConflictHandlerType } from 'graphql-transformer-core'; +import { category } from '../../../category-constants'; +import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; +import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; +import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; +import _ from 'lodash'; +import { getAppSyncAuthConfig, checkIfAuthExists } from '../utils/amplify-meta-utils'; + const serviceName = 'AppSync'; -const parametersFileName = 'parameters.json'; -const schemaFileName = 'schema.graphql'; const providerName = 'awscloudformation'; -const resolversDirName = 'resolvers'; -const stacksDirName = 'stacks'; -const defaultStackName = 'CustomResources.json'; - -const { - collectDirectivesByTypeNames, - readTransformerConfiguration, - writeTransformerConfiguration, - TRANSFORM_CURRENT_VERSION, -} = TransformPackage; +const graphqlSchemaDir = path.join(rootAssetDir, 'graphql-schemas'); const authProviderChoices = [ { @@ -42,7 +36,7 @@ const authProviderChoices = [ }, ]; -function openConsole(context) { +export const openConsole = context => { const amplifyMeta = context.amplify.getProjectMeta(); const categoryAmplifyMeta = amplifyMeta[category]; let appSyncMeta; @@ -61,9 +55,9 @@ function openConsole(context) { } else { context.print.error('AppSync API is not pushed in the cloud.'); } -} +}; -async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadata) { +export const serviceWalkthrough = async (context, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); let authConfig; let defaultAuthType; @@ -100,17 +94,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const resourceAnswers = await inquirer.prompt(resourceQuestions); resourceAnswers[inputs[0].key] = resourceAnswers[inputs[1].key]; - const parameters = { - AppSyncApiName: resourceAnswers[inputs[1].key], - DynamoDBBillingMode: 'PAY_PER_REQUEST', - DynamoDBEnableServerSideEncryption: 'false', - }; - // Ask additonal questions - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); - ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType)); - await checkForCognitoUserPools(context, parameters, authConfig); + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); + ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, authConfig, defaultAuthType)); // Ask schema file question @@ -127,33 +114,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat const schemaFileAnswer = await inquirer.prompt(schemaFileQuestion); - const backendDir = amplify.pathManager.getBackendDirPath(); - - const resourceDir = `${backendDir}/${category}/${resourceAnswers[inputs[0].key]}`; - - // 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); - } - - // During API add, make sure we're creating a transform.conf.json file with the latest version the CLI supports. - await updateTransformerConfigVersion(resourceDir); - - await writeResolverConfig(resolverConfig, resourceDir); - - // Write the default custom resources stack out to disk. - const defaultCustomResourcesStack = fs.readFileSync(`${__dirname}/defaultCustomResources.json`); - fs.writeFileSync(`${resourceDir}/${stacksDirName}/${defaultStackName}`, defaultCustomResourcesStack); - + let schemaContent = ''; + let askToEdit = true; if (schemaFileAnswer[inputs[2].key]) { // User has an annotated schema file - const filePathQuestion = { type: inputs[3].type, name: inputs[3].key, @@ -161,202 +125,41 @@ async function serviceWalkthrough(context, defaultValuesFilename, serviceMetadat validate: amplify.inputValidation(inputs[3]), }; const { schemaFilePath } = await inquirer.prompt(filePathQuestion); - - fs.copyFileSync(schemaFilePath, `${resourceDir}/${schemaFileName}`); - - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters, - authConfig, - }); - - return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; - } - - // The user doesn't have an annotated schema file - - if (!(await amplify.confirmPrompt.run('Do you want a guided schema creation?'))) { - // Copy the most basic schema onto the users resource dir and transform that - - const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; - const typeNameQuestion = { - type: 'input', - name: 'typeName', - message: 'Provide a custom type name', - default: 'MyType', - validate: amplify.inputValidation({ - operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric', - }), - }; - const typeNameAnswer = await inquirer.prompt(typeNameQuestion); - - // fs.copyFileSync(schemaFilePath, targetSchemaFilePath); - const schemaDir = `${__dirname}/../appsync-schemas`; - - const copyJobs = [ - { - dir: schemaDir, - template: 'basic-schema.graphql.ejs', - target: targetSchemaFilePath, - }, - ]; - - // copy over the ejs file - await context.amplify.copyBatch(context, copyJobs, typeNameAnswer); - - context.print.info('Creating a base schema for you...'); - - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters, - authConfig, - }); - - return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; - } - - // Guided creation of the transform schema - const authTypes = getAuthTypes(authConfig); - const cognitoNotEnabled = !authTypes.includes('AMAZON_COGNITO_USER_POOLS'); - - let templateSchemaChoices = inputs[4].options; - - if (cognitoNotEnabled) { - templateSchemaChoices = templateSchemaChoices.filter(schema => schema.value !== 'single-object-auth-schema.graphql'); - } - - const templateQuestions = [ - { + schemaContent = fs.readFileSync(schemaFilePath, 'utf8'); + askToEdit = false; + } else { + // Schema template selection + const templateSelectionQuestion = { type: inputs[4].type, name: inputs[4].key, message: inputs[4].question, - choices: templateSchemaChoices, + choices: inputs[4].options.filter(templateSchemaFilter(authConfig)), validate: amplify.inputValidation(inputs[4]), - }, - { - type: inputs[5].type, - name: inputs[5].key, - message: inputs[5].question, - validate: amplify.inputValidation(inputs[5]), - default: () => { - const defaultValue = allDefaultValues[inputs[5].key]; - return defaultValue; - }, - }, - ]; - - const { templateSelection, editSchemaChoice } = await inquirer.prompt(templateQuestions); - const schemaFilePath = `${__dirname}/../appsync-schemas/${templateSelection}`; - const targetSchemaFilePath = `${resourceDir}/${schemaFileName}`; - - fs.copyFileSync(schemaFilePath, targetSchemaFilePath); - - if (editSchemaChoice) { - return context.amplify.openEditor(context, targetSchemaFilePath).then(async () => { - let notCompiled = true; - while (notCompiled) { - try { - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters, - authConfig, - }); - } catch (e) { - context.print.error('Failed compiling GraphQL schema:'); - context.print.info(e.message); - const continueQuestion = { - type: 'input', - name: 'pressKey', - message: `Correct the errors in schema.graphql and press Enter to re-compile.\n\nPath to schema.graphql:\n${targetSchemaFilePath}`, - }; - await inquirer.prompt(continueQuestion); - continue; - } - notCompiled = false; - } + }; - return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; - }); + const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); + const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); + schemaContent = fs.readFileSync(schemaFilePath, 'utf8'); } - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters, - authConfig, - }); - - return { answers: resourceAnswers, output: { authConfig }, noCfnFile: true }; -} -// write to the transformer conf if the resolverConfig is valid -async function writeResolverConfig(resolverConfig, resourceDir) { - if (resolverConfig && (resolverConfig.project || resolverConfig.models)) { - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - localTransformerConfig.ResolverConfig = resolverConfig; - await writeTransformerConfiguration(resourceDir, localTransformerConfig); - } -} - -async function updateTransformerConfigVersion(resourceDir) { - const localTransformerConfig = await readTransformerConfiguration(resourceDir); - localTransformerConfig.Version = TRANSFORM_CURRENT_VERSION; - localTransformerConfig.ElasticsearchWarning = true; - await writeTransformerConfiguration(resourceDir, localTransformerConfig); -} - -async function createSyncFunction(context) { - const targetDir = context.amplify.pathManager.getBackendDirPath(); - const pluginDir = __dirname; - const [shortId] = uuid().split('-'); - - const functionName = `syncConflictHandler${shortId}`; - - const functionProps = { - functionName: `${functionName}`, - roleName: `${functionName}LambdaRole`, - }; - - const copyJobs = [ - { - dir: pluginDir, - template: '../sync-conflict-handler-assets/sync-conflict-handler-index.js.ejs', - target: `${targetDir}/function/${functionName}/src/index.js`, - }, - { - dir: pluginDir, - template: '../sync-conflict-handler-assets/sync-conflict-handler-package.json.ejs', - target: `${targetDir}/function/${functionName}/src/package.json`, - }, - { - dir: pluginDir, - template: '../sync-conflict-handler-assets/sync-conflict-handler-template.json.ejs', - target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + return { + answers: resourceAnswers, + output: { + authConfig, }, - ]; - - // copy over the files - await context.amplify.copyBatch(context, copyJobs, functionProps, true); - - const backendConfigs = { - service: FunctionServiceName.LambdaFunction, - providerPlugin: 'awscloudformation', - build: true, + noCfnFile: true, + resolverConfig, + schemaContent, + askToEdit, }; +}; - await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - context.print.success(`Successfully added ${functionName} function locally`); - - return functionName + '-${env}'; -} - -async function updateWalkthrough(context) { +export const updateWalkthrough = async (context): Promise => { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; let authConfig; let defaultAuthType; - let resolverConfig; const resources = allResources.filter(resource => resource.service === 'AppSync'); // There can only be one appsync resource @@ -374,22 +177,11 @@ async function updateWalkthrough(context) { } else { context.print.error('No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'); process.exit(0); - return; - } - - const parametersFilePath = path.join(resourceDir, parametersFileName); - let parameters = {}; - - try { - parameters = context.amplify.readJsonFile(parametersFilePath); - } catch (e) { - context.print.error('Parameters file not found'); - context.print.info(e.stack); } // Get models - - const project = await TransformPackage.readProjectConfiguration(resourceDir); + const project = await readProjectConfiguration(resourceDir); + let resolverConfig = project.config.ResolverConfig; // Check for common errors const directiveMap = collectDirectivesByTypeNames(project.schema); @@ -413,7 +205,7 @@ async function updateWalkthrough(context) { }, ]; // check if DataStore is enabled for the entire API - if (project.config && project.config.ResolverConfig) { + if (project.config && !_.isEmpty(project.config.ResolverConfig)) { updateChoices.push({ name: 'Disable DataStore for entire API', value: 'disableDatastore' }); } else { updateChoices.push({ name: 'Enable DataStore for entire API', value: 'enableDatastore' }); @@ -426,61 +218,37 @@ async function updateWalkthrough(context) { choices: updateChoices, }; - let { updateOption } = await inquirer.prompt([updateOptionQuestion]); + const { updateOption } = await inquirer.prompt([updateOptionQuestion]); if (updateOption === 'enableDatastore') { resolverConfig = { - project: { ConflictHandler: 'AUTOMERGE', ConflictDetection: 'VERSION' }, + project: { ConflictHandler: ConflictHandlerType.AUTOMERGE, ConflictDetection: 'VERSION' }, }; } else if (updateOption === 'disableDatastore') { - delete project.config.ResolverConfig; - await writeTransformerConfiguration(resourceDir, project.config); + resolverConfig = {}; } else if (updateOption === 'authUpdate') { - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); - authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); - await checkForCognitoUserPools(context, parameters, authConfig); + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); + authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); } else if (updateOption === 'all') { - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context, parameters)); - ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes)); - await checkForCognitoUserPools(context, parameters, authConfig); + ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); + ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes)); } - if (authConfig) { - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); - - if (amplifyMeta[category][resourceName].output.securityType) { - delete amplifyMeta[category][resourceName].output.securityType; - } - - amplifyMeta[category][resourceName].output.authConfig = authConfig; - let jsonString = JSON.stringify(amplifyMeta, null, 4); - fs.writeFileSync(amplifyMetaFilePath, jsonString, 'utf8'); - - const backendConfigFilePath = context.amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); - - if (backendConfig[category][resourceName].output.securityType) { - delete backendConfig[category][resourceName].output.securityType; - } - - backendConfig[category][resourceName].output.authConfig = authConfig; - jsonString = JSON.stringify(backendConfig, null, 4); - fs.writeFileSync(backendConfigFilePath, jsonString, 'utf8'); - } - - if (resolverConfig) { - await writeResolverConfig(resolverConfig, resourceDir); - } - - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters, - authConfig, - }); -} + 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 askAdditionalQuestions(context, parameters, authConfig, defaultAuthType, modelTypes) { +async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { let resolverConfig; const advancedSettingsQuestion = { @@ -502,22 +270,22 @@ async function askAdditionalQuestions(context, parameters, authConfig, defaultAu const advancedSettingsAnswer = await inquirer.prompt([advancedSettingsQuestion]); if (advancedSettingsAnswer.advancedSettings) { - authConfig = await askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType); - resolverConfig = await askResolverConflictQuestion(context, parameters, modelTypes); + authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); + resolverConfig = await askResolverConflictQuestion(context, modelTypes); } return { authConfig, resolverConfig }; } -async function askResolverConflictQuestion(context, parameters, modelTypes) { - let resolverConfig = {}; +async function askResolverConflictQuestion(context, modelTypes?) { + let resolverConfig: any = {}; if (await context.prompt.confirm('Configure conflict detection?')) { const askConflictResolutionStrategy = async msg => { let conflictResolutionStrategy; do { - const conflictResolutionQuestion = { + const conflictResolutionQuestion: ListQuestion = { type: 'list', name: 'conflictResolutionStrategy', message: msg, @@ -542,20 +310,22 @@ async function askResolverConflictQuestion(context, parameters, modelTypes) { ], }; if (conflictResolutionStrategy === 'Learn More') { - conflictResolutionQuestion.prefix = syncAssets.getDataStoreLearnMore(); + conflictResolutionQuestion.prefix = dataStoreLearnMore; } ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); - let syncConfig = { + let syncConfig: any = { ConflictHandler: conflictResolutionStrategy, ConflictDetection: 'VERSION', }; if (conflictResolutionStrategy === 'LAMBDA') { - const lambdaFunctionName = await askSyncFunctionQuestion(context); - syncConfig.LambdaConflictHandler = {}; - syncConfig.LambdaConflictHandler.name = lambdaFunctionName; + const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); + syncConfig.LambdaConflictHandler = { + name: lambdaFunctionName, + new: newFunction, + }; } return syncConfig; @@ -611,10 +381,9 @@ async function askSyncFunctionQuestion(context) { const { syncLambdaAnswer } = await inquirer.prompt([syncLambdaQuestion]); let lambdaFunctionName; + const newFunction = syncLambdaAnswer === 'NEW'; - if (syncLambdaAnswer === 'NEW') { - lambdaFunctionName = await createSyncFunction(context); - } else { + if (!newFunction) { const syncLambdaNameQuestion = { type: 'input', name: 'lambdaFunctionName', @@ -624,40 +393,50 @@ async function askSyncFunctionQuestion(context) { ({ lambdaFunctionName } = await inquirer.prompt([syncLambdaNameQuestion])); } - return lambdaFunctionName; + return { newFunction, lambdaFunctionName }; } -async function askDefaultAuthQuestion(context, parameters) { +async function askDefaultAuthQuestion(context) { + const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + 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]); - const authConfig = { - additionalAuthenticationProviders: [], - }; - // Get default auth configured const defaultAuth = await askAuthQuestions(defaultAuthType, context); - authConfig.defaultAuthentication = defaultAuth; - - return { authConfig, defaultAuthType }; + return { + authConfig: { + defaultAuthentication: defaultAuth, + }, + defaultAuthType, + }; } -async function askAdditionalAuthQuestions(context, parameters, authConfig, defaultAuthType) { +async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { if (await context.prompt.confirm('Configure additional auth types?')) { + authConfig.additionalAuthenticationProviders = []; // Get additional auth configured const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType); - const additionalProvidersQuestion = { + const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + 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]); @@ -674,34 +453,6 @@ async function askAdditionalAuthQuestions(context, parameters, authConfig, defau return authConfig; } -async function checkForCognitoUserPools(context, parameters, authConfig) { - const additionalUserPoolProviders = authConfig.additionalAuthenticationProviders.filter( - provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS', - ); - const additionalUserPoolProvider = additionalUserPoolProviders.length > 0 ? additionalUserPoolProviders[0] : undefined; - - if (authConfig.defaultAuthentication.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { - let userPoolId; - const configuredUserPoolName = checkIfAuthExists(context); - - 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.'); - } - - parameters.AuthCognitoUserPoolId = { - 'Fn::GetAtt': [userPoolId, 'Outputs.UserPoolId'], - }; - } else { - delete parameters.AuthCognitoUserPoolId; - } -} - async function askAuthQuestions(authType, context, printLeadText = false) { if (authType === 'AMAZON_COGNITO_USER_POOLS') { if (printLeadText) { @@ -881,32 +632,14 @@ function resourceAlreadyExists(context) { return resourceName; } -function checkIfAuthExists(context) { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); - let authResourceName; - const authServiceName = 'Cognito'; - const authCategory = 'auth'; - - if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { - const categoryResources = amplifyMeta[authCategory]; - Object.keys(categoryResources).forEach(resource => { - if (categoryResources[resource].service === authServiceName) { - authResourceName = resource; - } - }); - } - return authResourceName; -} - -async function migrate(context) { +export const migrate = async context => { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true, }); -} +}; -function getIAMPolicies(resourceName, crudOptions) { +export const getIAMPolicies = (resourceName, crudOptions) => { let policy = {}; const actions = []; @@ -955,9 +688,15 @@ function getIAMPolicies(resourceName, crudOptions) { const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; return { policy, attributes }; -} +}; -function getAuthTypes(authConfig) { +const templateSchemaFilter = authConfig => { + const authIncludesCognito = getAuthTypes(authConfig).includes('AMAZON_COGNITO_USER_POOLS'); + return (templateOption: ListChoiceOptions): boolean => + authIncludesCognito || templateOption.value !== 'single-object-auth-schema.graphql'; +}; + +const getAuthTypes = authConfig => { const additionalAuthTypes = (authConfig.additionalAuthenticationProviders || []) .map(provider => provider.authenticationType) .filter(t => !!t); @@ -965,12 +704,4 @@ function getAuthTypes(authConfig) { const uniqueAuthTypes = new Set([...additionalAuthTypes, authConfig.defaultAuthentication.authenticationType]); return [...uniqueAuthTypes.keys()]; -} - -module.exports = { - serviceWalkthrough, - updateWalkthrough, - openConsole, - migrate, - getIAMPolicies, }; diff --git a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js similarity index 90% rename from packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js index 54ccc059cd..bbde2f3300 100644 --- a/packages/amplify-category-api/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js @@ -13,10 +13,4 @@ Other writers are rejected and must handle merges through other means, such as a 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. `; -function getDataStoreLearnMore() { - return chalk.green(learnMore); -} - -module.exports = { - getDataStoreLearnMore, -}; +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 new file mode 100644 index 0000000000..c3a4f43f08 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/amplify-meta-utils.ts @@ -0,0 +1,40 @@ +export const checkIfAuthExists = context => { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); + let authResourceName; + const authServiceName = 'Cognito'; + const authCategory = 'auth'; + + if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { + const categoryResources = amplifyMeta[authCategory]; + Object.keys(categoryResources).forEach(resource => { + if (categoryResources[resource].service === authServiceName) { + authResourceName = resource; + } + }); + } + return authResourceName; +}; + +// some utility functions to extract the AppSync API name and config from amplify-meta + +export const getAppSyncAuthConfig = projectMeta => { + const entry = getAppSyncAmplifyMetaEntry(projectMeta); + if (entry) { + const value = entry[1] as any; + return value && value.output ? value.output.authConfig : {}; + } +}; + +export const getAppSyncResourceName = (projectMeta: any): 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: any) => { + return Object.entries(projectMeta.api || {}).find(([, value]) => (value as any).service === '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 new file mode 100644 index 0000000000..d52094eae5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper.ts @@ -0,0 +1,79 @@ +import { + AppSyncAuthType, + AppSyncAPIKeyAuthType, + AppSyncCognitoUserPoolsAuthType, + AppSyncOpenIDConnectAuthType, +} 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, + 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, + }), +}; + +const appSyncAuthTypeToAuthConfigMap: Record any> = { + API_KEY: (authType: AppSyncAPIKeyAuthType) => ({ + authenticationType: 'API_KEY', + apiKeyConfig: { + apiKeyExpirationDays: authType.expirationTime, + 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, + }, + }), +}; 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 new file mode 100644 index 0000000000..05b3688da0 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/dynamic-imports.ts @@ -0,0 +1,4 @@ +export const serviceMetadataFor = async service => (await import('../../supported-services')).supportedServices[service]; +export const datasourceMetadataFor = async datasource => (await import('../../supported-datasources')).supportedDatasources[datasource]; +export const getServiceWalkthrough = async walkthroughFilename => + (await import(`../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 new file mode 100644 index 0000000000..96dbb2acfd --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/edit-schema-flow.ts @@ -0,0 +1,18 @@ +import inquirer, { ConfirmQuestion } from 'inquirer'; +import path from 'path'; +import { category } from '../../../category-constants'; +import { gqlSchemaFilename } from '../aws-constants'; + +export const editSchemaFlow = async (context: any, apiName: string) => { + const prompt: ConfirmQuestion = { + type: 'confirm', + name: 'editNow', + message: 'Do you want to edit the schema now?', + default: false, + }; + + if (!(await inquirer.prompt(prompt)).editNow) return; + + const schemaPath = path.join(context.amplify.pathManager.getBackendDirPath(), category, apiName, gqlSchemaFilename); + await context.amplify.openEditor(context, schemaPath, false); +}; 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 new file mode 100644 index 0000000000..0ca3b96cf5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/resolver-config-to-conflict-resolution-bi-di-mapper.ts @@ -0,0 +1,105 @@ +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 (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 new file mode 100644 index 0000000000..127baf2060 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts @@ -0,0 +1,37 @@ +export const validatePathName = (name: string, paths: { name: string }[]) => { + 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.'; + } + + const split = name.split('/').filter(sub => sub !== ''); // because name starts with a /, this filters out the first empty element + // Check if any prefix of this path matches an existing path + let subpath = ''; + const subMatch = split.some(sub => { + subpath = `${subpath}/${sub}`; + return paths.map(path => path.name).find(name => name === subpath) !== undefined; + }); + if (subMatch) { + return `An existing path already matches this sub-path: ${subpath}`; + } + return true; +}; + +// 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 new file mode 100644 index 0000000000..5a8fb460a3 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request.ts @@ -0,0 +1,18 @@ +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 new file mode 100644 index 0000000000..f458e8e429 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -0,0 +1,36 @@ +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', + defaultValuesFilename: 'appSync-rds-defaults.js', + serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', + cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', + provider: 'awscloudformation', + availableRegions: ['us-east-1', 'us-east-2', 'us-west-2', 'ap-northeast-1', 'eu-west-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 new file mode 100644 index 0000000000..9bf9cbba01 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -0,0 +1,152 @@ +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]+$', + onErrorMsg: 'You can use the following characters: a-z A-Z 0-9', + }, + 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', + }, + ], + 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, Mac OS only)', + value: 'vim', + }, + { + name: 'Emacs (via Terminal, Mac OS 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', + defaultValuesFilename: 'appSync-defaults.js', + 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', + defaultValuesFilename: 'apigw-defaults.js', + serviceWalkthroughFilename: 'apigw-walkthrough.js', + cfnFilename: 'apigw-cloudformation-template-default.json.ejs', + provider: 'awscloudformation', + }, +}; diff --git a/packages/amplify-category-api/templates/api.ejs b/packages/amplify-category-api/templates/api.ejs deleted file mode 100644 index 1206116e91..0000000000 --- a/packages/amplify-category-api/templates/api.ejs +++ /dev/null @@ -1,382 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: "AWS Amplify API" -Parameters: - LambdaFunctionName: - Type: String - Default: "EmberServerlessFunction" - Description: "AWS Amplify created function" - AppClientName: - Type: String - Default: "EmberServerlessWebClient" - Description: "Cognito user pools app client name" -Resources: - ApiGatewayApi: - Type: AWS::Serverless::Api - DependsOn: CognitoUserPool - Properties: - StageName: Prod - DefinitionBody: - swagger: "2.0" - info: - version: "2017-02-24T04:09:00Z" - title: "EmberServerlessAPI" - basePath: "/Prod" - schemes: - - "https" - paths: - "/docs": - get: - consumes: - - "application/json" - produces: - - "application/json" - parameters: - - name: "user" - in: "header" - required: false - type: "string" - - name: "id" - in: "query" - required: false - type: "string" - responses: - "200": - description: "200 response" - schema: - $ref: "#/definitions/Empty" - headers: - Access-Control-Allow-Origin: - type: "string" - security: - - EmberServerless: [] - x-amazon-apigateway-integration: - responses: - default: - statusCode: "200" - responseParameters: - method.response.header.Access-Control-Allow-Origin: "'*'" - requestTemplates: - application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ - ## This template will pass through all parameters including path, querystring,\ - \ header, stage variables, and context through to the integration endpoint\ - \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ - \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ - \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ - \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ - \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ - #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ - \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ - \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ - \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ - ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ - \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ - ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ - ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ - \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ - \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ - \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ - \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ - \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ - source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ - ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ - \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ - ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ - \ : \"$context.resourcePath\"\n }\n}\n" - uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] - passthroughBehavior: "when_no_templates" - httpMethod: "POST" - contentHandling: "CONVERT_TO_TEXT" - type: "aws" - post: - consumes: - - "application/json" - produces: - - "application/json" - parameters: - - name: "user" - in: "header" - required: false - type: "string" - responses: - "200": - description: "200 response" - schema: - $ref: "#/definitions/Empty" - headers: - Access-Control-Allow-Origin: - type: "string" - security: - - EmberServerless: [] - x-amazon-apigateway-integration: - responses: - default: - statusCode: "200" - responseParameters: - method.response.header.Access-Control-Allow-Origin: "'*'" - requestTemplates: - application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ - ## This template will pass through all parameters including path, querystring,\ - \ header, stage variables, and context through to the integration endpoint\ - \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ - \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ - \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ - \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ - \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ - #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ - \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ - \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ - \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ - ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ - \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ - ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ - ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ - \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ - \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ - \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ - \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ - \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ - source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ - ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ - \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ - ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ - \ : \"$context.resourcePath\"\n }\n}\n" - uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] - passthroughBehavior: "when_no_templates" - httpMethod: "POST" - contentHandling: "CONVERT_TO_TEXT" - type: "aws" - delete: - consumes: - - "application/json" - produces: - - "application/json" - parameters: - - name: "user" - in: "header" - required: false - type: "string" - responses: - "200": - description: "200 response" - schema: - $ref: "#/definitions/Empty" - headers: - Access-Control-Allow-Origin: - type: "string" - security: - - EmberServerless: [] - x-amazon-apigateway-integration: - responses: - default: - statusCode: "200" - responseParameters: - method.response.header.Access-Control-Allow-Origin: "'*'" - requestTemplates: - application/json: "## See http://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html\n\ - ## This template will pass through all parameters including path, querystring,\ - \ header, stage variables, and context through to the integration endpoint\ - \ via the body/payload\n#set($allParams = $input.params())\n{\n\"body-json\"\ - \ : $input.json('$'),\n\"params\" : {\n#foreach($type in $allParams.keySet())\n\ - \ #set($params = $allParams.get($type))\n\"$type\" : {\n #foreach($paramName\ - \ in $params.keySet())\n \"$paramName\" : \"$util.escapeJavaScript($params.get($paramName))\"\ - \n #if($foreach.hasNext),#end\n #end\n}\n #if($foreach.hasNext),#end\n\ - #end\n},\n\"stage-variables\" : {\n#foreach($key in $stageVariables.keySet())\n\ - \"$key\" : \"$util.escapeJavaScript($stageVariables.get($key))\"\n \ - \ #if($foreach.hasNext),#end\n#end\n},\n\"context\" : {\n \"user\"\ - \ : \"$context.authorizer.claims.sub\",\n\t\"email\" : \"$context.authorizer.claims.email\"\ - ,\n \"account-id\" : \"$context.identity.accountId\",\n \"api-id\"\ - \ : \"$context.apiId\",\n \"api-key\" : \"$context.identity.apiKey\"\ - ,\n \"authorizer-principal-id\" : \"$context.authorizer.principalId\"\ - ,\n \"caller\" : \"$context.identity.caller\",\n \"cognito-authentication-provider\"\ - \ : \"$context.identity.cognitoAuthenticationProvider\",\n \"cognito-authentication-type\"\ - \ : \"$context.identity.cognitoAuthenticationType\",\n \"cognito-identity-id\"\ - \ : \"$context.identity.cognitoIdentityId\",\n \"cognito-identity-pool-id\"\ - \ : \"$context.identity.cognitoIdentityPoolId\",\n \"httpMethod\" :\ - \ \"$context.httpMethod\",\n \"stage\" : \"$context.stage\",\n \"\ - source-ip\" : \"$context.identity.sourceIp\",\n \"user\" : \"$context.identity.user\"\ - ,\n \"user-agent\" : \"$context.identity.userAgent\",\n \"user-arn\"\ - \ : \"$context.identity.userArn\",\n \"request-id\" : \"$context.requestId\"\ - ,\n \"resource-id\" : \"$context.resourceId\",\n \"resource-path\"\ - \ : \"$context.resourcePath\"\n }\n}\n" - uri: !Join [ "", [ "arn:aws:apigateway:", !Ref "AWS::Region", ":lambda:path/2015-03-31/functions/arn:aws:lambda:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":function:", !Ref "LambdaFunctionName", "/invocations" ] ] - passthroughBehavior: "when_no_templates" - httpMethod: "POST" - contentHandling: "CONVERT_TO_TEXT" - type: "aws" - 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: "'GET,OPTIONS,POST,PUT,DELETE'" - method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token,user'" - method.response.header.Access-Control-Allow-Origin: "'*'" - requestTemplates: - application/json: "{\"statusCode\": 200}" - passthroughBehavior: "when_no_match" - type: "mock" - securityDefinitions: - EmberServerless: - type: "apiKey" - name: "user" - in: "header" - x-amazon-apigateway-authtype: "cognito_user_pools" - x-amazon-apigateway-authorizer: - providerARNs: - - !GetAtt CognitoUserPool.Arn - type: "cognito_user_pools" - definitions: - Empty: - type: "object" - title: "Empty Schema" - LambdaFunction: - Type: AWS::Serverless::Function - Properties: - FunctionName: !Ref LambdaFunctionName - Handler: index.handler - Runtime: nodejs4.3 - Policies: AmazonDynamoDBFullAccess - Environment: - Variables: - TABLE_NAME: !Ref Table - Events: - GetDocs: - Type: Api - Properties: - RestApiId: !Ref ApiGatewayApi - Path: /docs - Method: GET - NewDoc: - Type: Api - Properties: - RestApiId: !Ref ApiGatewayApi - Path: /docs - Method: POST - DeleteDoc: - Type: Api - Properties: - RestApiId: !Ref ApiGatewayApi - Path: /docs - Method: DELETE - CognitoUserPool: - Type: AWS::Cognito::UserPool - Properties: - UserPoolName: EmberServerless - AutoVerifiedAttributes: - - "email" - CognitoUserPoolClient: - Type: AWS::Cognito::UserPoolClient - DependsOn: CognitoUserPool - Properties: - ClientName: !Ref AppClientName - UserPoolId: !Ref CognitoUserPool - GenerateSecret: false - CognitoIdentityPool: - Type: AWS::Cognito::IdentityPool - Properties: - AllowUnauthenticatedIdentities: true - CognitoIdentityProviders: - - ClientId: !Ref CognitoUserPoolClient - ProviderName: !GetAtt CognitoUserPool.ProviderName - CognitoIdentityPoolRoles: - Type: AWS::Cognito::IdentityPoolRoleAttachment - DependsOn: CognitoIdentityPool - Properties: - IdentityPoolId: !Ref CognitoIdentityPool - Roles: - authenticated: !GetAtt AuthenticatedRole.Arn - unauthenticated: !GetAtt UnauthenticatedRole.Arn - UnauthenticatedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Federated: cognito-identity.amazonaws.com - Action: sts:AssumeRoleWithWebIdentity - Condition: - StringEquals: - cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool - ForAnyValue:StringLike: - cognito-identity.amazonaws.com:amr: unauthenticated - Policies: - - - PolicyName: EmberServerlessUnauthenticatedApi - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - mobileanalytics:PutEvents - - cognito-sync:* - Resource: - - "*" - AuthenticatedRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Principal: - Federated: cognito-identity.amazonaws.com - Action: sts:AssumeRoleWithWebIdentity - Condition: - StringEquals: - cognito-identity.amazonaws.com:aud: !Ref CognitoIdentityPool - ForAnyValue:StringLike: - cognito-identity.amazonaws.com:amr: authenticated - Policies: - - - PolicyName: EmberServerlessAuthenticatedApi - PolicyDocument: - Version: '2012-10-17' - Statement: - - Effect: Allow - Action: - - execute-api:Invoke - Resource: !Join [ "", [ "arn:aws:execute-api:", !Ref "AWS::Region", ":", !Ref "AWS::AccountId", ":", !Ref ApiGatewayApi, "/*" ] ] - Table: - Type: AWS::Serverless::SimpleTable -Outputs: - CognitoIdentityPoolId: - Description: Cognito Identity Pool ID - Value: !Ref CognitoIdentityPool - CognitoUserPoolsId: - Description: Cognito User Pools ID - Value: !Ref CognitoUserPool - CognitoUserPoolsClientId: - Description: Cognito User Pools App Client ID - Value: !Ref CognitoUserPoolClient - Api: - Description: API Gateway ID - Value: !Ref ApiGatewayApi - ApiUrl: - Description: URL of your API endpoint - Value: !Join - - '' - - - https:// - - !Ref ApiGatewayApi - - '.execute-api.' - - !Ref 'AWS::Region' - - '.amazonaws.com/Prod' diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json new file mode 100644 index 0000000000..bbff900511 --- /dev/null +++ b/packages/amplify-category-api/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "lib", + "rootDir": "src", + "strict": false, // because package has been converted from js + "allowJs": true + }, + "exclude": [ + "coverage", + "lib", + "src/__tests__" + ], + "references": [ + {"path": "../amplify-headless-interface"}, + {"path": "../graphql-transformer-core"}, + {"path": "../amplify-util-headless-input"}, + ] +} From 544cb0b50194d7c20a5063c6b058e26499028787 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Tue, 21 Jul 2020 17:49:57 -0700 Subject: [PATCH 328/587] fix: remove mutableParametersState from stored function-params (#4897) --- packages/amplify-category-api/src/index.ts | 40 ++++++++++++---------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 394da3ebca..78b09b5205 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -143,26 +143,28 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { const permissionPolicies = []; const resourceAttributes = []; - Object.keys(resourceOpsMapping).forEach(resourceName => { - try { - const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); - if (providerController) { - const { policy, attributes } = providerController.getPermissionPolicies( - context, - amplifyMeta[category][resourceName].service, - resourceName, - resourceOpsMapping[resourceName], - ); - permissionPolicies.push(policy); - resourceAttributes.push({ resourceName, attributes, category }); - } else { - context.print.error(`Provider not configured for ${category}: ${resourceName}`); + await Promise.all( + Object.keys(resourceOpsMapping).map(async resourceName => { + try { + const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + if (providerController) { + const { policy, attributes } = await providerController.getPermissionPolicies( + context, + amplifyMeta[category][resourceName].service, + resourceName, + resourceOpsMapping[resourceName], + ); + permissionPolicies.push(policy); + resourceAttributes.push({ resourceName, attributes, category }); + } else { + context.print.error(`Provider not configured for ${category}: ${resourceName}`); + } + } catch (e) { + context.print.warning(`Could not get policies for ${category}: ${resourceName}`); + throw e; } - } catch (e) { - context.print.warning(`Could not get policies for ${category}: ${resourceName}`); - throw e; - } - }); + }), + ); return { permissionPolicies, resourceAttributes }; } From 2b08c3ca252a4df8c491aada8964fd67fd587ebf Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Wed, 22 Jul 2020 11:28:29 -0700 Subject: [PATCH 329/587] chore: fix test-ci script to run all unit tests (#4900) --- packages/amplify-category-api/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 83051ceb03..d4484b7265 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,8 +13,7 @@ "scripts": { "build": "tsc", "clean": "rimraf lib tsconfig.tsbuildinfo", - "test": "jest", - "test-ci": "jest --ci -i" + "test": "jest" }, "dependencies": { "amplify-category-auth": "2.16.5", From 51cede35e808084830444843eed5f255dc02f5dd Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 23 Jul 2020 17:06:34 -0700 Subject: [PATCH 330/587] chore(release): Publish [ci skip] (#4926) - amplify-app@2.17.5 - amplify-appsync-simulator@1.22.0 - amplify-category-analytics@2.17.6 - amplify-category-api@2.21.0 - amplify-category-auth@2.17.0 - amplify-category-function@2.22.0 - amplify-category-hosting@2.4.1 - amplify-category-interactions@2.4.6 - amplify-category-notifications@2.15.15 - amplify-category-predictions@2.4.6 - amplify-category-storage@2.6.0 - amplify-category-xr@2.4.6 - amplify-cli-core@1.1.0 - @aws-amplify/cli@4.25.0 - amplify-codegen-appsync-model-plugin@1.20.1 - amplify-codegen@2.15.14 - amplify-console-integration-tests@1.2.16 - amplify-dynamodb-simulator@1.14.1 - amplify-e2e-core@1.3.0 - amplify-e2e-tests@2.20.0 - amplify-frontend-ios@2.13.7 - amplify-go-function-runtime-provider@1.2.1 - amplify-graphql-docs-generator@2.1.14 - amplify-graphql-types-generator@2.4.0 - amplify-headless-interface@1.1.0 - amplify-java-function-template-provider@1.3.0 - amplify-migration-tests@2.17.13 - amplify-nodejs-function-runtime-provider@1.1.1 - amplify-nodejs-function-template-provider@1.2.0 - amplify-provider-awscloudformation@4.23.0 - amplify-util-headless-input@1.1.0 - amplify-util-mock@3.23.0 - amplify-velocity-template@1.2.0 - graphql-auth-transformer@6.19.0 - graphql-connection-transformer@4.18.6 - graphql-dynamodb-transformer@6.19.7 - graphql-elasticsearch-transformer@4.7.9 - graphql-function-transformer@2.3.14 - graphql-http-transformer@4.15.14 - graphql-key-transformer@2.19.6 - graphql-mapping-template@4.14.0 - graphql-predictions-transformer@2.3.14 - graphql-relational-schema-transformer@2.15.11 - graphql-transformer-common@4.17.6 - graphql-transformer-core@6.20.0 - graphql-transformers-e2e-tests@6.18.7 - graphql-versioned-transformer@4.15.14 Co-authored-by: aws-amplify-bot --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fa39ec5156..dfa390f8fc 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d4484b7265..b7b39e954f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.20.5", + "version": "2.21.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,14 +16,14 @@ "test": "jest" }, "dependencies": { - "amplify-category-auth": "2.16.5", - "amplify-category-function": "2.21.5", - "amplify-util-headless-input": "1.0.0", + "amplify-category-auth": "2.17.0", + "amplify-category-function": "2.22.0", + "amplify-util-headless-input": "1.1.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.10", - "graphql-transformer-core": "6.19.5", + "graphql-relational-schema-transformer": "2.15.11", + "graphql-transformer-core": "6.20.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 4baacec6f22d1ec92138255a894a6fd07b1f0c0c Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Mon, 27 Jul 2020 11:10:02 -0700 Subject: [PATCH 331/587] fix: populate API_KEY env var when present (#4923) --- .../cfn-api-artifact-handler.test.ts | 21 ++++++++- .../appSync-walkthrough.test.ts | 38 ++++++++++++++++ .../utils/amplify-meta-utils.test.ts | 45 +++++++++++++++++++ .../cfn-api-artifact-handler.ts | 5 ++- .../provider-utils/awscloudformation/index.ts | 2 +- .../appSync-walkthrough.ts | 9 ++-- .../{syncAssets.js => syncAssets.ts} | 0 .../utils/amplify-meta-utils.ts | 15 +++++++ .../utils/print-api-key-warnings.ts | 17 +++++++ 9 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts rename packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/{syncAssets.js => syncAssets.ts} (100%) create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts 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 index 65c8ba3636..523089d70c 100644 --- 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 @@ -6,7 +6,11 @@ import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; import { category } from '../../../category-constants'; import { writeTransformerConfiguration } from 'graphql-transformer-core'; import { rootAssetDir } from '../../../provider-utils/awscloudformation/aws-constants'; -import { getAppSyncResourceName, getAppSyncAuthConfig } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +import { + getAppSyncResourceName, + getAppSyncAuthConfig, + authConfigHasApiKey, +} from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; import _ from 'lodash'; jest.mock('fs-extra'); @@ -20,12 +24,14 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', checkIfAuthExists: jest.fn(), getAppSyncResourceName: jest.fn(() => testApiName), getAppSyncAuthConfig: jest.fn(() => ({})), + authConfigHasApiKey: jest.fn(() => true), })); const fs_mock = (fs as unknown) as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; +const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; const backendDirPathStub = 'backendDirPath'; @@ -34,6 +40,7 @@ const testApiName = 'testApiName'; const context_stub = { print: { success: jest.fn(), + warning: jest.fn(), }, amplify: { updateamplifyMetaAfterResourceAdd: jest.fn(), @@ -222,4 +229,16 @@ describe('update artifacts', () => { expect(context_stub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(1); expect(context_stub.amplify.updateBackendConfigAfterResourceUpdate.mock.calls.length).toBe(1); }); + + it('prints warning when adding API key auth', async () => { + authConfigHasApiKey_mock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.print.warning.mock.calls.length).toBe(2); + }); + + it('prints warning when removing API key auth', async () => { + authConfigHasApiKey_mock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); + expect(context_stub.print.warning.mock.calls.length).toBe(3); + }); }); 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 new file mode 100644 index 0000000000..4d64805a2d --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts @@ -0,0 +1,38 @@ +import { getIAMPolicies } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; +import { authConfigHasApiKey } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ + getAppSyncAuthConfig: jest.fn(), + authConfigHasApiKey: jest.fn(), +})); + +const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; +const context_stub = { + amplify: { + getProjectMeta: jest.fn(), + }, +}; + +describe('get IAM policies', () => { + it('does not include API key if none exists', () => { + authConfigHasApiKey_mock.mockImplementationOnce(() => false); + const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub); + expect(attributes).toMatchInlineSnapshot(` + Array [ + "GraphQLAPIIdOutput", + "GraphQLAPIEndpointOutput", + ] + `); + }); + + it('includes API key if it exists', () => { + authConfigHasApiKey_mock.mockImplementationOnce(() => true); + const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub); + expect(attributes).toMatchInlineSnapshot(` + Array [ + "GraphQLAPIIdOutput", + "GraphQLAPIEndpointOutput", + "GraphQLAPIKeyOutput", + ] + `); + }); +}); 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 new file mode 100644 index 0000000000..0ca8d87ce6 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/amplify-meta-utils.test.ts @@ -0,0 +1,45 @@ +import { authConfigHasApiKey } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; + +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); + }); +}); 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 index 8e0a695001..3186996ce8 100644 --- 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 @@ -16,7 +16,8 @@ import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-aut import uuid from 'uuid'; import _ from 'lodash'; import { ServiceName as FunctionServiceName } from 'amplify-category-function'; -import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists } from './utils/amplify-meta-utils'; +import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from './utils/amplify-meta-utils'; +import { printApiKeyWarnings } from './utils/print-api-key-warnings'; export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { return new CfnApiArtifactHandler(context); @@ -103,6 +104,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await writeResolverConfig(updates.conflictResolution, resourceDir); } const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); + const oldConfigHadApiKey = authConfigHasApiKey(authConfig); if (updates.defaultAuthType) { authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); } @@ -117,6 +119,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); + printApiKeyWarnings(this.context, oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; private writeSchema = (resourceDir: string, schema: string) => { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index 00b98fe6d1..7c4acb451f 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -91,5 +91,5 @@ export async function getPermissionPolicies(context, service, resourceName, crud return; } - return getIAMPolicies(resourceName, crudOptions); + return getIAMPolicies(resourceName, crudOptions, context); } 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 index 1c3c881215..acfbca72c2 100644 --- 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 @@ -4,14 +4,14 @@ import inquirer from 'inquirer'; import fs from 'fs-extra'; import path from 'path'; import open from 'open'; -import { rootAssetDir, cfnParametersFilename } from '../aws-constants'; +import { rootAssetDir } from '../aws-constants'; import { collectDirectivesByTypeNames, readProjectConfiguration, ConflictHandlerType } from 'graphql-transformer-core'; import { category } from '../../../category-constants'; import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; -import { getAppSyncAuthConfig, checkIfAuthExists } from '../utils/amplify-meta-utils'; +import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; const serviceName = 'AppSync'; const providerName = 'awscloudformation'; @@ -639,7 +639,7 @@ export const migrate = async context => { }); }; -export const getIAMPolicies = (resourceName, crudOptions) => { +export const getIAMPolicies = (resourceName, crudOptions, context) => { let policy = {}; const actions = []; @@ -686,6 +686,9 @@ export const getIAMPolicies = (resourceName, crudOptions) => { }; const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; + if (authConfigHasApiKey(getAppSyncAuthConfig(context.amplify.getProjectMeta()))) { + attributes.push('GraphQLAPIKeyOutput'); + } return { policy, attributes }; }; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts similarity index 100% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/sync-conflict-handler-assets/syncAssets.ts 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 index c3a4f43f08..c2671df70f 100644 --- 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 @@ -1,3 +1,18 @@ +import _ from 'lodash'; + +export const authConfigHasApiKey = authConfig => { + 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 = context => { const { amplify } = context; const { amplifyMeta } = amplify.getProjectDetails(); 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 new file mode 100644 index 0000000000..f98601878b --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts @@ -0,0 +1,17 @@ +// 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 = (context, oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { + if (oldConfigHadApiKey && !newConfigHasApiKey) { + context.print.warning('The API_KEY auth type has been removed from the API.'); + context.print.warning( + 'If other resources depend on this API, run "amplify update " and reselect this API to remove the dependency on the API key.', + ); + context.print.warning('⚠️ This must be done before running "amplify push" to prevent a push failure'); + } + + if (!oldConfigHadApiKey && newConfigHasApiKey) { + context.print.warning('The API_KEY auth type has been added to the API.'); + context.print.warning( + '⚠️ 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.', + ); + } +}; From 7f44bae5122390543440b2f3dd34bb1821daac1e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 29 Jul 2020 17:07:16 +0000 Subject: [PATCH 332/587] chore(release): Publish [ci skip] - amplify-app@2.17.6 - amplify-appsync-simulator@1.23.0 - amplify-category-analytics@2.17.7 - amplify-category-api@2.22.0 - amplify-category-auth@2.18.0 - amplify-category-function@2.23.0 - amplify-category-hosting@2.4.2 - amplify-category-interactions@2.4.7 - amplify-category-notifications@2.15.16 - amplify-category-predictions@2.4.7 - amplify-category-storage@2.7.0 - amplify-category-xr@2.4.7 - amplify-cli-core@1.2.0 - @aws-amplify/cli@4.26.0 - amplify-codegen-appsync-model-plugin@1.20.2 - amplify-codegen@2.15.15 - amplify-console-integration-tests@1.2.17 - amplify-dynamodb-simulator@1.14.2 - amplify-e2e-core@1.4.0 - amplify-e2e-tests@2.21.0 - amplify-frontend-ios@2.13.8 - amplify-go-function-runtime-provider@1.2.2 - amplify-graphql-docs-generator@2.1.15 - amplify-graphql-types-generator@2.5.0 - amplify-headless-interface@1.2.0 - amplify-java-function-template-provider@1.4.0 - amplify-migration-tests@2.17.14 - amplify-nodejs-function-runtime-provider@1.1.2 - amplify-nodejs-function-template-provider@1.3.0 - amplify-provider-awscloudformation@4.24.0 - amplify-util-headless-input@1.2.0 - amplify-util-mock@3.24.0 - amplify-velocity-template@1.3.0 - graphql-auth-transformer@6.20.0 - graphql-connection-transformer@4.18.7 - graphql-dynamodb-transformer@6.19.8 - graphql-elasticsearch-transformer@4.7.10 - graphql-function-transformer@2.3.15 - graphql-http-transformer@4.15.15 - graphql-key-transformer@2.19.7 - graphql-mapping-template@4.15.0 - graphql-predictions-transformer@2.3.15 - graphql-relational-schema-transformer@2.15.12 - graphql-transformer-common@4.17.7 - graphql-transformer-core@6.21.0 - graphql-transformers-e2e-tests@6.18.8 - graphql-versioned-transformer@4.15.15 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index dfa390f8fc..06b463b8e1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b7b39e954f..4c270715df 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.21.0", + "version": "2.22.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,14 +16,14 @@ "test": "jest" }, "dependencies": { - "amplify-category-auth": "2.17.0", - "amplify-category-function": "2.22.0", - "amplify-util-headless-input": "1.1.0", + "amplify-category-auth": "2.18.0", + "amplify-category-function": "2.23.0", + "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.11", - "graphql-transformer-core": "6.20.0", + "graphql-relational-schema-transformer": "2.15.12", + "graphql-transformer-core": "6.21.0", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From a67147185b4bc7f2e3ce8bd9489c371ac25f15fc Mon Sep 17 00:00:00 2001 From: Nick Chaloult <31291920+nchaloult@users.noreply.github.com> Date: Wed, 29 Jul 2020 13:22:00 -0400 Subject: [PATCH 333/587] feat: allow creation of REST API endpoint at root path (/) (#4649) * feat: allow creation of REST API endpoint at root path (/) re #3868 * refactor: relocate util funcs to new files to be compatible with #4834 --- .../utils/rest-api-path-utils.test.ts | 55 +++++++++++----- .../service-walkthroughs/apigw-walkthrough.ts | 61 ++++++++++++------ .../utils/rest-api-path-utils.ts | 64 +++++++++++++++++-- 3 files changed, 139 insertions(+), 41 deletions(-) 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 index 61b453ad2f..7c82402f42 100644 --- 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 @@ -1,22 +1,27 @@ -import { validatePathName, formatCFNPathParamsForExpressJs } from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; +import { + validatePathName, + checkForPathOverlap, + formatCFNPathParamsForExpressJs, +} from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; -const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }]; +const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }, { name: '/path/{with}/{params}' }]; test('validatePathName_validPath', () => { - expect(validatePathName('/some/path', stubOtherPaths)).toBe(true); - expect(validatePathName('/path/{with}/{params}', stubOtherPaths)).toBe(true); + expect(validatePathName('/some/path')).toBe(true); + expect(validatePathName('/path/{with}/{params}')).toBe(true); + expect(validatePathName('/')).toBe(true); }); test('validatePath_empty', () => { - expect(validatePathName('', stubOtherPaths)).toStrictEqual('The path must not be empty'); + expect(validatePathName('')).toStrictEqual('The path must not be empty'); }); test('validatePathName_noLeadingSlash', () => { - expect(validatePathName('no/leading/slash', stubOtherPaths)).toStrictEqual('The path must begin with / e.g. /items'); + expect(validatePathName('no/leading/slash')).toStrictEqual('The path must begin with / e.g. /items'); }); test('validatePathName_hasTrailingSlash', () => { - expect(validatePathName('/has/trailing/slash/', stubOtherPaths)).toStrictEqual('The path must not end with /'); + expect(validatePathName('/has/trailing/slash/')).toStrictEqual('The path must not end with /'); }); test('validatePathName_invalidCharacters', () => { @@ -25,22 +30,40 @@ test('validatePathName_invalidCharacters', () => { '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}', stubOtherPaths)).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{char@}', stubOtherPaths)).toStrictEqual(errorMessage); - expect(validatePathName('/invalid/{param', stubOtherPaths)).toStrictEqual(errorMessage); + expect(validatePathName('/invalid+/{char}')).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{char@}')).toStrictEqual(errorMessage); + expect(validatePathName('/invalid/{param')).toStrictEqual(errorMessage); }); -test('validatePathName_subPathMatch', () => { - expect(validatePathName('/sub/path/match', stubOtherPaths)).toStrictEqual('An existing path already matches this sub-path: /sub/path'); +test('checkForPathOverlap_subPathMatch', () => { + expect(checkForPathOverlap('/sub/path/match', stubOtherPaths)).toEqual({ + higherOrderPath: '/sub/path', + lowerOrderPath: '/sub/path/match', + }); }); -test('validatePathName_pathMatch', () => { - expect(validatePathName(stubOtherPaths[0].name, stubOtherPaths)).toStrictEqual( - 'An existing path already matches this sub-path: /other/path', - ); +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].name, stubOtherPaths)).toEqual({ + higherOrderPath: stubOtherPaths[0].name, + lowerOrderPath: stubOtherPaths[0].name, + }); }); 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/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts index 01f95ed589..1e05045d19 100644 --- 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 @@ -3,7 +3,7 @@ import path from 'path'; import fs from 'fs-extra'; import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; -import { validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; +import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; import { ServiceName as FunctionServiceName } from 'amplify-category-function'; const category = 'api'; @@ -406,6 +406,7 @@ async function askReadWrite(userType, context, privacy) { async function askPaths(context, answers, currentPath) { // const existingLambdaArns = true; + const existingFunctions = functionsExist(context); const choices = [ @@ -438,33 +439,55 @@ async function askPaths(context, answers, currentPath) { defaultFunctionType = currentPath.lambdaArn ? 'arn' : 'projectFunction'; } - const questions = [ - { - name: 'name', - type: 'input', - message: 'Provide a path (e.g., /book/{isbn}):', - default: currentPath ? currentPath.name : '/items', - validate: value => validatePathName(value, answers.paths), - }, - { + const paths = [...answers.paths]; + + let addAnotherPath; + do { + let pathName; + let isPathValid; + do { + const pathAnswer = await inquirer.prompt({ + name: 'name', + type: 'input', + message: 'Provide a path (e.g., /book/{isbn}):', + default: currentPath ? currentPath.name : '/items', + validate: value => validatePathName(value), + }); + pathName = pathAnswer.name; + + const overlapCheckResult = checkForPathOverlap(pathName, 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 inquirer.prompt({ + name: 'isOverlappingPathOK', + type: 'confirm', + message: `This path ${lowerOrderPath} is overlapping with ${higherOrderPath}. ${higherOrderPath} is going to catch all requests from ${lowerOrderPath}. Are you sure you want to continue?`, + default: false, + }) + ).isOverlappingPathOK; + } + } while (!isPathValid); + + const lambdaAnswer = await inquirer.prompt({ name: 'functionType', type: 'list', message: 'Choose a Lambda source', choices, default: defaultFunctionType, - }, - ]; - - let addAnotherPath; - const paths = [...answers.paths]; + }); - do { - const answer = await inquirer.prompt(questions); // TODO: add path validation like awsmobile-cli does - let path = { name: answer.name }; + let path = { name: pathName }; let lambda; do { - lambda = await askLambdaSource(context, answer.functionType, answer.name, currentPath); + lambda = await askLambdaSource(context, lambdaAnswer.functionType, path.name, currentPath); } while (!lambda); const privacy = await askPrivacy(context, answers, currentPath); path = { ...path, ...lambda, privacy }; 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 index 127baf2060..6bce9e16a0 100644 --- 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 @@ -1,4 +1,11 @@ -export const validatePathName = (name: string, paths: { name: string }[]) => { +// 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) => { + // "Whitelist" the path / + if (name === '/') { + return true; + } + if (name.length === 0) { return 'The path must not be empty'; } @@ -17,17 +24,62 @@ export const validatePathName = (name: string, paths: { name: string }[]) => { 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.'; } - const split = name.split('/').filter(sub => sub !== ''); // because name starts with a /, this filters out the first empty element - // Check if any prefix of this path matches an existing path + 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: { name: 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}`; - return paths.map(path => path.name).find(name => name === subpath) !== undefined; + // 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.map(path => path.name).find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); + return overlappingPath !== undefined; }); if (subMatch) { - return `An existing path already matches this sub-path: ${subpath}`; + // 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, + }; } - return true; + + // This path doesn't overlap with any of the other provided paths. + return false; }; // Convert a CloudFormation parameterized path to an ExpressJS parameterized path From dc077d8ee9d9dd929d7428eb3d8e5c8cc24372c1 Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Fri, 31 Jul 2020 12:50:30 -0700 Subject: [PATCH 334/587] fix(amplify-category-api): added check to read schema in schema dir (#3871) * fix(amplify-category-api): fixes#3082 check for schema in dir * fix(amplify-category-api): added check to read schema in schema dir * fix(amplify-category-api): conforming comments * fix: reads schema dir * fix: dumps rds schema * chore: fixing comments * fix: added tests for read schema --- packages/amplify-category-api/package.json | 2 +- .../api/add-graphql-datasource.test.js | 17 +++++++++ .../api/mock-data/invalid_schema.graphql | 0 .../commands/api/mock-data/schema.graphql | 7 ++++ .../commands/api/add-graphql-datasource.js | 38 +++++++++++++++---- 5 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/invalid_schema.graphql create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4c270715df..93cdcd7bfa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -35,7 +35,7 @@ "transform": { "^.+\\.tsx?$": "ts-jest" }, - "testRegex": "(src/__tests__/.*.test.ts)$", + "testRegex": "((\\.|/)(test|spec))\\.(jsx?|tsx?)$", "moduleFileExtensions": [ "ts", "tsx", diff --git a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js new file mode 100644 index 0000000000..118ae14401 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js @@ -0,0 +1,17 @@ +const { readSchema } = require('../../../commands/api/add-graphql-datasource'); +const path = require('path'); + +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).toThrowError('Could not parse graphql schema'); + }); +}); 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 new file mode 100644 index 0000000000..e69de29bb2 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 new file mode 100644 index 0000000000..619867da0a --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/commands/api/mock-data/schema.graphql @@ -0,0 +1,7 @@ +type Todo @model { + id: ID! + name: String! + description: String + createdAt: AWSDateTime! + updatedAt: AWSDateTime! +} diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index b467611eb4..f975bd688e 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -1,6 +1,7 @@ const fs = require('fs-extra'); const inquirer = require('inquirer'); const graphql = require('graphql'); +const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypes } = require('merge-graphql-schemas'); @@ -105,16 +106,24 @@ module.exports = { */ const apiDirPath = `${projectBackendDirPath}/${category}/${resourceName}`; fs.ensureDirSync(apiDirPath); - const graphqlSchemaFilePath = `${apiDirPath}/schema.graphql`; - fs.ensureFileSync(graphqlSchemaFilePath); - const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath, 'utf8'); - const currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); - + const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); + const schemaFileExists = fs.existsSync(graphqlSchemaFilePath); const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; + const schemaDirectoryPath = path.join(apiDirPath, 'schema'); + const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); + + if (schemaFileExists) { + const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + const concatGraphQLSchemaDoc = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); + fs.writeFileSync(graphqlSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); + } else if (schemaDirectoryExists) { + const rdsSchemaFilePath = path.join(apiDirPath, 'rds.graphql'); + const concatGraphQLSchemaDoc = mergeTypes([{}, rdsGraphQLSchemaDoc], { all: true }); + fs.writeFileSync(rdsSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); + } else { + throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); + } - const concatGraphQLSchemaDoc = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); - - fs.writeFileSync(graphqlSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); const resolversDir = `${projectBackendDirPath}/${category}/${resourceName}/resolvers`; /** @@ -158,6 +167,7 @@ module.exports = { context.usageData.emitError(err); }); }, + readSchema, }; function datasourceSelectionPrompt(context, supportedDatasources) { @@ -206,3 +216,15 @@ async function getAwsClient(context, action) { const provider = require(providerPlugins[providerName]); return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); } + +function readSchema(graphqlSchemaFilePath) { + const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); + let currGraphQLSchemaDoc; + try { + currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); + } catch (err) { + const relativePathToInput = path.relative(process.cwd(), graphqlSchemaRaw); + throw new Error(`Could not parse graphql schema \n${relativePathToInput}\n${err.message}`); + } + return currGraphQLSchemaDoc; +} From 1ccfb7098c87c476af14976cfd27380f6bb76736 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Tue, 4 Aug 2020 16:49:11 -0700 Subject: [PATCH 335/587] fix: return undefined for empty conflict resolution (#4982) Fixes issue with creating datastore tables when datastore is not enabled by checking resolver config #4965 --- .../resolver-config-to-conflict-resolution-bi-di-mapper.test.ts | 2 +- .../resolver-config-to-conflict-resolution-bi-di-mapper.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 index fa18ae097e..e0f14fa597 100644 --- 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 @@ -41,7 +41,7 @@ describe('transform ConflictResolution to ResolverConfig', () => { }); it('returns an empty object when ConflictResolution is not present', () => { - expect(conflictResolutionToResolverConfig(undefined)).toEqual({}); + expect(conflictResolutionToResolverConfig(undefined)).toEqual(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 index 0ca3b96cf5..c3e9365edf 100644 --- 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 @@ -4,6 +4,7 @@ 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); } From 83cccb99b374eed1dbe2cfc85be199ac3c78a514 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 6 Aug 2020 22:15:12 +0000 Subject: [PATCH 336/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.23.1 - amplify-category-api@2.23.0 - amplify-category-predictions@2.4.8 - @aws-amplify/cli@4.27.0 - amplify-codegen-appsync-model-plugin@1.20.3 - amplify-codegen@2.15.16 - amplify-console-integration-tests@1.2.18 - amplify-e2e-core@1.4.1 - amplify-e2e-tests@2.21.1 - amplify-graphql-docs-generator@2.1.16 - amplify-migration-tests@2.17.15 - amplify-provider-awscloudformation@4.24.1 - amplify-util-mock@3.24.1 - amplify-velocity-template@1.3.1 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 06b463b8e1..5c384b7f9a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 93cdcd7bfa..a690e5ca91 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.22.0", + "version": "2.23.0", "description": "amplify-cli api plugin", "repository": { "type": "git", From 63a693f05620828a8c674b58d6877763794efda9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 11 Aug 2020 04:04:39 +0000 Subject: [PATCH 337/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.8 - amplify-category-api@2.23.1 - amplify-category-auth@2.18.1 - amplify-category-function@2.23.1 - amplify-category-interactions@2.4.8 - amplify-category-notifications@2.15.17 - amplify-category-predictions@2.4.9 - amplify-category-storage@2.7.1 - amplify-category-xr@2.4.8 - @aws-amplify/cli@4.27.1 - amplify-console-integration-tests@1.2.19 - amplify-e2e-core@1.4.2 - amplify-e2e-tests@2.21.2 - amplify-migration-tests@2.17.16 - amplify-provider-awscloudformation@4.24.2 - amplify-util-mock@3.24.2 - graphql-auth-transformer@6.20.1 - graphql-connection-transformer@4.18.8 - graphql-dynamodb-transformer@6.19.9 - graphql-elasticsearch-transformer@4.7.11 - graphql-function-transformer@2.3.16 - graphql-http-transformer@4.15.16 - graphql-key-transformer@2.19.8 - graphql-predictions-transformer@2.3.16 - graphql-transformer-core@6.21.1 - graphql-transformers-e2e-tests@6.18.9 - graphql-versioned-transformer@4.15.16 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5c384b7f9a..2041167874 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a690e5ca91..e60b3edfb7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.0", + "version": "2.23.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,14 +16,14 @@ "test": "jest" }, "dependencies": { - "amplify-category-auth": "2.18.0", - "amplify-category-function": "2.23.0", + "amplify-category-auth": "2.18.1", + "amplify-category-function": "2.23.1", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.12", - "graphql-transformer-core": "6.21.0", + "graphql-transformer-core": "6.21.1", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From 703da7e4f4137b503018549887d628ac209636b7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 14 Aug 2020 17:09:38 +0000 Subject: [PATCH 338/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.9 - amplify-category-api@2.23.2 - amplify-category-auth@2.18.2 - amplify-category-function@2.23.2 - amplify-category-interactions@2.4.9 - amplify-category-notifications@2.15.18 - amplify-category-predictions@2.4.10 - amplify-category-storage@2.7.2 - amplify-category-xr@2.4.9 - @aws-amplify/cli@4.27.2 - amplify-console-integration-tests@1.2.20 - amplify-e2e-core@1.4.3 - amplify-e2e-tests@2.21.3 - amplify-migration-tests@2.17.17 - amplify-provider-awscloudformation@4.24.3 - amplify-util-mock@3.24.3 - graphql-auth-transformer@6.20.2 - graphql-connection-transformer@4.18.9 - graphql-dynamodb-transformer@6.19.10 - graphql-elasticsearch-transformer@4.7.12 - graphql-function-transformer@2.3.17 - graphql-http-transformer@4.15.17 - graphql-key-transformer@2.19.9 - graphql-mapping-template@4.15.1 - graphql-predictions-transformer@2.3.17 - graphql-relational-schema-transformer@2.15.13 - graphql-transformer-common@4.17.8 - graphql-transformer-core@6.21.2 - graphql-transformers-e2e-tests@6.18.10 - graphql-versioned-transformer@4.15.17 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2041167874..8b37656413 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e60b3edfb7..640acea21d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.1", + "version": "2.23.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,14 +16,14 @@ "test": "jest" }, "dependencies": { - "amplify-category-auth": "2.18.1", - "amplify-category-function": "2.23.1", + "amplify-category-auth": "2.18.2", + "amplify-category-function": "2.23.2", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.12", - "graphql-transformer-core": "6.21.1", + "graphql-relational-schema-transformer": "2.15.13", + "graphql-transformer-core": "6.21.2", "inquirer": "^7.0.3", "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", From be65f4096aebb6b26d97070fc09fd39ced24309e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 20 Aug 2020 17:04:15 +0000 Subject: [PATCH 339/587] chore(release): Publish [ci skip] - amplify-app@2.17.7 - amplify-appsync-simulator@1.23.2 - amplify-category-analytics@2.17.10 - amplify-category-api@2.23.3 - amplify-category-auth@2.18.3 - amplify-category-function@2.23.3 - amplify-category-interactions@2.4.10 - amplify-category-notifications@2.15.19 - amplify-category-predictions@2.4.11 - amplify-category-storage@2.7.3 - amplify-category-xr@2.4.10 - @aws-amplify/cli@4.27.3 - amplify-codegen-appsync-model-plugin@1.20.4 - amplify-codegen@2.15.17 - amplify-console-hosting@1.4.2 - amplify-nodejs-function-runtime-provider@1.1.3 - amplify-provider-awscloudformation@4.24.4 - amplify-python-function-runtime-provider@1.2.2 - amplify-util-mock@3.24.4 - graphql-auth-transformer@6.20.3 - graphql-transformers-e2e-tests@6.18.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8b37656413..639e5e0adb 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 640acea21d..5ed2698c99 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.2", + "version": "2.23.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -16,8 +16,8 @@ "test": "jest" }, "dependencies": { - "amplify-category-auth": "2.18.2", - "amplify-category-function": "2.23.2", + "amplify-category-auth": "2.18.3", + "amplify-category-function": "2.23.3", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", From cf42d05aaf8eed5715391b1b4137d4b73fcf2a95 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Thu, 20 Aug 2020 12:19:40 -0700 Subject: [PATCH 340/587] fix: sub * for path parms in CFN policy (#5092) --- ...w-cloudformation-template-default.json.ejs | 12 +++---- .../legacy-add-resource.test.ts.snap | 17 ++++++++++ .../legacy-add-resource.test.ts | 34 +++++++++++++++++++ .../awscloudformation/legacy-add-resource.ts | 12 +++++++ 4 files changed, 69 insertions(+), 6 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index d25cb258e2..7e61a219e5 100644 --- a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -84,7 +84,7 @@ ] }, "<%= props.paths[i].privacy.auth[x] %>", - "<%= props.paths[i].name %>/*" + "<%= props.paths[i].policyResourceName %>/*" ] ] }, @@ -115,7 +115,7 @@ ] }, "<%= props.paths[i].privacy.auth[x] %>", - "<%= props.paths[i].name %>" + "<%= props.paths[i].policyResourceName %>" ] ] } @@ -197,7 +197,7 @@ ] }, "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].name %>/*" + "<%= props.paths[i].policyResourceName %>/*" ] ] }, @@ -228,7 +228,7 @@ ] }, "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].name %>" + "<%= props.paths[i].policyResourceName %>" ] ] } @@ -295,7 +295,7 @@ ] }, "<%= props.paths[i].privacy.unauth[x] %>", - "<%= props.paths[i].name %>/*" + "<%= props.paths[i].policyResourceName %>/*" ] ] }, @@ -326,7 +326,7 @@ ] }, "<%= props.paths[i].privacy.unauth[x] %>", - "<%= props.paths[i].name %>" + "<%= props.paths[i].policyResourceName %>" ] ] } 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 new file mode 100644 index 0000000000..d07d099e0c --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-add-resource.test.ts.snap @@ -0,0 +1,17 @@ +// 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/legacy-add-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts new file mode 100644 index 0000000000..209e3e13aa --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-add-resource.test.ts @@ -0,0 +1,34 @@ +import { legacyAddResource } from '../../../provider-utils/awscloudformation/legacy-add-resource'; +import { category } from '../../../category-constants'; + +jest.mock('fs-extra'); + +describe('legacy add resource', () => { + const contextStub = { + amplify: { + pathManager: { + getBackendDirPath: jest.fn(_ => 'mock/backend/path'), + }, + 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, category, 'API Gateway', {}); + expect(contextStub.amplify.copyBatch.mock.calls[0][2]).toMatchSnapshot(); + }); +}); 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 index 3e83c79497..3e9769b193 100644 --- 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 @@ -25,6 +25,7 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, if (answers.customCfnFile) { cfnFilename = answers.customCfnFile; } + addPolicyResourceNameToPaths(answers.paths); copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; @@ -67,3 +68,14 @@ export const copyCfnTemplate = (context, category, options, cfnFilename) => { // copy over the files return context.amplify.copyBatch(context, copyJobs, options, true, false); }; + +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, '*'); + } + }); + } +}; From cc4c90536a6b3b3008cb3045949476f31e67d952 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Wed, 26 Aug 2020 12:35:36 -0700 Subject: [PATCH 341/587] chore: convert auth category to ts (#5165) --- .../service-walkthroughs/apigw-walkthrough.ts | 6 +++--- packages/amplify-category-api/tsconfig.json | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) 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 index 1e05045d19..0d2e353e2d 100644 --- 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 @@ -275,7 +275,7 @@ async function askPrivacy(context, answers, currentPath) { const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + const satisfiedRequirements = await checkRequirements(apiRequirements, context); // checking to see if any requirements are unsatisfied const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); @@ -297,7 +297,7 @@ async function askPrivacy(context, answers, currentPath) { allowUnauthenticatedIdentities = true; const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities }; // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + const satisfiedRequirements = await checkRequirements(apiRequirements, context); // checking to see if any requirements are unsatisfied const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); @@ -319,7 +319,7 @@ async function askPrivacy(context, answers, currentPath) { const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context, 'api', answers.resourceName); + const satisfiedRequirements = await checkRequirements(apiRequirements, context); // checking to see if any requirements are unsatisfied const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index bbff900511..6c9cdb52cd 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -12,6 +12,7 @@ "src/__tests__" ], "references": [ + {"path": "../amplify-category-auth"}, {"path": "../amplify-headless-interface"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, From 6fc055c3c60b06f9fa91631544e762e30ac05c93 Mon Sep 17 00:00:00 2001 From: opeer Date: Thu, 27 Aug 2020 02:10:24 +0300 Subject: [PATCH 342/587] refactor: replace deprecated dependencies (#5176) * refactor: replace deprecated Merge GraphQL Schemas with GraphQL Tools * refactor: replace deprecated GraphQL Toolkit with GraphQL Tools Co-authored-by: Yathi <511386+yuth@users.noreply.github.com> --- packages/amplify-category-api/package.json | 2 +- .../src/commands/api/add-graphql-datasource.js | 11 +++++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5ed2698c99..99f3cc1356 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -16,6 +16,7 @@ "test": "jest" }, "dependencies": { + "@graphql-tools/merge": "^6.0.18", "amplify-category-auth": "2.18.3", "amplify-category-function": "2.23.3", "amplify-util-headless-input": "1.2.0", @@ -25,7 +26,6 @@ "graphql-relational-schema-transformer": "2.15.13", "graphql-transformer-core": "6.21.2", "inquirer": "^7.0.3", - "merge-graphql-schemas": "^1.7.6", "open": "^7.0.0", "ora": "^4.0.3", "uuid": "^3.4.0" diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index f975bd688e..31cee41cc5 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -4,7 +4,7 @@ const graphql = require('graphql'); const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); -const { mergeTypes } = require('merge-graphql-schemas'); +const { mergeTypeDefs } = require('@graphql-tools/merge'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; @@ -114,12 +114,11 @@ module.exports = { if (schemaFileExists) { const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - const concatGraphQLSchemaDoc = mergeTypes([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); - fs.writeFileSync(graphqlSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); + const concatGraphQLSchemaDoc = mergeTypeDefs([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); + fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); } else if (schemaDirectoryExists) { - const rdsSchemaFilePath = path.join(apiDirPath, 'rds.graphql'); - const concatGraphQLSchemaDoc = mergeTypes([{}, rdsGraphQLSchemaDoc], { all: true }); - fs.writeFileSync(rdsSchemaFilePath, concatGraphQLSchemaDoc, 'utf8'); + const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); + fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); } else { throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); } From 51376d4f4f68f6f4e7b1939e7f78c712b8dc03a4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 31 Aug 2020 19:42:40 +0000 Subject: [PATCH 343/587] chore(release): Publish [ci skip] - amplify-app@2.17.8 - amplify-category-analytics@2.17.11 - amplify-category-api@2.23.4 - amplify-category-auth@2.18.4 - amplify-category-function@2.23.4 - amplify-category-interactions@2.4.11 - amplify-category-notifications@2.15.20 - amplify-category-predictions@2.4.12 - amplify-category-storage@2.7.4 - amplify-category-xr@2.4.11 - amplify-cli-core@1.3.0 - @aws-amplify/cli@4.28.0 - amplify-codegen-appsync-model-plugin@1.20.5 - amplify-codegen@2.15.18 - amplify-console-hosting@1.4.3 - amplify-console-integration-tests@1.2.21 - amplify-dotnet-function-runtime-provider@1.2.1 - amplify-dotnet-function-template-provider@1.3.1 - amplify-e2e-core@1.5.0 - amplify-e2e-tests@2.22.0 - amplify-frontend-javascript@2.15.5 - amplify-function-plugin-interface@1.4.1 - amplify-go-function-runtime-provider@1.2.3 - amplify-go-function-template-provider@1.2.1 - amplify-java-function-runtime-provider@1.2.1 - amplify-java-function-template-provider@1.4.1 - amplify-migration-tests@2.17.18 - amplify-nodejs-function-runtime-provider@1.1.4 - amplify-nodejs-function-template-provider@1.3.1 - amplify-provider-awscloudformation@4.25.0 - amplify-python-function-runtime-provider@1.2.3 - amplify-python-function-template-provider@1.2.1 - amplify-util-mock@3.24.5 - graphql-auth-transformer@6.20.4 - graphql-connection-transformer@4.18.10 - graphql-dynamodb-transformer@6.19.11 - graphql-elasticsearch-transformer@4.7.13 - graphql-function-transformer@2.3.18 - graphql-http-transformer@4.15.18 - graphql-key-transformer@2.19.10 - graphql-mapping-template@4.15.2 - graphql-predictions-transformer@2.3.18 - graphql-relational-schema-transformer@2.15.14 - graphql-transformer-common@4.17.9 - graphql-transformer-core@6.21.3 - graphql-transformers-e2e-tests@6.18.12 - graphql-versioned-transformer@4.15.18 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 639e5e0adb..f6eb40066f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 99f3cc1356..87e00c0ce6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.3", + "version": "2.23.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.18.3", - "amplify-category-function": "2.23.3", + "amplify-category-auth": "2.18.4", + "amplify-category-function": "2.23.4", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.13", - "graphql-transformer-core": "6.21.2", + "graphql-relational-schema-transformer": "2.15.14", + "graphql-transformer-core": "6.21.3", "inquirer": "^7.0.3", "open": "^7.0.0", "ora": "^4.0.3", From 9c5cd3e0ac9e416ba528f32c0f0b260aab1f6563 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 3 Sep 2020 03:56:06 +0000 Subject: [PATCH 344/587] chore(release): Publish [ci skip] - amplify-app@2.17.10 - amplify-category-analytics@2.17.12 - amplify-category-api@2.23.5 - amplify-category-auth@2.18.5 - amplify-category-function@2.23.5 - amplify-category-interactions@2.4.12 - amplify-category-notifications@2.15.21 - amplify-category-predictions@2.4.14 - amplify-category-storage@2.7.5 - amplify-category-xr@2.4.12 - @aws-amplify/cli@4.28.2 - amplify-frontend-javascript@2.16.1 - amplify-provider-awscloudformation@4.25.2 - amplify-util-mock@3.24.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f6eb40066f..fe752fb53c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 87e00c0ce6..428e68619e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.4", + "version": "2.23.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,8 +17,8 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.18.4", - "amplify-category-function": "2.23.4", + "amplify-category-auth": "2.18.5", + "amplify-category-function": "2.23.5", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", From 800fad1ed5562aabba73d191b8965c0afe684ff3 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 3 Sep 2020 21:21:32 +0000 Subject: [PATCH 345/587] chore(release): Publish [ci skip] - amplify-category-analytics@2.17.13 - amplify-category-api@2.23.6 - amplify-category-auth@2.18.6 - amplify-category-function@2.24.0 - amplify-category-interactions@2.4.13 - amplify-category-notifications@2.15.22 - amplify-category-predictions@2.4.15 - amplify-category-storage@2.7.6 - amplify-category-xr@2.4.13 - @aws-amplify/cli@4.29.0 - amplify-console-integration-tests@1.2.22 - amplify-e2e-core@1.6.0 - amplify-e2e-tests@2.23.0 - amplify-migration-tests@2.18.0 - amplify-provider-awscloudformation@4.26.0 - amplify-util-mock@3.24.8 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fe752fb53c..41cf4acab9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 428e68619e..ce085426de 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.5", + "version": "2.23.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,8 +17,8 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.18.5", - "amplify-category-function": "2.23.5", + "amplify-category-auth": "2.18.6", + "amplify-category-function": "2.24.0", "amplify-util-headless-input": "1.2.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", From ee750aa6b5941eae8c715aed49c21c581da74d70 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 9 Sep 2020 22:44:27 +0000 Subject: [PATCH 346/587] chore(release): Publish [ci skip] - amplify-app@2.17.11 - amplify-category-analytics@2.17.14 - amplify-category-api@2.23.7 - amplify-category-auth@2.19.0 - amplify-category-function@2.24.1 - amplify-category-interactions@2.4.14 - amplify-category-notifications@2.15.23 - amplify-category-predictions@2.4.16 - amplify-category-storage@2.7.7 - amplify-category-xr@2.4.14 - amplify-cli-core@1.3.1 - @aws-amplify/cli@4.29.1 - amplify-console-integration-tests@1.2.23 - amplify-e2e-core@1.6.1 - amplify-e2e-tests@2.23.1 - amplify-frontend-javascript@2.16.2 - amplify-headless-interface@1.3.0 - amplify-migration-tests@2.18.1 - amplify-provider-awscloudformation@4.26.1 - amplify-storage-simulator@1.4.1 - amplify-util-headless-input@1.2.1 - amplify-util-mock@3.24.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 41cf4acab9..cf5d32b4ae 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ce085426de..a43288d659 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.6", + "version": "2.23.7", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,9 +17,9 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.18.6", - "amplify-category-function": "2.24.0", - "amplify-util-headless-input": "1.2.0", + "amplify-category-auth": "2.19.0", + "amplify-category-function": "2.24.1", + "amplify-util-headless-input": "1.2.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From d470a72d575cba8c43d5e8d91ddecc8d00f262a3 Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Fri, 11 Sep 2020 11:43:55 -0700 Subject: [PATCH 347/587] fix: removes duplicate auth types (#5272) * fix: removes duplicate auth types * fix: addressing comments --- .../appSync-walkthrough.test.ts.snap | 14 ++++++ .../appSync-walkthrough.test.ts | 50 ++++++++++++++++--- .../appSync-walkthrough.ts | 10 ++-- 3 files changed, 64 insertions(+), 10 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap 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 new file mode 100644 index 0000000000..19c9e1c5f2 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/__snapshots__/appSync-walkthrough.test.ts.snap @@ -0,0 +1,14 @@ +// 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/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts index 4d64805a2d..b497d07111 100644 --- 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 @@ -1,21 +1,30 @@ -import { getIAMPolicies } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; -import { authConfigHasApiKey } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +import { + getIAMPolicies, + askAdditionalAuthQuestions, +} 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(), })); const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; -const context_stub = { +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(), }, -}; +}); describe('get IAM policies', () => { it('does not include API key if none exists', () => { authConfigHasApiKey_mock.mockImplementationOnce(() => false); - const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub); + const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub(confirmPromptFalse_mock)); expect(attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -26,7 +35,7 @@ describe('get IAM policies', () => { it('includes API key if it exists', () => { authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub); + const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub(confirmPromptFalse_mock)); expect(attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -36,3 +45,32 @@ describe('get IAM policies', () => { `); }); }); + +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/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index acfbca72c2..d1092ae90b 100644 --- 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 @@ -420,13 +420,12 @@ async function askDefaultAuthQuestion(context) { }; } -async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { +export async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { + const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); if (await context.prompt.confirm('Configure additional auth types?')) { authConfig.additionalAuthenticationProviders = []; // Get additional auth configured const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType); - - const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); const currentAdditionalAuth = ((currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders ? currentAuthConfig.additionalAuthenticationProviders : []) as any[]).map(authProvider => authProvider.authenticationType); @@ -448,8 +447,11 @@ async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) authConfig.additionalAuthenticationProviders.push(config); } + } else { + authConfig.additionalAuthenticationProviders = (currentAuthConfig.additionalAuthenticationProviders || []).filter( + p => p.authenticationType !== defaultAuthType, + ); } - return authConfig; } From ab3fc147d272b1fe9e91337ab258ed77392c78dc Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Fri, 11 Sep 2020 15:13:46 -0700 Subject: [PATCH 348/587] fix: checking undefined auth config (#5313) * fix: checking undefined auth config * fix: changes as per comments --- .../service-walkthroughs/appSync-walkthrough.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index d1092ae90b..74f0174d1d 100644 --- 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 @@ -422,8 +422,8 @@ async function askDefaultAuthQuestion(context) { export async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + authConfig.additionalAuthenticationProviders = []; if (await context.prompt.confirm('Configure additional auth types?')) { - authConfig.additionalAuthenticationProviders = []; // Get additional auth configured const remainingAuthProviderChoices = authProviderChoices.filter(p => p.value !== defaultAuthType); const currentAdditionalAuth = ((currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders @@ -448,7 +448,7 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut authConfig.additionalAuthenticationProviders.push(config); } } else { - authConfig.additionalAuthenticationProviders = (currentAuthConfig.additionalAuthenticationProviders || []).filter( + authConfig.additionalAuthenticationProviders = (currentAuthConfig?.additionalAuthenticationProviders || []).filter( p => p.authenticationType !== defaultAuthType, ); } From 9dbec0820b3f3067e86bcb1b161fe3652907868d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 16 Sep 2020 19:31:08 +0000 Subject: [PATCH 349/587] chore(release): Publish [ci skip] - amplify-app@2.17.12 - amplify-category-analytics@2.17.15 - amplify-category-api@2.23.8 - amplify-category-auth@2.19.1 - amplify-category-function@2.25.0 - amplify-category-interactions@2.4.15 - amplify-category-notifications@2.15.24 - amplify-category-predictions@2.4.17 - amplify-category-storage@2.7.8 - amplify-category-xr@2.4.15 - amplify-cli-core@1.3.2 - @aws-amplify/cli@4.29.2 - amplify-console-hosting@1.4.4 - amplify-console-integration-tests@1.2.24 - amplify-e2e-core@1.6.2 - amplify-e2e-tests@2.24.0 - amplify-frontend-javascript@2.16.3 - amplify-migration-tests@2.18.2 - amplify-nodejs-function-runtime-provider@1.1.5 - amplify-nodejs-function-template-provider@1.4.0 - amplify-provider-awscloudformation@4.26.2 - amplify-util-mock@3.24.10 - graphql-auth-transformer@6.20.6 - graphql-connection-transformer@4.18.12 - graphql-dynamodb-transformer@6.19.13 - graphql-elasticsearch-transformer@4.7.15 - graphql-function-transformer@2.3.19 - graphql-http-transformer@4.15.19 - graphql-key-transformer@2.19.12 - graphql-predictions-transformer@2.3.19 - graphql-relational-schema-transformer@2.15.15 - graphql-transformer-common@4.17.10 - graphql-transformer-core@6.21.4 - graphql-transformers-e2e-tests@6.18.14 - graphql-versioned-transformer@4.15.20 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index cf5d32b4ae..e91288c648 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a43288d659..94c71d4f73 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.7", + "version": "2.23.8", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.19.0", - "amplify-category-function": "2.24.1", + "amplify-category-auth": "2.19.1", + "amplify-category-function": "2.25.0", "amplify-util-headless-input": "1.2.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.14", - "graphql-transformer-core": "6.21.3", + "graphql-relational-schema-transformer": "2.15.15", + "graphql-transformer-core": "6.21.4", "inquirer": "^7.0.3", "open": "^7.0.0", "ora": "^4.0.3", From 867a9596f6d98fb52db5b1db46c9298b6a273dde Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Wed, 23 Sep 2020 10:46:32 -0700 Subject: [PATCH 350/587] fix: data inconsitency (#5344) * fix: data inconsistency --- .../commands/api/add-graphql-datasource.js | 6 ++++- .../src/commands/api/add.js | 1 + .../src/commands/api/console.js | 1 + .../src/commands/api/gql-compile.js | 1 + .../src/commands/api/push.js | 1 + .../src/commands/api/remove.js | 1 + .../src/commands/api/update.js | 1 + .../provider-utils/awscloudformation/index.ts | 9 +++++-- .../service-walkthroughs/apigw-walkthrough.ts | 11 +++++--- .../appSync-rds-walkthrough.js | 27 ++++++++++++------- .../appSync-walkthrough.ts | 16 +++++++---- 11 files changed, 54 insertions(+), 21 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 31cee41cc5..fc9b8c580e 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -5,6 +5,7 @@ const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypeDefs } = require('@graphql-tools/merge'); +const { ResourceDoesNotExistError } = require('amplify-cli-core'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; @@ -164,6 +165,7 @@ module.exports = { context.print.info(err.stack); context.print.error('There was an error adding the datasource'); context.usageData.emitError(err); + process.exitCode = 1; }); }, readSchema, @@ -186,7 +188,9 @@ function datasourceSelectionPrompt(context, supportedDatasources) { }); if (options.length === 0) { - context.print.error(`No datasources defined by configured providers for category: ${category}`); + const errMessage = `No datasources defined by configured providers for category: ${category}`; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(1); } diff --git a/packages/amplify-category-api/src/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js index aee1ba5953..21ccf2a4f6 100644 --- a/packages/amplify-category-api/src/commands/api/add.js +++ b/packages/amplify-category-api/src/commands/api/add.js @@ -38,6 +38,7 @@ module.exports = { context.print.info(err.stack); context.print.error('There was an error adding the API resource'); context.usageData.emitError(err); + process.exitCode = 1; }); }, }; diff --git a/packages/amplify-category-api/src/commands/api/console.js b/packages/amplify-category-api/src/commands/api/console.js index 521c18ee97..f208c9faee 100644 --- a/packages/amplify-category-api/src/commands/api/console.js +++ b/packages/amplify-category-api/src/commands/api/console.js @@ -21,6 +21,7 @@ module.exports = { context.print.error('Error opening console.'); context.print.info(err.message); context.usageData.emitError(err); + process.exitCode = 1; }); }, }; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.js b/packages/amplify-category-api/src/commands/api/gql-compile.js index a7d6f1a641..a53e64d0fe 100644 --- a/packages/amplify-category-api/src/commands/api/gql-compile.js +++ b/packages/amplify-category-api/src/commands/api/gql-compile.js @@ -14,6 +14,7 @@ module.exports = { } catch (err) { context.print.error(err.toString()); context.usageData.emitError(err); + process.exitCode = 1; } }, }; diff --git a/packages/amplify-category-api/src/commands/api/push.js b/packages/amplify-category-api/src/commands/api/push.js index 06dcc8de26..8a0da0bb5a 100644 --- a/packages/amplify-category-api/src/commands/api/push.js +++ b/packages/amplify-category-api/src/commands/api/push.js @@ -11,6 +11,7 @@ module.exports = { context.print.error('There was an error pushing the API resource'); context.print.error(err.toString()); context.usageData.emitError(err); + process.exitCode = 1; }); }, }; diff --git a/packages/amplify-category-api/src/commands/api/remove.js b/packages/amplify-category-api/src/commands/api/remove.js index 9e3d0d5837..8c334611a5 100644 --- a/packages/amplify-category-api/src/commands/api/remove.js +++ b/packages/amplify-category-api/src/commands/api/remove.js @@ -25,6 +25,7 @@ module.exports = { context.print.info(err.stack); context.print.error('There was an error removing the api resource'); context.usageData.emitError(err); + process.exitCode = 1; }); }, }; diff --git a/packages/amplify-category-api/src/commands/api/update.js b/packages/amplify-category-api/src/commands/api/update.js index 74af43feaf..03dbb328f1 100644 --- a/packages/amplify-category-api/src/commands/api/update.js +++ b/packages/amplify-category-api/src/commands/api/update.js @@ -23,6 +23,7 @@ module.exports = { context.print.error(err.message); console.log(err.stack); context.usageData.emitError(err); + process.exitCode = 1; }); }, }; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index 7c4acb451f..d86b4ee6ff 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -5,6 +5,7 @@ import { legacyAddResource } from './legacy-add-resource'; import { legacyUpdateResource } from './legacy-update-resource'; import { UpdateApiRequest } from 'amplify-headless-interface'; import { editSchemaFlow } from './utils/edit-schema-flow'; +import { NotImplementedError } from 'amplify-cli-core'; export async function console(context, service) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); @@ -12,7 +13,9 @@ export async function console(context, service) { const { openConsole } = require(serviceWalkthroughSrc); if (!openConsole) { - context.print.error('Opening console functionality not available for this option'); + const errMessage = 'Opening console functionality not available for this option'; + context.print.error(errMessage); + context.usageData.emitError(new NotImplementedError(errMessage)); process.exit(0); } @@ -46,7 +49,9 @@ export async function updateResource(context, category, service) { const { updateWalkthrough } = require(serviceWalkthroughSrc); if (!updateWalkthrough) { - context.print.error('Update functionality not available for this option'); + const errMessage = 'Update functionality not available for this option'; + context.print.error(errMessage); + context.usageData.emitError(new NotImplementedError(errMessage)); process.exit(0); } 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 index 0d2e353e2d..d0373f2f1b 100644 --- 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 @@ -5,6 +5,7 @@ import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; import { ServiceName as FunctionServiceName } from 'amplify-category-function'; +import { ResourceDoesNotExistError } from 'amplify-cli-core'; const category = 'api'; const serviceName = 'API Gateway'; @@ -37,7 +38,9 @@ export async function updateWalkthrough(context, defaultValuesFilename) { // There can only be one appsync resource if (resources.length === 0) { - context.print.error('No REST API resource to update. Please use "amplify add api" command to create a new REST API'); + const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); return; } @@ -68,9 +71,9 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const updateApi = await inquirer.prompt(question); if (updateApi.resourceName === 'AdminQueries') { - context.print.warning( - `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`, - ); + const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; + context.print.warning(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index ce274b914f..fcf6f1149d 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -1,6 +1,7 @@ const inquirer = require('inquirer'); const ora = require('ora'); const { DataApiParams } = require('graphql-relational-schema-transformer'); +const { ResourceDoesNotExistError, ResourceCredentialsNotFoundError } = require('amplify-cli-core'); const spinner = ora(''); const category = 'api'; @@ -11,9 +12,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // Verify that an API exists in the project before proceeding. if (amplifyMeta == null || amplifyMeta[category] == null || Object.keys(amplifyMeta[category]).length === 0) { - context.print.error( - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.', - ); + 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.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } @@ -30,9 +32,10 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta // If an AppSync API does not exist, inform the user to create the AppSync API if (!appSyncApi) { - context.print.error( - 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.', - ); + 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.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } @@ -92,7 +95,9 @@ async function selectCluster(context, inputs, AWS) { clusterResourceId: selectedCluster.DbClusterResourceId, }; } - context.print.error('No properly configured Aurora Serverless clusters found.'); + const errMessage = 'No properly configured Aurora Serverless clusters found.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } @@ -142,7 +147,9 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); selectedSecretArn = secrets.get(selectedSecretName); } else { - context.print.error('No RDS access credentials found in the AWS Secrect Manager.'); + const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); process.exit(0); } } @@ -185,7 +192,9 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { return await promptWalkthroughQuestion(inputs, 3, databaseList); } - context.print.error('No properly configured databases found.'); + const errMessage = 'No properly configured databases found.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } 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 index 74f0174d1d..08b6bdbb33 100644 --- 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 @@ -12,6 +12,7 @@ import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-au import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; +import { ResourceAlreadyExistsError, ResourceDoesNotExistError, UnknownResourceTypeError } from 'amplify-cli-core'; const serviceName = 'AppSync'; const providerName = 'awscloudformation'; @@ -64,9 +65,10 @@ export const serviceWalkthrough = async (context, defaultValuesFilename, service let resolverConfig; if (resourceName) { - context.print.warning( - 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.', - ); + const errMessage = + 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'; + context.print.warning(errMessage); + context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); process.exit(0); } @@ -175,7 +177,9 @@ export const updateWalkthrough = async (context): Promise => { const backEndDir = context.amplify.pathManager.getBackendDirPath(); resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); } else { - context.print.error('No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'); + const errMessage = 'No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'; + context.print.error(errMessage); + context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); process.exit(0); } @@ -492,7 +496,9 @@ async function askAuthQuestions(authType, context, printLeadText = false) { return openIDConnectConfig; } - context.print.error(`Unknown authType: ${authType}`); + const errMessage = `Unknown authType: ${authType}`; + context.print.error(errMessage); + context.usageData.emitError(new UnknownResourceTypeError(errMessage)); process.exit(1); } From a7a15dcfc231965f2dfce1f4e446478ea278bfb9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 25 Sep 2020 00:35:43 +0000 Subject: [PATCH 351/587] chore(release): Publish [ci skip] - amplify-app@2.17.13 - amplify-category-analytics@2.17.16 - amplify-category-api@2.23.9 - amplify-category-auth@2.20.0 - amplify-category-function@2.25.1 - amplify-category-hosting@2.4.3 - amplify-category-interactions@2.4.16 - amplify-category-notifications@2.15.25 - amplify-category-predictions@2.4.18 - amplify-category-storage@2.7.9 - amplify-category-xr@2.4.16 - amplify-cli-core@1.3.3 - @aws-amplify/cli@4.29.3 - amplify-codegen-appsync-model-plugin@1.20.6 - amplify-codegen@2.15.19 - amplify-console-hosting@1.4.5 - amplify-console-integration-tests@1.2.25 - amplify-dotnet-function-template-provider@1.3.2 - amplify-e2e-core@1.7.0 - amplify-e2e-tests@2.25.0 - amplify-frontend-javascript@2.16.4 - amplify-go-function-runtime-provider@1.2.4 - amplify-graphql-types-generator@2.5.1 - amplify-headless-interface@1.4.0 - amplify-migration-tests@2.18.3 - amplify-nodejs-function-template-provider@1.4.1 - amplify-provider-awscloudformation@4.26.3 - amplify-util-headless-input@1.3.0 - amplify-util-mock@3.24.11 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e91288c648..2a8a43c9bf 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 94c71d4f73..b1c9c5c862 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.8", + "version": "2.23.9", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,9 +17,9 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.19.1", - "amplify-category-function": "2.25.0", - "amplify-util-headless-input": "1.2.1", + "amplify-category-auth": "2.20.0", + "amplify-category-function": "2.25.1", + "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From e82db853a68a48fa888deb5fe88708efa668e974 Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Mon, 28 Sep 2020 14:09:39 -0700 Subject: [PATCH 352/587] feat(amplify-category-api): add rds support for new regions (#5360) Update the amplify api add-graphql-datasource` to support new regions that support Aroura Serverless re #4739 --- .../src/provider-utils/supported-datasources.ts | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index f458e8e429..f9eb118a09 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -31,6 +31,19 @@ export const supportedDatasources = { serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', - availableRegions: ['us-east-1', 'us-east-2', 'us-west-2', 'ap-northeast-1', 'eu-west-1'], + availableRegions: [ + 'us-east-1', + 'us-east-2', + 'us-west-1', + 'us-west-2', + 'ap-south-1', + 'ap-southeast-1', + 'ap-southeast-2', + 'ap-northeast-1', + 'eu-central-1', + 'eu-west-1', + 'eu-west-2', + 'eu-west-3', + ], }, }; From 78dc91ee1918cce30de73f1e3626266cbe54dd9b Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Tue, 29 Sep 2020 10:56:17 -0700 Subject: [PATCH 353/587] fix: added exit code on remove (#5427) * fix: added exit code on remove * fix: added exit code * fix: exit on next tick * test: fixed abort test * test: fixed delete.test.ts --- .../src/commands/api/add-graphql-datasource.js | 4 ++-- .../src/provider-utils/awscloudformation/index.ts | 6 +++--- .../service-walkthroughs/apigw-walkthrough.ts | 6 +++--- .../service-walkthroughs/appSync-rds-walkthrough.js | 12 ++++++------ .../service-walkthroughs/appSync-walkthrough.ts | 8 ++++---- 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index fc9b8c580e..56dcd87315 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -5,7 +5,7 @@ const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { ResourceDoesNotExistError } = require('amplify-cli-core'); +const { ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; @@ -191,7 +191,7 @@ function datasourceSelectionPrompt(context, supportedDatasources) { const errMessage = `No datasources defined by configured providers for category: ${category}`; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(1); + exitOnNextTick(1); } if (options.length === 1) { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index d86b4ee6ff..dc7812ff6d 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -5,7 +5,7 @@ import { legacyAddResource } from './legacy-add-resource'; import { legacyUpdateResource } from './legacy-update-resource'; import { UpdateApiRequest } from 'amplify-headless-interface'; import { editSchemaFlow } from './utils/edit-schema-flow'; -import { NotImplementedError } from 'amplify-cli-core'; +import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; export async function console(context, service) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); @@ -16,7 +16,7 @@ export async function console(context, service) { const errMessage = 'Opening console functionality not available for this option'; context.print.error(errMessage); context.usageData.emitError(new NotImplementedError(errMessage)); - process.exit(0); + exitOnNextTick(0); } return openConsole(context); @@ -52,7 +52,7 @@ export async function updateResource(context, category, service) { const errMessage = 'Update functionality not available for this option'; context.print.error(errMessage); context.usageData.emitError(new NotImplementedError(errMessage)); - process.exit(0); + exitOnNextTick(0); } const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); 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 index d0373f2f1b..ec3579c78f 100644 --- 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 @@ -5,7 +5,7 @@ import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; import { ServiceName as FunctionServiceName } from 'amplify-category-function'; -import { ResourceDoesNotExistError } from 'amplify-cli-core'; +import { ResourceDoesNotExistError, exitOnNextTick } from 'amplify-cli-core'; const category = 'api'; const serviceName = 'API Gateway'; @@ -41,7 +41,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); return; } @@ -74,7 +74,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; context.print.warning(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index fcf6f1149d..4068c270b3 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -1,7 +1,7 @@ const inquirer = require('inquirer'); const ora = require('ora'); const { DataApiParams } = require('graphql-relational-schema-transformer'); -const { ResourceDoesNotExistError, ResourceCredentialsNotFoundError } = require('amplify-cli-core'); +const { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick } = require('amplify-cli-core'); const spinner = ora(''); const category = 'api'; @@ -16,7 +16,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } // Loop through to find the AppSync API Resource Name @@ -36,7 +36,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 'You must create an AppSync API in your project before adding a graphql datasource. Please use "amplify api add" to create the API.'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } const { inputs, availableRegions } = datasourceMetadata; @@ -98,7 +98,7 @@ async function selectCluster(context, inputs, AWS) { const errMessage = 'No properly configured Aurora Serverless clusters found.'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } /** @@ -150,7 +150,7 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; context.print.error(errMessage); context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); - process.exit(0); + exitOnNextTick(0); } } @@ -195,7 +195,7 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { const errMessage = 'No properly configured databases found.'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } /** 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 index 08b6bdbb33..31e99f6cc1 100644 --- 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 @@ -12,7 +12,7 @@ import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-au import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; -import { ResourceAlreadyExistsError, ResourceDoesNotExistError, UnknownResourceTypeError } from 'amplify-cli-core'; +import { ResourceAlreadyExistsError, ResourceDoesNotExistError, UnknownResourceTypeError, exitOnNextTick } from 'amplify-cli-core'; const serviceName = 'AppSync'; const providerName = 'awscloudformation'; @@ -69,7 +69,7 @@ export const serviceWalkthrough = async (context, defaultValuesFilename, service 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'; context.print.warning(errMessage); context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); - process.exit(0); + exitOnNextTick(0); } const { amplify } = context; @@ -180,7 +180,7 @@ export const updateWalkthrough = async (context): Promise => { const errMessage = 'No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'; context.print.error(errMessage); context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - process.exit(0); + exitOnNextTick(0); } // Get models @@ -499,7 +499,7 @@ async function askAuthQuestions(authType, context, printLeadText = false) { const errMessage = `Unknown authType: ${authType}`; context.print.error(errMessage); context.usageData.emitError(new UnknownResourceTypeError(errMessage)); - process.exit(1); + exitOnNextTick(1); } async function askUserPoolQuestions(context) { From e112f697954b0a96791d116ef7d719dee5731ea0 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 30 Sep 2020 14:04:40 -0700 Subject: [PATCH 354/587] fix: add support for mobile hub migrated resources (#5407) * fix: add support for mobile hub migrated resources - support push/pull operations - support CRUD permission assignment to migrated resources - block multi-env commands - block update and remove operations on migrated resources * fix: sigint test failure * chore: fix lgtm warning * fix: add 'add notification' and 'update auth' protection * chore: fix update unit test --- packages/amplify-category-api/src/index.ts | 12 ++++++++++-- .../service-walkthroughs/apigw-walkthrough.ts | 4 +++- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 78b09b5205..3c8664f687 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -58,6 +58,13 @@ export async function initEnv(context) { * configured an RDS datasource */ const backendConfigFilePath = amplify.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 = amplify.readJsonFile(backendConfigFilePath); if (!backendConfig[category]) { @@ -146,8 +153,9 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { await Promise.all( Object.keys(resourceOpsMapping).map(async resourceName => { try { - const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); - if (providerController) { + const providerName = amplifyMeta[category][resourceName].providerPlugin; + if (providerName) { + const providerController = require(`./provider-utils/${providerName}/index`); const { policy, attributes } = await providerController.getPermissionPolicies( context, amplifyMeta[category][resourceName].service, 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 index ec3579c78f..dbe7cb3fe5 100644 --- 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 @@ -34,7 +34,9 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; const { getAllDefaults } = await import(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - const resources = allResources.filter(resource => resource.service === serviceName).map(resource => resource.resourceName); + const resources = allResources + .filter(resource => resource.service === serviceName && !!resource.providerPlugin) + .map(resource => resource.resourceName); // There can only be one appsync resource if (resources.length === 0) { From 8d19697cf0f4dd89725e91171d5b5cf58c3a5f13 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 1 Oct 2020 17:37:29 +0000 Subject: [PATCH 355/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.23.3 - amplify-category-analytics@2.17.17 - amplify-category-api@2.24.0 - amplify-category-auth@2.20.1 - amplify-category-function@2.25.2 - amplify-category-hosting@2.4.4 - amplify-category-interactions@2.4.17 - amplify-category-notifications@2.15.26 - amplify-category-predictions@2.4.19 - amplify-category-storage@2.7.10 - amplify-category-xr@2.4.17 - amplify-cli-core@1.3.4 - @aws-amplify/cli@4.29.4 - amplify-codegen-appsync-model-plugin@1.20.7 - amplify-codegen@2.15.20 - amplify-console-hosting@1.4.6 - amplify-console-integration-tests@1.2.26 - amplify-dotnet-function-template-provider@1.3.3 - amplify-e2e-core@1.7.1 - amplify-e2e-tests@2.25.1 - amplify-migration-tests@2.18.4 - amplify-nodejs-function-template-provider@1.4.2 - amplify-provider-awscloudformation@4.26.4 - amplify-util-mock@3.24.12 - graphql-auth-transformer@6.20.7 - graphql-connection-transformer@4.18.13 - graphql-dynamodb-transformer@6.19.14 - graphql-elasticsearch-transformer@4.7.16 - graphql-function-transformer@2.3.20 - graphql-http-transformer@4.15.20 - graphql-key-transformer@2.19.13 - graphql-predictions-transformer@2.3.20 - graphql-transformer-core@6.21.5 - graphql-transformers-e2e-tests@6.18.15 - graphql-versioned-transformer@4.15.21 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2a8a43c9bf..2a0c7cee68 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b1c9c5c862..4ad5cb5819 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.23.9", + "version": "2.24.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.20.0", - "amplify-category-function": "2.25.1", + "amplify-category-auth": "2.20.1", + "amplify-category-function": "2.25.2", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.15", - "graphql-transformer-core": "6.21.4", + "graphql-transformer-core": "6.21.5", "inquirer": "^7.0.3", "open": "^7.0.0", "ora": "^4.0.3", From 58e12f4b861f28e7a301736de2daf3f2d287490e Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Thu, 1 Oct 2020 14:28:14 -0700 Subject: [PATCH 356/587] chore: regen yarn.lock, fix dependabot warning, package upgrades (#5464) * chore: regen yarn.lock, upgrade prompt, print deps * chore: change table header colors from red to neutral * chore: fix dependabot warning by updating react relateed pkgs --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4ad5cb5819..721e80601f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -25,7 +25,7 @@ "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.15", "graphql-transformer-core": "6.21.5", - "inquirer": "^7.0.3", + "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", "uuid": "^3.4.0" From 1ee5f4caab2068c82c5d227a1028a546f61c7f32 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 7 Oct 2020 20:46:25 +0000 Subject: [PATCH 357/587] chore(release): Publish [ci skip] - amplify-app@2.17.14 - amplify-appsync-simulator@1.23.4 - amplify-category-analytics@2.17.18 - amplify-category-api@2.24.1 - amplify-category-auth@2.20.2 - amplify-category-function@2.25.3 - amplify-category-hosting@2.4.5 - amplify-category-interactions@2.4.18 - amplify-category-notifications@2.15.27 - amplify-category-predictions@2.4.20 - amplify-category-storage@2.7.11 - amplify-category-xr@2.4.18 - @aws-amplify/cli@4.29.5 - amplify-codegen-appsync-model-plugin@1.20.8 - amplify-codegen@2.15.21 - amplify-console-hosting@1.4.7 - amplify-console-integration-tests@1.2.27 - amplify-dynamodb-simulator@1.14.3 - amplify-e2e-tests@2.25.2 - amplify-frontend-android@2.13.5 - amplify-frontend-javascript@2.16.5 - amplify-graphiql-explorer@1.3.3 - amplify-migration-tests@2.18.5 - amplify-provider-awscloudformation@4.26.5 - amplify-storage-simulator@1.4.2 - amplify-util-mock@3.24.13 - amplify-velocity-template@1.3.2 - graphql-relational-schema-transformer@2.15.16 - graphql-transformers-e2e-tests@6.18.16 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2a0c7cee68..0c00274abd 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 721e80601f..3a1e3ae06b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.24.0", + "version": "2.24.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,13 +17,13 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.20.1", - "amplify-category-function": "2.25.2", + "amplify-category-auth": "2.20.2", + "amplify-category-function": "2.25.3", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.15", + "graphql-relational-schema-transformer": "2.15.16", "graphql-transformer-core": "6.21.5", "inquirer": "^7.3.3", "open": "^7.0.0", From 5094cdeeb563e920c0182204d44b31debb50bbc0 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Fri, 16 Oct 2020 14:39:13 -0700 Subject: [PATCH 358/587] feat: support importing of auth resources (#5591) * feat: auth import functionality * chore: update split tests * chore: fix lgtm warnings * chore: address pr feedback, e2e cleanup - address PR feedback - separate auth import e2e test files * chore: add more e2e tests, refactor api logic * chore: fix lgtm warnings --- .../cfn-api-artifact-handler.test.ts | 1 + .../service-walkthroughs/apigw-walkthrough.ts | 80 ++++++++----------- .../appSync-walkthrough.ts | 5 +- .../utils/amplify-meta-utils.ts | 7 +- 4 files changed, 41 insertions(+), 52 deletions(-) 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 index 523089d70c..9fa8ebe762 100644 --- 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 @@ -25,6 +25,7 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', getAppSyncResourceName: jest.fn(() => testApiName), getAppSyncAuthConfig: jest.fn(() => ({})), authConfigHasApiKey: jest.fn(() => true), + getImportedAuthUserPoolId: jest.fn(() => undefined), })); const fs_mock = (fs as unknown) as jest.Mocked; 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 index dbe7cb3fe5..0747b549a1 100644 --- 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 @@ -1,6 +1,7 @@ import inquirer from 'inquirer'; import path from 'path'; import fs from 'fs-extra'; +import os from 'os'; import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; @@ -211,7 +212,6 @@ async function askPrivacy(context, answers, currentPath) { const userPoolGroupList = await context.amplify.getUserPoolGroupList(context); let permissionSelected = 'Auth/Guest Users'; - let allowUnauthenticatedIdentities = false; const privacy: any = {}; const { checkRequirements, externalAuthEnable } = await import('amplify-category-auth'); @@ -279,43 +279,16 @@ async function askPrivacy(context, answers, currentPath) { privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - } catch (e) { - context.print.error(e); - throw e; - } - } + + await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); } if (answer.privacy === 'protected') { privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); - allowUnauthenticatedIdentities = true; - const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - } catch (e) { - context.print.error(e); - throw e; - } - } + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + + await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); } } @@ -323,21 +296,8 @@ async function askPrivacy(context, answers, currentPath) { // Enable Auth if not enabled const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - // getting requirement satisfaction map - const satisfiedRequirements = await checkRequirements(apiRequirements, context); - // checking to see if any requirements are unsatisfied - const foundUnmetRequirements = Object.values(satisfiedRequirements).includes(false); - - // if requirements are unsatisfied, trigger auth - - if (foundUnmetRequirements) { - try { - await externalAuthEnable(context, 'api', answers.resourceName, apiRequirements); - } catch (e) { - context.print.error(e); - throw e; - } - } + + await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); // Get Auth resource name const authResourceName = await getAuthResourceName(context); @@ -387,6 +347,30 @@ async function askPrivacy(context, answers, currentPath) { } } +async function ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, resourceName) { + const checkResult = await 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) { + context.print.warning(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 externalAuthEnable(context, 'api', resourceName, apiRequirements); + } catch (error) { + context.print.error(error); + throw error; + } + } +} + async function askReadWrite(userType, context, privacy) { const permissionMap = { create: ['/POST'], 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 index 31e99f6cc1..ec8fccc91c 100644 --- 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 @@ -517,10 +517,13 @@ async function askUserPoolQuestions(context) { context.print.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: `auth${authResourceName}`, + userPoolId: authResourceName, }, }; } 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 index c2671df70f..d920a8d9c9 100644 --- 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 @@ -18,16 +18,17 @@ export const checkIfAuthExists = context => { const { amplifyMeta } = amplify.getProjectDetails(); let authResourceName; const authServiceName = 'Cognito'; - const authCategory = 'auth'; + const authCategoryName = 'auth'; - if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { - const categoryResources = amplifyMeta[authCategory]; + 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; }; From fc19dac89b9727c646104e8f94aeb7a6225e3793 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 17 Oct 2020 16:41:56 +0000 Subject: [PATCH 359/587] chore(release): Publish [ci skip] - amplify-app@2.17.15 - amplify-category-analytics@2.18.0 - amplify-category-api@2.25.0 - amplify-category-auth@2.21.0 - amplify-category-function@2.25.4 - amplify-category-interactions@2.5.0 - amplify-category-notifications@2.16.0 - amplify-category-predictions@2.5.0 - amplify-category-storage@2.8.0 - amplify-category-xr@2.5.0 - amplify-cli-core@1.4.0 - @aws-amplify/cli@4.30.0 - amplify-console-hosting@1.4.9 - amplify-console-integration-tests@1.2.29 - amplify-dotnet-function-template-provider@1.3.4 - amplify-e2e-core@1.8.0 - amplify-e2e-tests@2.26.0 - amplify-frontend-javascript@2.17.0 - amplify-migration-tests@2.18.7 - amplify-provider-awscloudformation@4.27.0 - amplify-util-import@1.1.0 - amplify-util-mock@3.24.16 - graphql-auth-transformer@6.20.8 - graphql-connection-transformer@4.18.14 - graphql-dynamodb-transformer@6.19.15 - graphql-elasticsearch-transformer@4.7.17 - graphql-function-transformer@2.3.21 - graphql-http-transformer@4.15.21 - graphql-key-transformer@2.19.14 - graphql-predictions-transformer@2.3.21 - graphql-transformer-core@6.21.6 - graphql-transformers-e2e-tests@6.18.17 - graphql-versioned-transformer@4.15.22 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 0c00274abd..818ec4ad11 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3a1e3ae06b..b09083df6c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.24.1", + "version": "2.25.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.20.2", - "amplify-category-function": "2.25.3", + "amplify-category-auth": "2.21.0", + "amplify-category-function": "2.25.4", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.16", - "graphql-transformer-core": "6.21.5", + "graphql-transformer-core": "6.21.6", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 440e07117d09b36072d9b71f9caa4c1b5484652d Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Tue, 20 Oct 2020 19:28:30 -0700 Subject: [PATCH 360/587] fix: refactor mobile hub migration checks (#5632) * fix: refactor mobile hub migration checks * chore: fix comment --- .../awscloudformation/service-walkthroughs/apigw-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0747b549a1..e78bb386e0 100644 --- 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 @@ -36,7 +36,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const { getAllDefaults } = await import(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); const resources = allResources - .filter(resource => resource.service === serviceName && !!resource.providerPlugin) + .filter(resource => resource.service === serviceName && resource.mobileHubMigrated !== true) .map(resource => resource.resourceName); // There can only be one appsync resource From 505ad99512d8a4cb90ab4e771d187f6305eb6355 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 22 Oct 2020 23:34:52 +0000 Subject: [PATCH 361/587] chore(release): Publish [ci skip] - amplify-app@2.17.16 - amplify-appsync-simulator@1.23.7 - amplify-category-analytics@2.18.1 - amplify-category-api@2.25.1 - amplify-category-auth@2.21.1 - amplify-category-function@2.25.5 - amplify-category-hosting@2.4.6 - amplify-category-interactions@2.5.1 - amplify-category-notifications@2.16.1 - amplify-category-predictions@2.5.1 - amplify-category-storage@2.8.1 - amplify-category-xr@2.5.1 - amplify-cli-core@1.5.0 - @aws-amplify/cli@4.31.0 - amplify-codegen-appsync-model-plugin@1.20.9 - amplify-codegen@2.16.0 - amplify-console-hosting@1.4.10 - amplify-console-integration-tests@1.2.30 - amplify-dotnet-function-template-provider@1.3.5 - amplify-dynamodb-simulator@1.15.0 - amplify-e2e-core@1.8.1 - amplify-e2e-tests@2.27.0 - amplify-frontend-javascript@2.17.1 - amplify-go-function-runtime-provider@1.3.0 - amplify-graphiql-explorer@1.3.4 - amplify-graphql-types-generator@2.5.2 - amplify-java-function-runtime-provider@1.3.0 - amplify-migration-tests@2.18.8 - amplify-provider-awscloudformation@4.28.0 - amplify-python-function-runtime-provider@1.3.0 - amplify-util-import@1.1.1 - amplify-util-mock@3.25.0 - graphql-auth-transformer@6.20.9 - graphql-connection-transformer@4.18.15 - graphql-dynamodb-transformer@6.19.16 - graphql-elasticsearch-transformer@4.7.18 - graphql-function-transformer@2.3.22 - graphql-http-transformer@4.15.22 - graphql-key-transformer@2.19.15 - graphql-mapping-template@4.15.3 - graphql-predictions-transformer@2.3.22 - graphql-relational-schema-transformer@2.15.17 - graphql-transformer-common@4.17.11 - graphql-transformer-core@6.21.7 - graphql-transformers-e2e-tests@6.18.18 - graphql-versioned-transformer@4.15.23 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 818ec4ad11..2c3f3d2d9b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b09083df6c..cb45be23c7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.0", + "version": "2.25.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.21.0", - "amplify-category-function": "2.25.4", + "amplify-category-auth": "2.21.1", + "amplify-category-function": "2.25.5", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.16", - "graphql-transformer-core": "6.21.6", + "graphql-relational-schema-transformer": "2.15.17", + "graphql-transformer-core": "6.21.7", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 5f87eec592ac5f32b6aa05379ac9b28c24a34d57 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 27 Oct 2020 01:18:34 +0000 Subject: [PATCH 362/587] chore(release): Publish [ci skip] - amplify-app@2.17.17 - amplify-appsync-simulator@1.23.8 - amplify-category-analytics@2.18.2 - amplify-category-api@2.25.2 - amplify-category-auth@2.21.2 - amplify-category-function@2.25.6 - amplify-category-interactions@2.5.2 - amplify-category-notifications@2.16.2 - amplify-category-predictions@2.5.2 - amplify-category-storage@2.8.2 - amplify-category-xr@2.5.2 - amplify-cli-core@1.5.1 - @aws-amplify/cli@4.31.1 - amplify-codegen@2.16.1 - amplify-console-hosting@1.4.11 - amplify-console-integration-tests@1.2.31 - amplify-dotnet-function-template-provider@1.3.6 - amplify-dynamodb-simulator@1.15.1 - amplify-e2e-core@1.8.2 - amplify-e2e-tests@2.27.1 - amplify-frontend-javascript@2.17.2 - amplify-go-function-runtime-provider@1.3.1 - amplify-java-function-runtime-provider@1.3.1 - amplify-migration-tests@2.18.9 - amplify-provider-awscloudformation@4.28.1 - amplify-python-function-runtime-provider@1.3.1 - amplify-util-import@1.1.2 - amplify-util-mock@3.25.1 - graphql-auth-transformer@6.20.10 - graphql-connection-transformer@4.18.16 - graphql-key-transformer@2.19.16 - graphql-transformers-e2e-tests@6.18.19 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2c3f3d2d9b..77fb4efcf3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index cb45be23c7..b506517a98 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.1", + "version": "2.25.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,8 +17,8 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.21.1", - "amplify-category-function": "2.25.5", + "amplify-category-auth": "2.21.2", + "amplify-category-function": "2.25.6", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", From 5e316f72a0f5c3749de84b660ed560aa7df49c22 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 30 Oct 2020 18:49:53 +0000 Subject: [PATCH 363/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.23.9 - amplify-category-analytics@2.18.3 - amplify-category-api@2.25.3 - amplify-category-auth@2.22.0 - amplify-category-function@2.25.7 - amplify-category-interactions@2.5.3 - amplify-category-notifications@2.16.3 - amplify-category-predictions@2.5.3 - amplify-category-storage@2.8.3 - amplify-category-xr@2.5.3 - @aws-amplify/cli@4.32.0 - amplify-codegen-appsync-model-plugin@1.20.10 - amplify-codegen@2.16.2 - amplify-console-integration-tests@1.2.32 - amplify-e2e-core@1.8.3 - amplify-e2e-tests@2.27.2 - amplify-go-function-runtime-provider@1.3.2 - amplify-migration-tests@2.18.10 - amplify-nodejs-function-runtime-provider@1.1.6 - amplify-provider-awscloudformation@4.28.2 - amplify-util-mock@3.25.2 - graphql-auth-transformer@6.21.0 - graphql-connection-transformer@4.18.17 - graphql-dynamodb-transformer@6.19.17 - graphql-elasticsearch-transformer@4.8.0 - graphql-function-transformer@2.3.23 - graphql-http-transformer@4.15.23 - graphql-key-transformer@2.19.17 - graphql-mapping-template@4.16.0 - graphql-predictions-transformer@2.3.23 - graphql-relational-schema-transformer@2.15.18 - graphql-transformer-common@4.17.12 - graphql-transformer-core@6.21.8 - graphql-transformers-e2e-tests@6.19.0 - graphql-versioned-transformer@4.15.24 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 77fb4efcf3..9477565c01 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b506517a98..9e40059e4c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.2", + "version": "2.25.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.21.2", - "amplify-category-function": "2.25.6", + "amplify-category-auth": "2.22.0", + "amplify-category-function": "2.25.7", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.17", - "graphql-transformer-core": "6.21.7", + "graphql-relational-schema-transformer": "2.15.18", + "graphql-transformer-core": "6.21.8", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From bc44f85ee358da6beea5fbc53fb1d491e10e8c2a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 8 Nov 2020 01:14:57 +0000 Subject: [PATCH 364/587] chore(release): Publish [ci skip] - amplify-app@2.17.18 - amplify-category-analytics@2.18.4 - amplify-category-api@2.25.4 - amplify-category-auth@2.22.1 - amplify-category-function@2.25.8 - amplify-category-interactions@2.5.4 - amplify-category-notifications@2.16.4 - amplify-category-predictions@2.5.4 - amplify-category-storage@2.8.4 - amplify-category-xr@2.5.4 - amplify-cli-core@1.6.0 - @aws-amplify/cli@4.32.1 - amplify-console-hosting@1.4.12 - amplify-console-integration-tests@1.2.33 - amplify-dotnet-function-template-provider@1.3.7 - amplify-dynamodb-simulator@1.15.2 - amplify-e2e-core@1.8.4 - amplify-e2e-tests@2.27.3 - amplify-frontend-javascript@2.17.3 - amplify-go-function-runtime-provider@1.3.3 - @aws-amplify/graphql-model-transformer@0.1.0 - @aws-amplify/graphql-transformer-core@0.1.0 - @aws-amplify/graphql-transformer-interfaces@1.1.0 - amplify-java-function-runtime-provider@1.3.2 - amplify-migration-tests@2.18.11 - amplify-provider-awscloudformation@4.29.0 - amplify-python-function-runtime-provider@1.3.2 - amplify-util-import@1.1.3 - amplify-util-mock@3.25.3 - graphql-auth-transformer@6.21.1 - graphql-connection-transformer@4.18.18 - graphql-dynamodb-transformer@6.20.0 - graphql-elasticsearch-transformer@4.8.1 - graphql-function-transformer@2.3.24 - graphql-http-transformer@4.15.24 - graphql-key-transformer@2.19.18 - graphql-mapping-template@4.17.0 - graphql-predictions-transformer@2.3.24 - graphql-relational-schema-transformer@2.15.19 - graphql-transformer-common@4.17.13 - graphql-transformer-core@6.22.0 - graphql-transformers-e2e-tests@6.19.1 - graphql-versioned-transformer@4.15.25 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9477565c01..aae2a918b3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9e40059e4c..d18409c948 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.3", + "version": "2.25.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,14 +17,14 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.22.0", - "amplify-category-function": "2.25.7", + "amplify-category-auth": "2.22.1", + "amplify-category-function": "2.25.8", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.18", - "graphql-transformer-core": "6.21.8", + "graphql-relational-schema-transformer": "2.15.19", + "graphql-transformer-core": "6.22.0", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 8be89c7012ce17cdd3facfa725f866df7e31cde6 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 9 Nov 2020 09:08:27 -0800 Subject: [PATCH 365/587] chore: remove circular and direct dependencies between CLI packages (#5792) * chore: remove circular and direct dependencies - Remove circular and direct dependencies within category and other packages. - Add `invokePluginMethod` to AmplifyToolkit to enable cross package invocations. --- packages/amplify-category-api/package.json | 2 - .../cfn-api-artifact-handler.ts | 6 ++- .../service-walkthroughs/apigw-walkthrough.ts | 51 +++++++++++-------- .../appSync-walkthrough.ts | 8 +-- packages/amplify-category-api/tsconfig.json | 1 - 5 files changed, 36 insertions(+), 32 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d18409c948..ea4f477939 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,8 +17,6 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-category-auth": "2.22.1", - "amplify-category-function": "2.25.8", "amplify-util-headless-input": "1.3.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", 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 index 3186996ce8..9edb251d80 100644 --- 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 @@ -15,10 +15,12 @@ import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-c import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; import uuid from 'uuid'; import _ from 'lodash'; -import { ServiceName as FunctionServiceName } from 'amplify-category-function'; import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from './utils/amplify-meta-utils'; import { printApiKeyWarnings } from './utils/print-api-key-warnings'; +// keep in sync with ServiceName in amplify-category-function, but probably it will not change +const FunctionServiceNameLambdaFunction = 'Lambda'; + export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { return new CfnApiArtifactHandler(context); }; @@ -240,7 +242,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await this.context.amplify.copyBatch(this.context, copyJobs, functionProps, true); const backendConfigs = { - service: FunctionServiceName.LambdaFunction, + service: FunctionServiceNameLambdaFunction, providerPlugin: provider, build: true, }; 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 index e78bb386e0..ace62cf5c2 100644 --- 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 @@ -5,9 +5,11 @@ import os from 'os'; import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; -import { ServiceName as FunctionServiceName } from 'amplify-category-function'; import { ResourceDoesNotExistError, exitOnNextTick } from 'amplify-cli-core'; +// keep in sync with ServiceName in amplify-category-function, but probably it will not change +const FunctionServiceNameLambdaFunction = 'Lambda'; + const category = 'api'; const serviceName = 'API Gateway'; const parametersFileName = 'api-params.json'; @@ -213,7 +215,6 @@ async function askPrivacy(context, answers, currentPath) { let permissionSelected = 'Auth/Guest Users'; const privacy: any = {}; - const { checkRequirements, externalAuthEnable } = await import('amplify-category-auth'); if (userPoolGroupList.length > 0) { do { @@ -280,7 +281,7 @@ async function askPrivacy(context, answers, currentPath) { const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); + await ensureAuth(context, apiRequirements, answers.resourceName); } if (answer.privacy === 'protected') { @@ -288,7 +289,7 @@ async function askPrivacy(context, answers, currentPath) { privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; - await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); + await ensureAuth(context, apiRequirements, answers.resourceName); } } @@ -297,7 +298,7 @@ async function askPrivacy(context, answers, currentPath) { const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; - await ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, answers.resourceName); + await ensureAuth(context, apiRequirements, answers.resourceName); // Get Auth resource name const authResourceName = await getAuthResourceName(context); @@ -347,8 +348,13 @@ async function askPrivacy(context, answers, currentPath) { } } -async function ensureAuth(checkRequirements, externalAuthEnable, context, apiRequirements, resourceName) { - const checkResult = await checkRequirements(apiRequirements, context, 'api', resourceName); +async function ensureAuth(context, apiRequirements, resourceName) { + const checkResult = 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. @@ -363,7 +369,12 @@ async function ensureAuth(checkRequirements, externalAuthEnable, context, apiReq // If auth is not imported and there were errors, adjust or enable auth configuration if (!checkResult.authEnabled || !checkResult.requirementsMet) { try { - await externalAuthEnable(context, 'api', resourceName, apiRequirements); + await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ + context, + 'api', + resourceName, + apiRequirements, + ]); } catch (error) { context.print.error(error); throw error; @@ -571,7 +582,7 @@ function functionsExist(context) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceName.LambdaFunction) { + if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { lambdaFunctions.push(resourceName); } }); @@ -597,12 +608,6 @@ async function askLambdaSource(context, functionType, path, currentPath) { } async function newLambdaFunction(context, path) { - let add; - try { - ({ add } = await import('amplify-category-function')); - } catch (e) { - throw new Error('Function plugin not installed in the CLI. You need to install it to use this feature.'); - } context.api = { path, // ExpressJS represents path parameters as /:param instead of /{param}. This expression performs this replacement. @@ -618,17 +623,23 @@ async function newLambdaFunction(context, path) { }, }; - return add(context, 'awscloudformation', FunctionServiceName.LambdaFunction, params).then(resourceName => { - context.print.success('Succesfully added the Lambda function locally'); - return { lambdaFunction: resourceName }; - }); + const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ + context, + 'awscloudformation', + FunctionServiceNameLambdaFunction, + params, + ]); + + context.print.success('Succesfully added the Lambda function locally'); + + return { lambdaFunction: resourceName }; } async function askLambdaFromProject(context, currentPath) { const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceName.LambdaFunction) { + if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { lambdaFunctions.push(resourceName); } }); 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 index ec8fccc91c..823b02f622 100644 --- 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 @@ -506,13 +506,7 @@ async function askUserPoolQuestions(context) { let authResourceName = checkIfAuthExists(context); if (!authResourceName) { - try { - const { add } = require('amplify-category-auth'); - - authResourceName = await add(context); - } catch (e) { - context.print.error('Auth plugin not installed in the CLI. You need to install it to use this feature.'); - } + authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context]); } else { context.print.info('Use a Cognito user pool configured as a part of this project.'); } diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 6c9cdb52cd..bbff900511 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -12,7 +12,6 @@ "src/__tests__" ], "references": [ - {"path": "../amplify-category-auth"}, {"path": "../amplify-headless-interface"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, From bc0af2628ace67b5d3fd2ff04fc83bdb65442c19 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 19 Nov 2020 11:29:13 -0800 Subject: [PATCH 366/587] chore: version bump (#5911) --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index aae2a918b3..d47eb58a8c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ea4f477939..9cd50f22e5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.4", + "version": "2.25.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -22,7 +22,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.19", - "graphql-transformer-core": "6.22.0", + "graphql-transformer-core": "6.22.1", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 32c44202791c013a8a17ee0bbd3594515d0a667a Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 19 Nov 2020 21:29:39 -0800 Subject: [PATCH 367/587] chore: version bump (#5919) --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d47eb58a8c..492abdd2ab 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9cd50f22e5..14586e07fc 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.5", + "version": "2.25.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -22,7 +22,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.19", - "graphql-transformer-core": "6.22.1", + "graphql-transformer-core": "6.22.2", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From f5da95efc5592f2f08fc83e3c8e215dd03110fc2 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Fri, 20 Nov 2020 10:30:42 -0800 Subject: [PATCH 368/587] chore: version bump (#5920) --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 492abdd2ab..39e1ff61b3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 14586e07fc..6298712828 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.6", + "version": "2.25.7", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -22,7 +22,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.15.19", - "graphql-transformer-core": "6.22.2", + "graphql-transformer-core": "6.22.3", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 0bcc786ae444af22d82481f7d2084d92accc8494 Mon Sep 17 00:00:00 2001 From: Nikhil Lingireddy Date: Sat, 21 Nov 2020 16:31:50 -0800 Subject: [PATCH 369/587] chore: bump lerna minor version (#5926) --- packages/amplify-category-api/CHANGELOG.md | 70 ++++++++++++++++++++++ packages/amplify-category-api/package.json | 8 +-- 2 files changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 39e1ff61b3..830ddedcb6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,76 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 6298712828..8f2e3b0753 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.25.7", + "version": "2.26.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,12 +17,12 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-util-headless-input": "1.3.0", + "amplify-util-headless-input": "1.4.0", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.15.19", - "graphql-transformer-core": "6.22.3", + "graphql-relational-schema-transformer": "2.16.0", + "graphql-transformer-core": "6.23.0", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 16e997ebc380f3b56ba9c7d21b46e255e21bd1aa Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 22 Nov 2020 01:46:54 +0000 Subject: [PATCH 370/587] chore(release): Publish [ci skip] - amplify-app@2.18.1 - amplify-appsync-simulator@1.24.1 - amplify-category-analytics@2.19.1 - amplify-category-api@2.26.1 - amplify-category-auth@2.24.0 - amplify-category-function@2.26.1 - amplify-category-hosting@2.5.1 - amplify-category-interactions@2.6.1 - amplify-category-notifications@2.17.1 - amplify-category-predictions@2.6.1 - amplify-category-storage@2.10.0 - amplify-category-xr@2.6.1 - amplify-cli-core@1.8.0 - @aws-amplify/cli@4.34.0 - amplify-codegen-appsync-model-plugin@1.21.1 - amplify-codegen@2.17.1 - amplify-console-hosting@1.5.1 - amplify-console-integration-tests@1.3.1 - amplify-dotnet-function-runtime-provider@1.3.1 - amplify-dotnet-function-template-provider@1.4.1 - amplify-dynamodb-simulator@1.16.1 - amplify-e2e-core@1.10.0 - amplify-e2e-tests@2.29.0 - amplify-frontend-android@2.14.1 - amplify-frontend-ios@2.14.1 - amplify-frontend-javascript@2.18.1 - amplify-function-plugin-interface@1.5.1 - amplify-go-function-runtime-provider@1.4.1 - amplify-go-function-template-provider@1.3.1 - amplify-graphiql-explorer@1.4.1 - amplify-graphql-docs-generator@2.2.1 - @aws-amplify/graphql-model-transformer@0.2.1 - @aws-amplify/graphql-transformer-core@0.2.1 - @aws-amplify/graphql-transformer-interfaces@1.2.1 - amplify-graphql-types-generator@2.6.1 - amplify-headless-interface@1.5.1 - amplify-java-function-runtime-provider@1.4.1 - amplify-java-function-template-provider@1.5.1 - amplify-migration-tests@2.19.1 - amplify-nodejs-function-runtime-provider@1.2.1 - amplify-nodejs-function-template-provider@1.5.1 - amplify-provider-awscloudformation@4.31.0 - amplify-python-function-runtime-provider@1.4.1 - amplify-python-function-template-provider@1.3.1 - amplify-storage-simulator@1.5.1 - amplify-ui-tests@2.14.1 - amplify-util-headless-input@1.4.1 - amplify-util-import@1.3.0 - amplify-util-mock@3.26.1 - amplify-velocity-template@1.4.1 - graphql-auth-transformer@6.22.1 - graphql-connection-transformer@4.19.1 - graphql-dynamodb-transformer@6.21.1 - graphql-elasticsearch-transformer@4.9.1 - graphql-function-transformer@2.4.1 - graphql-http-transformer@4.16.1 - graphql-key-transformer@2.20.1 - graphql-mapping-template@4.18.1 - graphql-predictions-transformer@2.4.1 - graphql-relational-schema-transformer@2.16.1 - graphql-transformer-common@4.18.1 - graphql-transformer-core@6.23.1 - graphql-transformers-e2e-tests@6.20.1 - graphql-versioned-transformer@4.16.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 830ddedcb6..4b5ca72938 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8f2e3b0753..54ad3d07df 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.26.0", + "version": "2.26.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,12 +17,12 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-util-headless-input": "1.4.0", + "amplify-util-headless-input": "1.4.1", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.0", - "graphql-transformer-core": "6.23.0", + "graphql-relational-schema-transformer": "2.16.1", + "graphql-transformer-core": "6.23.1", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 13e923e195aac9f4ca00ca3e873b2cd8ce2ed869 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 24 Nov 2020 19:59:10 +0000 Subject: [PATCH 371/587] chore(release): Publish [ci skip] - amplify-category-api@2.26.2 - amplify-category-auth@2.24.1 - amplify-category-storage@2.10.1 - @aws-amplify/cli@4.35.0 - amplify-console-integration-tests@1.3.2 - amplify-e2e-core@1.10.1 - amplify-e2e-tests@2.29.1 - amplify-headless-interface@1.5.2 - amplify-migration-tests@2.19.2 - amplify-provider-awscloudformation@4.32.0 - amplify-util-headless-input@1.4.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4b5ca72938..58e35609fc 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 54ad3d07df..da9dc0ff18 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.26.1", + "version": "2.26.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ }, "dependencies": { "@graphql-tools/merge": "^6.0.18", - "amplify-util-headless-input": "1.4.1", + "amplify-util-headless-input": "1.4.2", "chalk": "^3.0.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From 69e0f0395ebe31dc220afdb4e0aa3a48ac236ed0 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Sun, 29 Nov 2020 20:17:00 -0500 Subject: [PATCH 372/587] feat: pre-deploy pull, new login mechanism and pkg cli updates (#5941) Co-authored-by: Kaustav Ghosh Co-authored-by: John Hockett Co-authored-by: Diego Costantino --- .../src/commands/api/console.js | 8 ++--- .../appSync-walkthrough.ts | 31 ++++++++++++++++--- 2 files changed, 29 insertions(+), 10 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/console.js b/packages/amplify-category-api/src/commands/api/console.js index f208c9faee..a8bc4d57bc 100644 --- a/packages/amplify-category-api/src/commands/api/console.js +++ b/packages/amplify-category-api/src/commands/api/console.js @@ -8,14 +8,12 @@ module.exports = { const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; return amplify .serviceSelectionPrompt(context, category, servicesMetadata) - .then(result => { + .then(async result => { const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { - context.print.error('Provider not configured for this category'); - return; + throw new Error(`Provider "${result.providerName}" is not configured for this category`); } - - return providerController.console(context, result.service); + return await providerController.console(context, result.service); }) .catch(err => { context.print.error('Error opening console.'); 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 index 823b02f622..6646d643cb 100644 --- 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 @@ -12,7 +12,14 @@ import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-au import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; -import { ResourceAlreadyExistsError, ResourceDoesNotExistError, UnknownResourceTypeError, exitOnNextTick } from 'amplify-cli-core'; +import { + ResourceAlreadyExistsError, + ResourceDoesNotExistError, + UnknownResourceTypeError, + exitOnNextTick, + stateManager, + $TSContext, +} from 'amplify-cli-core'; const serviceName = 'AppSync'; const providerName = 'awscloudformation'; @@ -37,8 +44,8 @@ const authProviderChoices = [ }, ]; -export const openConsole = context => { - const amplifyMeta = context.amplify.getProjectMeta(); +export const openConsole = async (context: $TSContext) => { + const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; let appSyncMeta; Object.keys(categoryAmplifyMeta).forEach(resourceName => { @@ -49,16 +56,30 @@ export const openConsole = context => { if (appSyncMeta) { const { GraphQLAPIIdOutput } = appSyncMeta; + const appId = amplifyMeta.providers[providerName].AmplifyAppId; + if (!appId) { + throw new Error('Missing AmplifyAppId in amplify-meta.json'); + } const { Region } = amplifyMeta.providers[providerName]; + let consoleUrl = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - const consoleUrl = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; + const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); + const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); + if (isAdminApp) { + if (region !== Region) { + context.print.warning(`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; + consoleUrl = `${baseUrl}/admin/${appId}/${envName}/datastore`; + } open(consoleUrl, { wait: false }); } else { context.print.error('AppSync API is not pushed in the cloud.'); } }; -export const serviceWalkthrough = async (context, defaultValuesFilename, serviceMetadata) => { +export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); let authConfig; let defaultAuthType; From a461ec2fbd367b9009cb824b7696cd66b1441e5c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 30 Nov 2020 22:33:59 +0000 Subject: [PATCH 373/587] chore(release): Publish [ci skip] - amplify-app@2.20.0 - amplify-category-api@2.27.0 - amplify-category-auth@2.25.0 - amplify-category-function@2.26.3 - amplify-category-storage@2.10.3 - amplify-cli-core@1.10.0 - @aws-amplify/cli@4.37.0 - amplify-codegen@2.19.0 - amplify-console-hosting@1.6.0 - amplify-console-integration-tests@1.3.5 - amplify-dotnet-function-runtime-provider@1.4.0 - amplify-dotnet-function-template-provider@1.4.3 - amplify-dynamodb-simulator@1.17.0 - amplify-e2e-core@1.11.0 - amplify-e2e-tests@2.31.0 - amplify-frontend-ios@2.16.0 - amplify-frontend-javascript@2.19.0 - amplify-go-function-runtime-provider@1.5.0 - amplify-java-function-runtime-provider@1.5.0 - amplify-migration-tests@2.19.5 - amplify-nodejs-function-runtime-provider@1.3.0 - amplify-provider-awscloudformation@4.33.0 - amplify-python-function-runtime-provider@1.5.0 - amplify-util-import@1.3.2 - amplify-util-mock@3.27.0 - graphql-auth-transformer@6.23.0 - graphql-connection-transformer@4.19.2 - graphql-dynamodb-transformer@6.21.2 - graphql-elasticsearch-transformer@4.9.2 - graphql-function-transformer@2.4.2 - graphql-http-transformer@4.16.2 - graphql-key-transformer@2.20.2 - graphql-predictions-transformer@2.4.2 - graphql-transformer-core@6.24.0 - graphql-transformers-e2e-tests@6.21.0 - graphql-versioned-transformer@4.16.2 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 58e35609fc..ab5314ffa6 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index da9dc0ff18..8ebdc90d6d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.26.2", + "version": "2.27.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -22,7 +22,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.1", - "graphql-transformer-core": "6.23.1", + "graphql-transformer-core": "6.24.0", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 81d8d9377be8f9e1e39a6e29b381db279c542f99 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 7 Dec 2020 18:48:20 +0000 Subject: [PATCH 374/587] chore(release): Publish [ci skip] - amplify-app@2.20.1 - amplify-appsync-simulator@1.24.2 - amplify-category-analytics@2.19.2 - amplify-category-api@2.27.1 - amplify-category-auth@2.25.1 - amplify-category-function@2.27.0 - amplify-category-storage@2.10.4 - amplify-cli-core@1.11.0 - amplify-cli-logger@1.1.0 - @aws-amplify/cli@4.38.0 - amplify-codegen@2.20.0 - amplify-console-hosting@1.6.1 - amplify-console-integration-tests@1.3.6 - amplify-dotnet-function-template-provider@1.4.4 - amplify-dynamodb-simulator@1.17.1 - amplify-e2e-core@1.12.0 - amplify-e2e-tests@2.32.0 - amplify-frontend-ios@2.17.0 - amplify-frontend-javascript@2.19.1 - amplify-go-function-runtime-provider@1.5.1 - amplify-java-function-runtime-provider@1.5.1 - amplify-migration-tests@2.19.6 - amplify-nodejs-function-template-provider@1.5.2 - amplify-provider-awscloudformation@4.34.0 - amplify-python-function-runtime-provider@1.5.1 - amplify-util-import@1.3.3 - amplify-util-mock@3.27.2 - amplify-velocity-template@1.4.2 - graphql-auth-transformer@6.23.1 - graphql-connection-transformer@4.19.3 - graphql-dynamodb-transformer@6.21.3 - graphql-elasticsearch-transformer@4.9.3 - graphql-function-transformer@2.4.3 - graphql-http-transformer@4.16.3 - graphql-key-transformer@2.20.3 - graphql-predictions-transformer@2.4.3 - graphql-transformer-core@6.25.0 - graphql-transformers-e2e-tests@6.21.1 - graphql-versioned-transformer@4.16.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ab5314ffa6..c88c0ab451 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8ebdc90d6d..0944a8b17a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.27.0", + "version": "2.27.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -22,7 +22,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.1", - "graphql-transformer-core": "6.24.0", + "graphql-transformer-core": "6.25.0", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 772ee60335cba121547d9f4a4ba24bf7d6e5ce02 Mon Sep 17 00:00:00 2001 From: Francisco Rodriguez Date: Wed, 9 Dec 2020 12:11:29 -0800 Subject: [PATCH 375/587] feat: container-based deployments(#5727) Co-authored-by: Manuel Iglesias <6154160+manueliglesias@users.noreply.github.com> Co-authored-by: Francisco Rodriguez Co-authored-by: Richard Threlkeld --- packages/amplify-category-api/package.json | 46 ++ .../docker-compose.yml | 23 + .../express/Dockerfile | 13 + .../express/DynamoDBActions.js | 60 ++ .../express/index.js | 124 ++++ .../express/package.json | 17 + .../python/Dockerfile | 17 + .../python/requirements.txt | 1 + .../python/src/server.py | 9 + .../dockerfile-rest-express/Dockerfile | 12 + .../DynamoDBActions.js | 60 ++ .../dockerfile-rest-express/index.js | 96 +++ .../dockerfile-rest-express/package.json | 16 + .../graphql-express/Dockerfile | 10 + .../graphql-express/index.js | 27 + .../graphql-express/package.json | 15 + .../graphql-express/resolvers.js | 58 ++ .../graphql-express/schema.js | 16 + .../lambdas/pipeline-on-event.js | 15 + .../awscloudformation/lambdas/pipeline.js | 108 ++++ .../awscloudformation/lambdas/predeploy.js | 20 + .../src/category-constants.ts | 1 + packages/amplify-category-api/src/index.ts | 12 +- .../awscloudformation/base-api-stack.ts | 522 +++++++++++++++ .../awscloudformation/containers-handler.ts | 253 ++++++++ .../default-values/containers-defaults.ts | 14 + .../docker-compose/DockerUtils.ts | 69 ++ .../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 | 84 +++ .../docker-compose/ecs-objects/service.ts | 70 ++ .../docker-compose/ecs-objects/types.ts | 93 +++ .../awscloudformation/docker-compose/index.ts | 3 + .../awscloudformation/ecs-alb-stack.ts | 290 +++++++++ .../awscloudformation/ecs-apigw-stack.ts | 101 +++ .../provider-utils/awscloudformation/index.ts | 214 ++++++- .../pipeline-with-awaiter.ts | 367 +++++++++++ .../service-walkthroughs/apigw-walkthrough.ts | 88 ++- .../appSync-walkthrough.ts | 98 ++- .../containers-walkthrough.ts | 354 +++++++++++ .../utils/containers-artifacts.ts | 353 +++++++++++ .../awscloudformation/utils/github.ts | 14 + packages/amplify-category-api/tsconfig.json | 2 + 46 files changed, 5039 insertions(+), 46 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0944a8b17a..f9a83f7672 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -12,13 +12,59 @@ "main": "lib/index.js", "scripts": { "build": "tsc", + "watch": "tsc -w", "clean": "rimraf lib tsconfig.tsbuildinfo", "test": "jest" }, "dependencies": { + "@aws-cdk/assets": "~1.72.0", + "@aws-cdk/aws-apigateway": "~1.72.0", + "@aws-cdk/aws-apigatewayv2": "~1.72.0", + "@aws-cdk/aws-applicationautoscaling": "~1.72.0", + "@aws-cdk/aws-autoscaling": "~1.72.0", + "@aws-cdk/aws-autoscaling-common": "~1.72.0", + "@aws-cdk/aws-autoscaling-hooktargets": "~1.72.0", + "@aws-cdk/aws-certificatemanager": "~1.72.0", + "@aws-cdk/aws-cloudformation":"1.72.0", + "@aws-cdk/aws-cloudfront": "~1.72.0", + "@aws-cdk/aws-cloudwatch": "~1.72.0", + "@aws-cdk/aws-codebuild":"~1.72.0", + "@aws-cdk/aws-codeguruprofiler":"1.72.0", + "@aws-cdk/aws-codepipeline":"~1.72.0", + "@aws-cdk/aws-codepipeline-actions":"~1.72.0", + "@aws-cdk/aws-cognito": "~1.72.0", + "@aws-cdk/aws-ec2": "~1.72.0", + "@aws-cdk/aws-ecr": "~1.72.0", + "@aws-cdk/aws-ecr-assets": "~1.72.0", + "@aws-cdk/aws-ecs": "~1.72.0", + "@aws-cdk/aws-efs":"1.72.0", + "@aws-cdk/aws-elasticloadbalancing": "~1.72.0", + "@aws-cdk/aws-elasticloadbalancingv2": "~1.72.0", + "@aws-cdk/aws-events": "~1.72.0", + "@aws-cdk/aws-iam": "~1.72.0", + "@aws-cdk/aws-kms": "~1.72.0", + "@aws-cdk/aws-lambda": "~1.72.0", + "@aws-cdk/aws-logs": "~1.72.0", + "@aws-cdk/aws-route53": "~1.72.0", + "@aws-cdk/aws-route53-targets": "~1.72.0", + "@aws-cdk/aws-s3": "~1.72.0", + "@aws-cdk/aws-s3-assets": "~1.72.0", + "@aws-cdk/aws-sam":"1.72.0", + "@aws-cdk/aws-secretsmanager": "~1.72.0", + "@aws-cdk/aws-servicediscovery": "~1.72.0", + "@aws-cdk/aws-sns": "~1.72.0", + "@aws-cdk/aws-sns-subscriptions": "~1.72.0", + "@aws-cdk/aws-sqs": "~1.72.0", + "@aws-cdk/aws-ssm": "~1.72.0", + "@aws-cdk/cloud-assembly-schema": "~1.72.0", + "@aws-cdk/core": "~1.72.0", + "@aws-cdk/custom-resources": "~1.72.0", + "@aws-cdk/cx-api": "~1.72.0", + "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", "amplify-util-headless-input": "1.4.2", "chalk": "^3.0.0", + "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.1", 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 new file mode 100644 index 0000000000..ec14c45640 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/docker-compose.yml @@ -0,0 +1,23 @@ +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 new file mode 100644 index 0000000000..b7a7be80ef --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/Dockerfile @@ -0,0 +1,13 @@ +FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 + +ENV PORT=8080 +EXPOSE 8080 + +WORKDIR /usr/src/app + +COPY package*.json ./ +RUN npm install +COPY . . + +CMD [ "node", "index.js" ] + \ No newline at end of file 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 new file mode 100644 index 0000000000..ca4e48cb06 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/DynamoDBActions.js @@ -0,0 +1,60 @@ +const AWS = require('aws-sdk'); +const docClient = new AWS.DynamoDB.DocumentClient(); + +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).promise() + 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).promise(); + 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).promise() + 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 new file mode 100644 index 0000000000..78228b2775 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/index.js @@ -0,0 +1,124 @@ +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/express/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json new file mode 100644 index 0000000000..bff7030c33 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/express/package.json @@ -0,0 +1,17 @@ +{ + "name": "express-lasagna", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": {}, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "aws-sdk": "^2.792.0", + "axios": "^0.16.2", + "body-parser": "^1.19.0", + "express": "^4.17.1", + "redis": "^3.0.2" + } +} 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 new file mode 100644 index 0000000000..8dd986b2b8 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/Dockerfile @@ -0,0 +1,17 @@ +# set base image (host OS) +FROM public.ecr.aws/bitnami/python:3.8-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 new file mode 100644 index 0000000000..0f2af12d22 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/requirements.txt @@ -0,0 +1 @@ +Flask==1.1.1 \ 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 new file mode 100644 index 0000000000..b46754de98 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockercompose-rest-express/python/src/server.py @@ -0,0 +1,9 @@ +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 new file mode 100644 index 0000000000..5409fbc7e0 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/Dockerfile @@ -0,0 +1,12 @@ +FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 + +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 new file mode 100644 index 0000000000..278e9975b2 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/DynamoDBActions.js @@ -0,0 +1,60 @@ +const AWS = require('aws-sdk'); +const docClient = new AWS.DynamoDB.DocumentClient(); + +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).promise() + 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).promise(); + 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).promise() + 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 new file mode 100644 index 0000000000..0d40649139 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/index.js @@ -0,0 +1,96 @@ +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/dockerfile-rest-express/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json new file mode 100644 index 0000000000..7df3fe7aae --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/dockerfile-rest-express/package.json @@ -0,0 +1,16 @@ +{ + "name": "express-lasagna", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + }, + "keywords": [], + "author": "", + "license": "ISC", + "dependencies": { + "aws-sdk": "^2.792.0", + "body-parser": "^1.19.0", + "express": "^4.17.1" + } + } \ 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 new file mode 100644 index 0000000000..b9fd49c25c --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile @@ -0,0 +1,10 @@ +FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 + +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 new file mode 100644 index 0000000000..685aa6d669 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/index.js @@ -0,0 +1,27 @@ +'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/package.json b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json new file mode 100644 index 0000000000..964344a7e9 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/package.json @@ -0,0 +1,15 @@ +{ + "name": "graphql", + "version": "1.0.0", + "description": "Sample GraphQL server for Fargate", + "main": "index.js", + "scripts": {}, + "author": "", + "license": "ISC", + "dependencies": { + "aws-sdk": "^2.790.0", + "express": "^4.17.1", + "express-graphql": "^0.11.0", + "graphql": "^15.4.0" + } +} 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 new file mode 100644 index 0000000000..e9c295fdf1 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/resolvers.js @@ -0,0 +1,58 @@ +const AWS = require('aws-sdk'); +const docClient = new AWS.DynamoDB.DocumentClient(); + +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).promise() + return params.Item; + } catch (err) { + return err + } +} + +const scanPostsFromDDB = async () => { + var params = { + TableName: TableName, + } + + try { + const data = await docClient.scan(params).promise(); + 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).promise() + 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 new file mode 100644 index 0000000000..0c9b2ef376 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/schema.js @@ -0,0 +1,16 @@ +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/lambdas/pipeline-on-event.js b/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js new file mode 100644 index 0000000000..bbec181a7e --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline-on-event.js @@ -0,0 +1,15 @@ +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 new file mode 100644 index 0000000000..daa3a4e1a4 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/lambdas/pipeline.js @@ -0,0 +1,108 @@ +const AWS = require('aws-sdk'); + +const stageName = 'Source'; +const actionName = 'Source'; + +const codePipeline = new AWS.CodePipeline(); +const cloudFormation = new AWS.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 }).promise(); + const [{ StackStatus }] = Stacks; + + if (StackStatus.includes('ROLLBACK')) { + return { IsComplete: true }; + } + } + + let stages; + + try { + const { pipeline } = await codePipeline.getPipeline({ name: pipelineName }).promise(); + + ({ 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 }).promise(); + + [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 new file mode 100644 index 0000000000..f5a0aa5423 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/lambdas/predeploy.js @@ -0,0 +1,20 @@ +const AWS = require('aws-sdk'); + +const codepipeline = new AWS.CodePipeline(); +const ecs = new AWS.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, + }) + .promise(); + + return await codepipeline.putJobSuccessResult({ jobId }).promise(); +}; diff --git a/packages/amplify-category-api/src/category-constants.ts b/packages/amplify-category-api/src/category-constants.ts index 83ae597bec..5851dbb6a0 100644 --- a/packages/amplify-category-api/src/category-constants.ts +++ b/packages/amplify-category-api/src/category-constants.ts @@ -1 +1,2 @@ export const category = 'api'; +export const NETWORK_STACK_LOGICAL_ID = 'NetworkStack'; diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 3c8664f687..88591e6da9 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -1,8 +1,16 @@ -import { run } from './commands/api/console'; +import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; import fs from 'fs-extra'; import path from 'path'; +import { run } from './commands/api/console'; import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler'; -import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; + +export { NETWORK_STACK_LOGICAL_ID } from './category-constants' +export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack'; +export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; +export { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; +export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; +export { generateContainersArtifacts, ApiResource, processDockerConfig } from './provider-utils/awscloudformation/utils/containers-artifacts'; +export { getContainers } from './provider-utils/awscloudformation/docker-compose'; const category = 'api'; 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 new file mode 100644 index 0000000000..e197d4522e --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/base-api-stack.ts @@ -0,0 +1,522 @@ +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as iam from '@aws-cdk/aws-iam'; +import * as logs from '@aws-cdk/aws-logs'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as ssm from '@aws-cdk/aws-secretsmanager'; +import * as cloudmap from '@aws-cdk/aws-servicediscovery'; +import * as cdk from '@aws-cdk/core'; +import { prepareApp } from '@aws-cdk/core/lib/private/prepare-app'; +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.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; + envName: string; + categoryName: string; + apiName: string; + deploymentBucketName: 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; +}>; +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; + + constructor(scope: cdk.Construct, id: string, private readonly props: ContainersStackProps) { + super(scope, id); + + const { + parameters, + vpcId, + vpcCidrBlock, + subnets, + clusterName, + zipPath, + cloudMapNamespaceId, + vpcLinkId, + isAuthCondition, + appClientId, + userPoolId, + } = 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; + + 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, + 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 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); + + 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 ?? '', '')), + ), + }); + + 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, + }; + } + + private ecs() { + const { + envName, + categoryName, + apiName, + policies, + containers, + secretsArns, + taskEnvironmentVariables, + exposedContainer, + taskPorts, + isInitialDeploy, + desiredCount, + 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: `${envName}-${apiName}`, + }); + (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); + policies.forEach(policy => { + const statement = isPolicyStatement(policy) ? policy : wrapJsonPoliciesInCdkPolicies(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/${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 = `${envName}-${categoryName}-${apiName}-${name}`; + + if (this.props.existingEcrRepositories.has(repositoryName)) { + repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); + } else { + repository = new ecr.Repository(this, logicalId, { + repositoryName: `${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.fromSecretCompleteArn(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, + }); + + if (build) { + 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 { + envName, + deploymentBucketName, + deploymentMechanism, + desiredCount, + } = this.props; + + const s3SourceActionKey = this.zipPath; + + const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); + + const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { + skipWait, + 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`; + } + + toCloudFormation() { + prepareApp(this); + + const cfn = this._toCloudFormation(); + + Object.keys(cfn.Parameters).forEach(k => { + if (k.startsWith('AssetParameters')) { + let value = ''; + + if (k.includes('Bucket')) { + value = this.props.deploymentBucketName; + } else if (k.includes('VersionKey')) { + value = `${PIPELINE_AWAITER_ZIP}||`; + } + + cfn.Parameters[k].Default = value; + } + }); + + return cfn; + } +} + +/** + * Wraps an array of JSON IAM statements in a {iam.PolicyStatement} array. + * This allow us tu pass the statements in a way that CDK can use when synthesizing + * + * CDK looks for a toStatementJson function + * + * @param policy JSON object with IAM statements + * @returns {iam.PolicyStatement} CDK compatible policy statement + */ +function wrapJsonPoliciesInCdkPolicies(policy: Record): iam.PolicyStatement { + return { + toStatementJson() { + return policy; + }, + } as iam.PolicyStatement; +} + +function isPolicyStatement(obj: any): obj is iam.PolicyStatement { + if (obj && typeof (obj).toStatementJson === 'function') { + return true; + } + + return false; +} \ No newline at end of file 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 new file mode 100644 index 0000000000..d117d74517 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts @@ -0,0 +1,253 @@ +import fs from 'fs-extra'; +import path from 'path'; +import 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, + category, + service, + options, + apiType: API_TYPE, +) => { + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + const walkthroughOptions = await serviceWalkthroughPromise; + + const { + resourceName, + restrictAccess, + imageSource, + gitHubPath, + gitHubToken, + deploymentMechanism, + categoryPolicies, + environmentMap, + dependsOn = [], + mutableParametersState, + } = walkthroughOptions; + const resourceDirPath = path.join(projectBackendDirPath, 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); + + } + + context.print.success(`Successfully added resource ${resourceName} locally.`); + context.print.info(''); + context.print.success('Next steps:'); + + if (deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED) { + context.print.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) { + context.print.info( + `- Ensure you have the Dockerfile, docker-compose.yml and any related container source files in your Github path: ${gitHubInfo.path}`, + ); + } + + context.print.info( + `- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers`, + ); + context.print.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: any; + 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) { + context.print.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, category) => { + 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/default-values/containers-defaults.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts new file mode 100644 index 0000000000..da44caf946 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/containers-defaults.ts @@ -0,0 +1,14 @@ +const uuid = require('uuid'); + +const getAllDefaults = project => { + const [shortId] = uuid().split('-'); + const defaults = { + resourceName: `container${shortId}`, + }; + + return defaults; +}; + +module.exports = { + getAllDefaults, +}; 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 new file mode 100644 index 0000000000..6bb37bd57a --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/DockerUtils.ts @@ -0,0 +1,69 @@ +import 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.safeLoad(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 new file mode 100644 index 0000000000..771160d6cd --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v1.ts @@ -0,0 +1,103 @@ +/** + * 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 new file mode 100644 index 0000000000..a16b147f4d --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v2.ts @@ -0,0 +1,294 @@ +/** + * 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 new file mode 100644 index 0000000000..81cd2529eb --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.8.ts @@ -0,0 +1,596 @@ +/* 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 new file mode 100644 index 0000000000..605b7e86ec --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/compose-spec/v3.ts @@ -0,0 +1,156 @@ +/** + * 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 new file mode 100644 index 0000000000..2bafe72104 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/converter.ts @@ -0,0 +1,171 @@ +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; + + var 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 new file mode 100644 index 0000000000..df88393757 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/container.ts @@ -0,0 +1,84 @@ +import { IContainerDefinitions, PortMappings, IBuildConfig, ContainerHealthCheck, IContainerHealthCheckItem } from './types'; +import { ListOrDict } from '../compose-spec/v1'; + +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 new file mode 100644 index 0000000000..1786890422 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/service.ts @@ -0,0 +1,70 @@ +import { IServiceDefinition, ServiceHealthCheck, DeploymentConfiguration, ContainerConfig, TaskConfig } from './types'; +import Container from './container'; +import * as v38Types from '../compose-spec/v3.8'; + +//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 new file mode 100644 index 0000000000..4f844a78e0 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/ecs-objects/types.ts @@ -0,0 +1,93 @@ +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 new file mode 100644 index 0000000000..39f92df12e --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/docker-compose/index.ts @@ -0,0 +1,3 @@ +import { getContainers } from "./converter"; + +export { getContainers }; \ No newline at end of file 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 new file mode 100644 index 0000000000..e6ab69b25d --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-alb-stack.ts @@ -0,0 +1,290 @@ +import * as acm from '@aws-cdk/aws-certificatemanager'; +import * as cloudfront from '@aws-cdk/aws-cloudfront'; +import * as cognito from '@aws-cdk/aws-cognito'; +import * as ec2 from '@aws-cdk/aws-ec2'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2'; +import * as route53 from '@aws-cdk/aws-route53'; +import * as route53targets from '@aws-cdk/aws-route53-targets'; +import * as cdk from '@aws-cdk/core'; +import { ContainersStack, ContainersStackProps } from "./base-api-stack"; +import { v4 as uuid } from "uuid"; + +type EcsStackProps = ContainersStackProps & Readonly<{ + domainName: string; + hostedZoneId?: string; + authName: string; +}>; +export class EcsAlbStack extends ContainersStack { + private readonly userPoolDomain: string; + + constructor(scope: cdk.Construct, id: string, private readonly ecsProps: EcsStackProps) { + super(scope, id, { + ...ecsProps, + skipWait: false, + 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 { + envName, + 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-${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.addDependsOn(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.addDependsOn(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 new file mode 100644 index 0000000000..3925b5835b --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/ecs-apigw-stack.ts @@ -0,0 +1,101 @@ +import * as apigw2 from '@aws-cdk/aws-apigatewayv2'; +import * as cdk from '@aws-cdk/core'; +import { ContainersStack, ContainersStackProps } from "./base-api-stack"; +import { API_TYPE } from './service-walkthroughs/containers-walkthrough'; + +type EcsStackProps = Readonly; +export class EcsStack extends ContainersStack { + + constructor(scope: cdk.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 { envName, apiName } = this.ecsProps + + const api = new apigw2.CfnApi(this, 'Api', { + name: `${envName}-${apiName}`, + protocolType: 'HTTP', + corsConfiguration: { + allowHeaders: ['*'], + allowOrigins: ['*'], + allowMethods: Object.values(apigw2.HttpMethod).filter(m => m !== apigw2.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: apigw2.HttpIntegrationType.HTTP_PROXY, + connectionId: this.vpcLinkId, + connectionType: apigw2.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 index dc7812ff6d..da273c0857 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -6,6 +6,10 @@ import { legacyUpdateResource } from './legacy-update-resource'; import { UpdateApiRequest } from 'amplify-headless-interface'; import { editSchemaFlow } from './utils/edit-schema-flow'; import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; +import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; +import inquirer from 'inquirer'; +import { API_TYPE, ServiceConfiguration, getPermissionPolicies as getContainerPermissionPolicies } from './service-walkthroughs/containers-walkthrough'; +import { category } from '../../category-constants'; export async function console(context, service) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); @@ -22,7 +26,17 @@ export async function console(context, service) { return openConsole(context); } -export async function addResource(context, category, service, options) { +async function addContainerResource(context, category, service, options, apiType) { + const serviceWalkthroughFilename = 'containers-walkthrough.js'; + const defaultValuesFilename = 'containers-defaults.js'; + + const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); + const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, apiType); + + return await addContainer(serviceWalkthroughPromise, context, category, service, options, apiType); +} + +async function addNonContainerResource(context, category, service, options) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename, defaultValuesFilename } = serviceMetadata; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); @@ -42,7 +56,178 @@ export async function addResource(context, category, service, options) { } } -export async function updateResource(context, category, service) { +export async function addResource(context, category, service, options) { + let useContainerResource = false; + let apiType = API_TYPE.GRAPHQL; + + if (isContainersEnabled(context)) { + switch (service) { + case 'AppSync': + useContainerResource = await isGraphQLContainer(context); + apiType = API_TYPE.GRAPHQL; + break; + case 'API Gateway': + useContainerResource = await isRestContainer(context); + apiType = API_TYPE.REST; + break; + default: + throw new Error(`${service} not exists`); + } + } + + return useContainerResource + ? addContainerResource(context, category, service, options, apiType) + : addNonContainerResource(context, category, service, options); +} + +function isContainersEnabled(context) { + const { frontend } = context.amplify.getProjectConfig(); + if (frontend) { + const { config: { ServerlessContainers = false } = {} } = context.amplify.getProjectConfig()[frontend] || {}; + + return ServerlessContainers; + } + + return false; +} + +async function isGraphQLContainer(context): Promise { + const { graphqlSelection } = await inquirer.prompt({ + name: 'graphqlSelection', + message: 'Which service would you like to use', + type: 'list', + choices: [ + { + name: 'AppSync', + value: false, + }, + { + name: 'AWS Fargate (Container-based)', + value: true, + }, + ], + }); + + return graphqlSelection; +} + +async function isRestContainer(context) { + 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, category, service, options) { + let useContainerResource = false; + let apiType = API_TYPE.GRAPHQL; + if (isContainersEnabled(context)) { + const { + hasAPIGatewayContainerResource, + hasAPIGatewayLambdaResource, + hasGraphQLAppSyncResource, + hasGraphqlContainerResource + } = await describeApiResourcesBySubCategory(context); + + switch (service) { + case 'AppSync': + if (hasGraphQLAppSyncResource && hasGraphqlContainerResource) { + useContainerResource = await isGraphQLContainer(context); + } else if (hasGraphqlContainerResource) { + useContainerResource = true; + } else { + useContainerResource = false; + } + apiType = API_TYPE.GRAPHQL; + break; + case 'API Gateway': + if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { + useContainerResource = await isRestContainer(context); + } 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, category, service); +} + +async function describeApiResourcesBySubCategory(context) { + + 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 === 'API Gateway'; + + hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || + resource.service === 'AppSync'; + + hasGraphqlContainerResource = hasGraphqlContainerResource || + (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); + }) + + return { + hasAPIGatewayLambdaResource, + hasAPIGatewayContainerResource, + hasGraphQLAppSyncResource, + hasGraphqlContainerResource + }; +} + +async function updateContainerResource(context, category, service, apiType: API_TYPE) { + const serviceWalkthroughFilename = 'containers-walkthrough'; + const defaultValuesFilename = 'containers-defaults.js'; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { updateWalkthrough } = require(serviceWalkthroughSrc); + + if (!updateWalkthrough) { + const errMessage = 'Update functionality not available for this option'; + context.print.error(errMessage); + context.usageData.emitError(new NotImplementedError(errMessage)); + exitOnNextTick(0); + } + + const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, apiType); + + updateContainer(updateWalkthroughPromise, context, category); +} + +async function updateNonContainerResource(context, category, service) { const serviceMetadata = await serviceMetadataFor(service); const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; @@ -66,6 +251,19 @@ export async function updateResource(context, category, service) { } export async function migrateResource(context, projectPath, service, resourceName) { + if (service === 'ElasticContainer') { + return migrateResourceContainer(context, projectPath, service, resourceName); + } else { + return migrateResourceNonContainer(context, projectPath, service, resourceName); + } +} + +async function migrateResourceContainer(context, projectPath, service, resourceName) { + context.print.info(`No migration required for ${resourceName}`); + return; +} + +async function migrateResourceNonContainer(context, projectPath, service, resourceName) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; @@ -86,6 +284,18 @@ export async function addDatasource(context, category, datasource) { } export async function getPermissionPolicies(context, service, resourceName, crudOptions) { + if (service === 'ElasticContainer') { + return getPermissionPoliciesContainer(context, service, resourceName, crudOptions); + } else { + return getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions); + } +} + +async function getPermissionPoliciesContainer(context, service, resourceName, crudOptions) { + return getContainerPermissionPolicies(context, service, resourceName, crudOptions); +} + +async function getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; 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 new file mode 100644 index 0000000000..b7e7d19788 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts @@ -0,0 +1,367 @@ +import * as codebuild from '@aws-cdk/aws-codebuild'; +import * as codepipeline from '@aws-cdk/aws-codepipeline'; +import * as codepipelineactions from '@aws-cdk/aws-codepipeline-actions'; +import * as ecr from '@aws-cdk/aws-ecr'; +import * as ecs from '@aws-cdk/aws-ecs'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as s3 from '@aws-cdk/aws-s3'; +import * as cdk from '@aws-cdk/core'; +import * as custom from '@aws-cdk/custom-resources'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +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 lambdasDir = path.resolve(__dirname, '../../../resources/awscloudformation/lambdas'); + +class PipelineAwaiter extends cdk.Construct { + constructor(scope: cdk.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: lambda.Runtime.NODEJS_12_X, + 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: lambda.Runtime.NODEJS_12_X, + 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 cdk.Construct { + pipelineName: string; + constructor( + scope: cdk.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:BatchGetDownloadUrlForLayer', + '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); + + 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: lambda.Runtime.NODEJS_12_X, + 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: [ + new codepipelineactions.EcsDeployAction({ + actionName: 'Deploy', + service: new (class extends cdk.Construct implements ecs.IBaseService { + cluster = { + clusterName: service.cluster, + env: {}, + } as ecs.ICluster; + serviceArn = cdk.Fn.ref(service.serviceArn); + serviceName = service.serviceName; + stack = cdk.Stack.of(this); + env = {} as any; + node = service.node; + })(this, 'tmpService'), + input: buildOutput, + }), + ], + }, + ]); + + 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: cdk.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: lambda.Runtime.NODEJS_12_X, + 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/service-walkthroughs/apigw-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/apigw-walkthrough.ts index ace62cf5c2..9695322aea 100644 --- 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 @@ -3,15 +3,17 @@ import path from 'path'; import fs from 'fs-extra'; import os from 'os'; import uuid from 'uuid'; +import open from 'open'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; -import { ResourceDoesNotExistError, exitOnNextTick } from 'amplify-cli-core'; +import { ResourceDoesNotExistError, exitOnNextTick, $TSContext, stateManager } from 'amplify-cli-core'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; const category = 'api'; const serviceName = 'API Gateway'; +const elasticContainerServiceName = 'ElasticContainer'; const parametersFileName = 'api-params.json'; const cfnParametersFilename = 'parameters.json'; @@ -732,23 +734,6 @@ export async function migrate(context, projectPath, resourceName) { fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); } -// function checkIfAuthExists(context) { -// const { amplify } = context; -// const { amplifyMeta } = amplify.getProjectDetails(); -// let authExists = false; -// const authServiceName = 'Cognito'; -// const authCategory = 'auth'; - -// if (amplifyMeta[authCategory] && Object.keys(amplifyMeta[authCategory]).length > 0) { -// const categoryResources = amplifyMeta[authCategory]; -// Object.keys(categoryResources).forEach((resource) => { -// if (categoryResources[resource].service === authServiceName) { -// authExists = true; -// } -// }); -// } -// return authExists; -// } function convertToCRUD(privacy) { if (privacy === 'r') { privacy = ['/GET']; @@ -809,3 +794,70 @@ export function getIAMPolicies(resourceName, crudOptions) { 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; + let selectedApi = restApis[0]; + + if (restApis.length > 1) { + ({ selectedApi } = await inquirer.prompt({ + type: "list", + name: "selectedApi", + choices: restApis, + message: "Please select the API" + })); + } + 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 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 { + context.print.error('Option not available'); + return; + } + } + + open(url, { wait: false }); + } else { + context.print.error('There are no REST APIs pushed to the cloud'); + } +}; \ No newline at end of file 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 index 6646d643cb..763f410e10 100644 --- 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 @@ -22,6 +22,7 @@ import { } from 'amplify-cli-core'; const serviceName = 'AppSync'; +const elasticContainerServiceName = 'ElasticContainer'; const providerName = 'awscloudformation'; const graphqlSchemaDir = path.join(rootAssetDir, 'graphql-schemas'); @@ -47,37 +48,86 @@ const authProviderChoices = [ export const openConsole = async (context: $TSContext) => { const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; - let appSyncMeta; - Object.keys(categoryAmplifyMeta).forEach(resourceName => { - if (categoryAmplifyMeta[resourceName].service === serviceName && categoryAmplifyMeta[resourceName].output) { - appSyncMeta = categoryAmplifyMeta[resourceName].output; - } + 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 (appSyncMeta) { - const { GraphQLAPIIdOutput } = appSyncMeta; - const appId = amplifyMeta.providers[providerName].AmplifyAppId; - if (!appId) { - throw new Error('Missing AmplifyAppId in amplify-meta.json'); + 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 { Region } = amplifyMeta.providers[providerName]; - let consoleUrl = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - - const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); - const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); - if (isAdminApp) { - if (region !== Region) { - context.print.warning(`Region mismatch: Amplify service returned '${region}', but found '${Region}' in amplify-meta.json.`); + + 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).awscloudformation); + const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); + if (isAdminApp) { + if (region !== Region) { + context.print.warning(`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 { + context.print.error('Option not available'); + return; } - const { envName } = context.amplify.getEnvInfo(); - const baseUrl: string = providerPlugin.adminBackendMap[region].amplifyAdminUrl; - consoleUrl = `${baseUrl}/admin/${appId}/${envName}/datastore`; } - open(consoleUrl, { wait: false }); + + open(url, { wait: false }); } else { context.print.error('AppSync API is not pushed in the cloud.'); - } -}; + }; +} export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); 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 new file mode 100644 index 0000000000..30fbd09c86 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/containers-walkthrough.ts @@ -0,0 +1,354 @@ +import { exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; +import inquirer from 'inquirer'; +import { category } from '../../../category-constants'; +import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; +import { GitHubSourceActionInfo } from '../pipeline-with-awaiter'; + +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, defaultValuesFilename, apiType: API_TYPE): Promise> { + const { amplify } = context; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = await import(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + + const resourceName = await askResourceName(context, allDefaultValues); + + const containerInfo = await askContainerSource(context, resourceName, apiType); + + return { resourceName, ...containerInfo }; +} + +async function askResourceName(context, allDefaultValues) { + 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-zA-Z0-9]+$', + onErrorMsg: 'Resource name should be alphanumeric', + }, + required: true, + }), + }, + ]); + + return resourceName; +} + +async function askContainerSource(context, resourceName: string, apiType: API_TYPE): Promise> { + return newContainer(context, resourceName, apiType); +} + +export enum IMAGE_SOURCE_TYPE { + TEMPLATE = 'TEMPLATE', + CUSTOM = 'CUSTOM', +} + +async function newContainer(context, 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) { + context.print.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); + context.print.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, defaultValuesFilename, 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`; + context.print.error(errMessage); + 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/utils/containers-artifacts.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts new file mode 100644 index 0000000000..e636079478 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts @@ -0,0 +1,353 @@ +import { Octokit } from '@octokit/rest'; +import * as fs from 'fs-extra'; +import inquirer from 'inquirer'; +import * as path from 'path'; +import uuid from 'uuid'; +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 { JSONUtilities } from 'amplify-cli-core'; +import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; + +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: any, resource: ApiResource, askForExposedContainer: boolean = false): Promise { + const { + providers: { [cloudformationProviderName]: provider }, + } = context.amplify.getProjectMeta(); + + const { StackName: envName, DeploymentBucketName: deploymentBucketName } = 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', { + envName, + categoryName, + apiName: resourceName, + taskPorts: containersPorts, + dependsOn, + policies: categoryPolicies, + taskEnvironmentVariables: environmentMap, + gitHubSourceActionInfo: gitHubInfo, + deploymentMechanism, + deploymentBucketName, + containers, + isInitialDeploy, + desiredCount, + restrictAccess, + apiType, + exposedContainer, + secretsArns, + existingEcrRepositories, + }); + + const cfn = stack.toCloudFormation(); + + const cfnFileName = `${resourceName}-cloudformation-template.json`; + JSONUtilities.writeJson(path.normalize(path.join(resourceDir, cfnFileName)), cfn); + + return { + exposedContainer, + pipelineInfo: { consoleUrl: stack.getPipelineConsoleUrl(provider.Region) }, + }; +} + +export async function processDockerConfig(context: any, 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), + }); + + 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(), + }); + + secretsArns.set(secretName, secretArn); + } + } + + const desiredCount = service?.replicas ?? 1; // TODO: 1 should be from meta (HA setting) + + return { + containersPorts, + containers, + isInitialDeploy, + desiredCount, + exposedContainer, + secretsArns, + }; +} + +async function shouldUpdateSecrets(context: any, 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/github.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts new file mode 100644 index 0000000000..6d73ee22a3 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/github.ts @@ -0,0 +1,14 @@ +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/tsconfig.json b/packages/amplify-category-api/tsconfig.json index bbff900511..dd332b004a 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -9,6 +9,8 @@ "exclude": [ "coverage", "lib", + "resources/awscloudformation/lambdas", + "resources/awscloudformation/container-templates", "src/__tests__" ], "references": [ From d5c63e6af163f0bfa6602fedc7b02c49abb221ff Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Thu, 10 Dec 2020 02:42:24 -0800 Subject: [PATCH 376/587] fix: only ignore root src folder (#6136) --- packages/amplify-category-api/.npmignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore index 3ee5d55b0b..89eeb1ee92 100644 --- a/packages/amplify-category-api/.npmignore +++ b/packages/amplify-category-api/.npmignore @@ -1,5 +1,5 @@ **/__mocks__/** **/__tests__/** -src +./src tsconfig.json tsconfig.tsbuildinfo From 7841db2a9860d9e009cebded1e198946da1d51eb Mon Sep 17 00:00:00 2001 From: Manuel Iglesias <6154160+manueliglesias@users.noreply.github.com> Date: Thu, 10 Dec 2020 08:43:18 -0800 Subject: [PATCH 377/587] fix: containers - don't wait for pipeline on hosting (#6137) * fix: containers - don't wait for pipeline on hosting * fix: remove mkdir from Dockerfile (hosting template) * Update index.js * Update index.js --- .../src/provider-utils/awscloudformation/ecs-alb-stack.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index e6ab69b25d..acf1b119fe 100644 --- 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 @@ -21,7 +21,7 @@ export class EcsAlbStack extends ContainersStack { constructor(scope: cdk.Construct, id: string, private readonly ecsProps: EcsStackProps) { super(scope, id, { ...ecsProps, - skipWait: false, + skipWait: true, createCloudMapService: false, }); From ab8b317d9651234f9aa61c215d2f38f2bb34554c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 11 Dec 2020 03:15:06 +0000 Subject: [PATCH 378/587] chore(release): Publish [ci skip] - amplify-app@2.20.3 - amplify-category-api@2.28.0 - amplify-category-auth@2.26.0 - amplify-category-function@2.28.0 - amplify-category-storage@2.10.5 - amplify-cli-core@1.12.0 - @aws-amplify/cli@4.39.0 - amplify-codegen@2.20.1 - amplify-console-hosting@1.6.2 - amplify-console-integration-tests@1.3.7 - amplify-container-hosting@1.1.0 - amplify-dotnet-function-runtime-provider@1.4.1 - amplify-dotnet-function-template-provider@1.4.5 - amplify-dynamodb-simulator@1.17.2 - amplify-e2e-core@1.13.0 - amplify-e2e-tests@2.33.0 - amplify-frontend-ios@2.17.2 - amplify-frontend-javascript@2.20.0 - amplify-function-plugin-interface@1.6.0 - amplify-go-function-runtime-provider@1.5.2 - amplify-go-function-template-provider@1.3.2 - @aws-amplify/graphql-model-transformer@0.3.0 - @aws-amplify/graphql-transformer-core@0.3.0 - @aws-amplify/graphql-transformer-interfaces@1.3.0 - amplify-java-function-runtime-provider@1.5.2 - amplify-java-function-template-provider@1.5.2 - amplify-migration-tests@2.19.7 - amplify-nodejs-function-runtime-provider@1.4.0 - amplify-nodejs-function-template-provider@1.5.3 - amplify-provider-awscloudformation@4.35.0 - amplify-python-function-runtime-provider@1.5.2 - amplify-python-function-template-provider@1.3.2 - amplify-util-import@1.3.4 - amplify-util-mock@3.27.3 --- packages/amplify-category-api/CHANGELOG.md | 21 +++++++++++++++++++++ packages/amplify-category-api/package.json | 16 ++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index c88c0ab451..ab30912196 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f9a83f7672..76ac34838c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.27.1", + "version": "2.28.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -25,19 +25,19 @@ "@aws-cdk/aws-autoscaling-common": "~1.72.0", "@aws-cdk/aws-autoscaling-hooktargets": "~1.72.0", "@aws-cdk/aws-certificatemanager": "~1.72.0", - "@aws-cdk/aws-cloudformation":"1.72.0", + "@aws-cdk/aws-cloudformation": "1.72.0", "@aws-cdk/aws-cloudfront": "~1.72.0", "@aws-cdk/aws-cloudwatch": "~1.72.0", - "@aws-cdk/aws-codebuild":"~1.72.0", - "@aws-cdk/aws-codeguruprofiler":"1.72.0", - "@aws-cdk/aws-codepipeline":"~1.72.0", - "@aws-cdk/aws-codepipeline-actions":"~1.72.0", + "@aws-cdk/aws-codebuild": "~1.72.0", + "@aws-cdk/aws-codeguruprofiler": "1.72.0", + "@aws-cdk/aws-codepipeline": "~1.72.0", + "@aws-cdk/aws-codepipeline-actions": "~1.72.0", "@aws-cdk/aws-cognito": "~1.72.0", "@aws-cdk/aws-ec2": "~1.72.0", "@aws-cdk/aws-ecr": "~1.72.0", "@aws-cdk/aws-ecr-assets": "~1.72.0", "@aws-cdk/aws-ecs": "~1.72.0", - "@aws-cdk/aws-efs":"1.72.0", + "@aws-cdk/aws-efs": "1.72.0", "@aws-cdk/aws-elasticloadbalancing": "~1.72.0", "@aws-cdk/aws-elasticloadbalancingv2": "~1.72.0", "@aws-cdk/aws-events": "~1.72.0", @@ -49,7 +49,7 @@ "@aws-cdk/aws-route53-targets": "~1.72.0", "@aws-cdk/aws-s3": "~1.72.0", "@aws-cdk/aws-s3-assets": "~1.72.0", - "@aws-cdk/aws-sam":"1.72.0", + "@aws-cdk/aws-sam": "1.72.0", "@aws-cdk/aws-secretsmanager": "~1.72.0", "@aws-cdk/aws-servicediscovery": "~1.72.0", "@aws-cdk/aws-sns": "~1.72.0", From 74e04756249f61ffb135a9895deae1d0999db096 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Fri, 11 Dec 2020 11:36:13 -0800 Subject: [PATCH 379/587] fix: #6123 - add missing amplify-cli-core dependencies to packages (#6124) --- packages/amplify-category-api/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 76ac34838c..0c38a9245f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -62,6 +62,7 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", + "amplify-cli-core": "1.11.0", "amplify-util-headless-input": "1.4.2", "chalk": "^3.0.0", "constructs": "^3.2.0", From 53e013dc9122bd4d9b28fe9c10607cc9c06c0941 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 16 Dec 2020 00:58:41 +0000 Subject: [PATCH 380/587] chore(release): Publish [ci skip] - amplify-app@2.20.4 - amplify-appsync-simulator@1.24.3 - amplify-category-analytics@2.19.3 - amplify-category-api@2.28.1 - amplify-category-auth@2.26.1 - amplify-category-function@2.28.1 - amplify-category-storage@2.10.6 - amplify-cli-core@1.13.0 - @aws-amplify/cli@4.40.0 - amplify-codegen-appsync-model-plugin@1.22.2 - amplify-codegen@2.20.2 - amplify-console-hosting@1.6.3 - amplify-console-integration-tests@1.3.8 - amplify-container-hosting@1.1.1 - amplify-dotnet-function-template-provider@1.4.6 - amplify-dynamodb-simulator@1.17.3 - amplify-e2e-core@1.13.1 - amplify-e2e-tests@2.33.1 - amplify-frontend-ios@2.18.0 - amplify-frontend-javascript@2.20.1 - amplify-go-function-runtime-provider@1.5.3 - amplify-java-function-runtime-provider@1.5.3 - amplify-migration-tests@2.19.8 - amplify-nodejs-function-runtime-provider@1.4.1 - amplify-nodejs-function-template-provider@1.5.4 - amplify-provider-awscloudformation@4.35.1 - amplify-python-function-runtime-provider@1.5.3 - amplify-util-import@1.3.5 - amplify-util-mock@3.27.4 - graphql-auth-transformer@6.23.2 - graphql-connection-transformer@4.19.4 - graphql-dynamodb-transformer@6.21.4 - graphql-elasticsearch-transformer@4.9.4 - graphql-function-transformer@2.4.4 - graphql-http-transformer@4.16.4 - graphql-key-transformer@2.20.4 - graphql-predictions-transformer@2.4.4 - graphql-transformer-core@6.25.1 - graphql-transformers-e2e-tests@6.21.2 - graphql-versioned-transformer@4.16.4 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ab30912196..02ecd0b49d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0c38a9245f..47ad6613e1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.28.0", + "version": "2.28.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -69,7 +69,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.1", - "graphql-transformer-core": "6.25.0", + "graphql-transformer-core": "6.25.1", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From e8fa89eaa2234c3e8b7264c1f042e1b540d3f9b7 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Tue, 5 Jan 2021 12:09:56 -0800 Subject: [PATCH 381/587] chore: dependency updates (#6316) --- .../dockercompose-rest-express/express/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index bff7030c33..bad38cf5e9 100644 --- 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 @@ -9,7 +9,7 @@ "license": "ISC", "dependencies": { "aws-sdk": "^2.792.0", - "axios": "^0.16.2", + "axios": "^0.21.1", "body-parser": "^1.19.0", "express": "^4.17.1", "redis": "^3.0.2" From 536e8b0706fe4f4b8c66ffa69e5cec2bb4aea483 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 7 Jan 2021 11:59:39 -0800 Subject: [PATCH 382/587] fix: remove process on next and await (#6239) --- .../provider-utils/awscloudformation/index.ts | 41 ++++++----- .../service-walkthroughs/apigw-walkthrough.ts | 64 +++++++++-------- .../appSync-rds-walkthrough.js | 10 +-- .../appSync-walkthrough.ts | 68 ++++++++++--------- .../containers-walkthrough.ts | 13 ++-- 5 files changed, 105 insertions(+), 91 deletions(-) diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index da273c0857..556d3dd76c 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -8,7 +8,11 @@ import { editSchemaFlow } from './utils/edit-schema-flow'; import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; import inquirer from 'inquirer'; -import { API_TYPE, ServiceConfiguration, getPermissionPolicies as getContainerPermissionPolicies } from './service-walkthroughs/containers-walkthrough'; +import { + API_TYPE, + ServiceConfiguration, + getPermissionPolicies as getContainerPermissionPolicies, +} from './service-walkthroughs/containers-walkthrough'; import { category } from '../../category-constants'; export async function console(context, service) { @@ -19,7 +23,7 @@ export async function console(context, service) { if (!openConsole) { const errMessage = 'Opening console functionality not available for this option'; context.print.error(errMessage); - context.usageData.emitError(new NotImplementedError(errMessage)); + await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -139,7 +143,7 @@ export async function updateResource(context, category, service, options) { hasAPIGatewayContainerResource, hasAPIGatewayLambdaResource, hasGraphQLAppSyncResource, - hasGraphqlContainerResource + hasGraphqlContainerResource, } = await describeApiResourcesBySubCategory(context); switch (service) { @@ -157,7 +161,7 @@ export async function updateResource(context, category, service, options) { if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { useContainerResource = await isRestContainer(context); } else if (hasAPIGatewayContainerResource) { - useContainerResource = true + useContainerResource = true; } else { useContainerResource = false; } @@ -174,13 +178,8 @@ export async function updateResource(context, category, service, options) { } async function describeApiResourcesBySubCategory(context) { - const { allResources } = await context.amplify.getResourceStatus(); - const resources = allResources - .filter(resource => - resource.category === category && - resource.mobileHubMigrated !== true - ); + const resources = allResources.filter(resource => resource.category === category && resource.mobileHubMigrated !== true); let hasAPIGatewayContainerResource = false; let hasAPIGatewayLambdaResource = false; @@ -188,24 +187,22 @@ async function describeApiResourcesBySubCategory(context) { let hasGraphqlContainerResource = false; resources.forEach(resource => { - hasAPIGatewayContainerResource = hasAPIGatewayContainerResource || - (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); + hasAPIGatewayContainerResource = + hasAPIGatewayContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); - hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || - resource.service === 'API Gateway'; + hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === 'API Gateway'; - hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || - resource.service === 'AppSync'; + hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === 'AppSync'; - hasGraphqlContainerResource = hasGraphqlContainerResource || - (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); - }) + hasGraphqlContainerResource = + hasGraphqlContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); + }); return { hasAPIGatewayLambdaResource, hasAPIGatewayContainerResource, hasGraphQLAppSyncResource, - hasGraphqlContainerResource + hasGraphqlContainerResource, }; } @@ -218,7 +215,7 @@ async function updateContainerResource(context, category, service, apiType: API_ if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; context.print.error(errMessage); - context.usageData.emitError(new NotImplementedError(errMessage)); + await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -236,7 +233,7 @@ async function updateNonContainerResource(context, category, service) { if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; context.print.error(errMessage); - context.usageData.emitError(new NotImplementedError(errMessage)); + await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } 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 index 9695322aea..9688332d98 100644 --- 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 @@ -47,7 +47,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { if (resources.length === 0) { const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; } @@ -80,7 +80,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { if (updateApi.resourceName === 'AdminQueries') { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; context.print.warning(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -802,9 +802,10 @@ export const openConsole = async (context: $TSContext) => { const restApis = Object.keys(categoryAmplifyMeta).filter(resourceName => { const resource = categoryAmplifyMeta[resourceName]; - return resource.output && - (resource.service === serviceName || - (resource.service === elasticContainerServiceName && resource.apiType === 'REST')) + return ( + resource.output && + (resource.service === serviceName || (resource.service === elasticContainerServiceName && resource.apiType === 'REST')) + ); }); if (restApis) { @@ -813,43 +814,48 @@ export const openConsole = async (context: $TSContext) => { if (restApis.length > 1) { ({ selectedApi } = await inquirer.prompt({ - type: "list", - name: "selectedApi", + type: 'list', + name: 'selectedApi', choices: restApis, - message: "Please select the API" + message: 'Please select the API', })); } const selectedResource = categoryAmplifyMeta[selectedApi]; if (selectedResource.service === serviceName) { - const { output: { ApiId } } = selectedResource; + 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" + } 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 - }] + 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` - + 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` - + url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; } else { context.print.error('Option not available'); return; @@ -860,4 +866,4 @@ export const openConsole = async (context: $TSContext) => { } else { context.print.error('There are no REST APIs pushed to the cloud'); } -}; \ No newline at end of file +}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 4068c270b3..0235550962 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -15,7 +15,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 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.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -35,7 +35,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta 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.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -97,7 +97,7 @@ async function selectCluster(context, inputs, AWS) { } const errMessage = 'No properly configured Aurora Serverless clusters found.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -149,7 +149,7 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { } else { const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); + await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); exitOnNextTick(0); } } @@ -194,7 +194,7 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { const errMessage = 'No properly configured databases found.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } 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 index 763f410e10..36fa772a11 100644 --- 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 @@ -53,9 +53,10 @@ export const openConsole = async (context: $TSContext) => { const graphQLApis = Object.keys(categoryAmplifyMeta).filter(resourceName => { const resource = categoryAmplifyMeta[resourceName]; - return resource.output && - (resource.service === serviceName || - (resource.service === elasticContainerServiceName && resource.apiType === 'GRAPHQL')) + return ( + resource.output && + (resource.service === serviceName || (resource.service === elasticContainerServiceName && resource.apiType === 'GRAPHQL')) + ); }); if (graphQLApis) { @@ -64,17 +65,19 @@ export const openConsole = async (context: $TSContext) => { if (graphQLApis.length > 1) { ({ selectedApi } = await inquirer.prompt({ - type: "list", - name: "selectedApi", + type: 'list', + name: 'selectedApi', choices: graphQLApis, - message: "Please select the API" + message: 'Please select the API', })); } const selectedResource = categoryAmplifyMeta[selectedApi]; if (selectedResource.service === serviceName) { - const { output: { GraphQLAPIIdOutput } } = selectedResource; + const { + output: { GraphQLAPIIdOutput }, + } = selectedResource; const appId = amplifyMeta.providers[providerName].AmplifyAppId; if (!appId) { throw new Error('Missing AmplifyAppId in amplify-meta.json'); @@ -92,31 +95,34 @@ export const openConsole = async (context: $TSContext) => { 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" + } 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 - }] + 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` - + 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` - + url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; } else { context.print.error('Option not available'); return; @@ -126,8 +132,8 @@ export const openConsole = async (context: $TSContext) => { open(url, { wait: false }); } else { context.print.error('AppSync API is not pushed in the cloud.'); - }; -} + } +}; export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); @@ -139,7 +145,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const errMessage = 'You already have an AppSync API in your project. Use the "amplify update api" command to update your existing AppSync API.'; context.print.warning(errMessage); - context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); + await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); exitOnNextTick(0); } @@ -250,7 +256,7 @@ export const updateWalkthrough = async (context): Promise => { } else { const errMessage = 'No AppSync resource to update. Use the "amplify add api" command to update your existing AppSync API.'; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -569,7 +575,7 @@ async function askAuthQuestions(authType, context, printLeadText = false) { const errMessage = `Unknown authType: ${authType}`; context.print.error(errMessage); - context.usageData.emitError(new UnknownResourceTypeError(errMessage)); + await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); exitOnNextTick(1); } 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 index 30fbd09c86..199ff52e30 100644 --- 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 @@ -172,7 +172,9 @@ async function newContainer(context, resourceName: string, apiType: API_TYPE): P if (deploymentMechanismQuestion.deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { context.print.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); - context.print.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'); + context.print.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([ { @@ -236,14 +238,17 @@ export async function updateWalkthrough(context, defaultValuesFilename, apiType: const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources - .filter(resource => resource.category === category && resource.service === serviceName && !!resource.providerPlugin && resource.apiType === apiType) + .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`; context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; } @@ -350,5 +355,5 @@ async function confirm(question: string) { } export async function getPermissionPolicies(context, service, resourceName, crudOptions) { - throw new Error('IAM access not available for this resource') + throw new Error('IAM access not available for this resource'); } From c68073fb35fbc0839c324f82dbc88c1a58b953e4 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Thu, 7 Jan 2021 17:28:20 -0800 Subject: [PATCH 383/587] chore: update jest to 26, fix test build errors (#6339) * chore: update jest to 26, fix test build errors * chore: update tests to pass with jest 26 --- .../utils/containers-artifacts.ts | 45 ++++++++----------- 1 file changed, 18 insertions(+), 27 deletions(-) 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 index e636079478..1aba546cae 100644 --- 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 @@ -41,7 +41,11 @@ type ContainerArtifactsMetadata = { pipelineInfo: { consoleUrl: string }; }; -export async function generateContainersArtifacts(context: any, resource: ApiResource, askForExposedContainer: boolean = false): Promise { +export async function generateContainersArtifacts( + context: any, + resource: ApiResource, + askForExposedContainer: boolean = false, +): Promise { const { providers: { [cloudformationProviderName]: provider }, } = context.amplify.getProjectMeta(); @@ -60,26 +64,23 @@ export async function generateContainersArtifacts(context: any, resource: ApiRes 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 { 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}-`)) + repositories + .map(({ repositoryName }) => repositoryName) + .filter(repositoryName => repositoryName.startsWith(`${envName}-${categoryName}-${resourceName}-`)), ); const stack = new EcsStack(undefined, 'ContainersStack', { @@ -121,13 +122,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s const { StackName: envName } = provider; - const { - resourceName, - gitHubInfo, - deploymentMechanism, - output, - exposedContainer: exposedContainerFromMeta, - } = resource; + const { resourceName, gitHubInfo, deploymentMechanism, output, exposedContainer: exposedContainerFromMeta } = resource; const dockerComposeFileNameYaml = 'docker-compose.yaml'; const dockerComposeFileNameYml = 'docker-compose.yml'; @@ -168,7 +163,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s path: path.join(pathInRepo, fileName), }); - containerDefinitionFiles[fileName] = Buffer.from(content, encoding).toString('utf8'); + containerDefinitionFiles[fileName] = Buffer.from(content, encoding).toString('utf8'); } catch (error) { const { status } = error; @@ -199,9 +194,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s const { buildspec, containers, service, secrets } = getContainers(composeContents, dockerfileContents); const containersPorts = containers.reduce( - (acc, container) => acc.concat( - container.portMappings.map(({ containerPort }) => containerPort), - ), + (acc, container) => acc.concat(container.portMappings.map(({ containerPort }) => containerPort)), [], ); @@ -210,8 +203,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s 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)); + isInitialDeploy = isInitialDeploy || newContainersName.some(newContainer => !currentContainersSet.has(newContainer)); let exposedContainer: { name: string; port: number }; @@ -350,4 +342,3 @@ async function checkContainerExposed( }; } } - From 4a965d8a7006641468635b82a98d5fb0ad8a7669 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 8 Jan 2021 22:24:04 +0000 Subject: [PATCH 384/587] chore(release): Publish [ci skip] - amplify-app@2.20.7 - amplify-appsync-simulator@1.25.0 - amplify-category-analytics@2.19.4 - amplify-category-api@2.28.2 - amplify-category-auth@2.26.4 - amplify-category-function@2.28.4 - amplify-category-notifications@2.17.2 - amplify-category-predictions@2.6.2 - amplify-category-storage@2.10.9 - amplify-cli-core@1.14.1 - @aws-amplify/cli@4.41.1 - amplify-codegen@2.20.5 - amplify-console-hosting@1.6.6 - amplify-console-integration-tests@1.3.11 - amplify-container-hosting@1.1.2 - amplify-dotnet-function-template-provider@1.4.9 - amplify-dynamodb-simulator@1.17.6 - amplify-e2e-core@1.13.4 - amplify-e2e-tests@2.33.4 - amplify-frontend-android@2.14.3 - amplify-frontend-flutter@0.2.1 - amplify-frontend-ios@2.18.3 - amplify-frontend-javascript@2.20.4 - amplify-go-function-runtime-provider@1.5.6 - amplify-headless-interface@1.5.3 - amplify-java-function-runtime-provider@1.5.6 - amplify-migration-tests@2.19.11 - amplify-nodejs-function-template-provider@1.5.7 - amplify-provider-awscloudformation@4.36.1 - amplify-python-function-runtime-provider@1.5.6 - amplify-util-headless-input@1.4.3 - amplify-util-import@1.3.8 - amplify-util-mock@3.27.7 - graphql-auth-transformer@6.23.3 - graphql-elasticsearch-transformer@4.10.0 - graphql-transformers-e2e-tests@6.21.3 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 02ecd0b49d..0e4c8034aa 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 47ad6613e1..eec6735795 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.28.1", + "version": "2.28.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,7 +63,7 @@ "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", "amplify-cli-core": "1.11.0", - "amplify-util-headless-input": "1.4.2", + "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", From f48a32d25544bd05944be7e5bd568037818708bd Mon Sep 17 00:00:00 2001 From: Ross Ragsdale Date: Thu, 14 Jan 2021 14:21:50 -0600 Subject: [PATCH 385/587] fix: fix appsync permission assignment from functions (#5342) * fix(amplify-category-function): update function to graphql permissions --- .../appSync-walkthrough.ts | 65 +++++++------------ 1 file changed, 25 insertions(+), 40 deletions(-) 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 index 36fa772a11..b43b927ef6 100644 --- 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 @@ -721,50 +721,16 @@ export const migrate = async context => { }); }; -export const getIAMPolicies = (resourceName, crudOptions, context) => { +export const getIAMPolicies = (resourceName, operations, context) => { let policy = {}; - const actions = []; - - crudOptions.forEach(crudOption => { - switch (crudOption) { - case 'create': - actions.push('appsync:Create*', 'appsync:StartSchemaCreation', 'appsync:GraphQL'); - 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: - console.log(`${crudOption} not supported`); - } - }); + const resources = []; + + operations.forEach(operation => resources.push(buildPolicyResource(resourceName, operation))); policy = { Effect: 'Allow', - Action: actions, - Resource: [ - { - 'Fn::Join': [ - '', - [ - 'arn:aws:appsync:', - { Ref: 'AWS::Region' }, - ':', - { Ref: 'AWS::AccountId' }, - ':apis/', - { - Ref: `${category}${resourceName}GraphQLAPIIdOutput`, - }, - '/*', - ], - ], - }, - ], + Action: ['appsync:GraphQL'], + Resource: resources, }; const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; @@ -775,6 +741,25 @@ export const getIAMPolicies = (resourceName, crudOptions, context) => { return { policy, attributes }; }; +const buildPolicyResource = (resourceName, operation) => { + return { + 'Fn::Join': [ + '', + [ + 'arn:aws:appsync:', + { Ref: 'AWS::Region' }, + ':', + { Ref: 'AWS::AccountId' }, + ':apis/', + { + Ref: `${category}${resourceName}GraphQLAPIIdOutput`, + }, + `/types/${operation}/*`, + ], + ], + }; +}; + const templateSchemaFilter = authConfig => { const authIncludesCognito = getAuthTypes(authConfig).includes('AMAZON_COGNITO_USER_POOLS'); return (templateOption: ListChoiceOptions): boolean => From f0a08f31fb7041bf199757d7fe54b6f69b1d965a Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 21 Jan 2021 14:09:46 -0800 Subject: [PATCH 386/587] chore: update internal dependencies to latest versions (#6442) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index eec6735795..2147bfe137 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -62,7 +62,7 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.11.0", + "amplify-cli-core": "1.14.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", From 3aec1a269c89c2e85ce64761d2ab330daa52c705 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 10 Feb 2021 00:30:54 +0000 Subject: [PATCH 387/587] chore(release): Publish [ci skip] - amplify-app@2.21.0 - amplify-appsync-simulator@1.25.1 - amplify-category-analytics@2.19.5 - amplify-category-api@2.28.3 - amplify-category-auth@2.27.0 - amplify-category-function@2.28.5 - amplify-category-storage@2.10.10 - amplify-cli-core@1.15.0 - @aws-amplify/cli@4.42.0 - amplify-codegen@2.21.0 - amplify-console-hosting@1.6.7 - amplify-console-integration-tests@1.3.12 - amplify-container-hosting@1.1.3 - amplify-dotnet-function-template-provider@1.4.10 - amplify-dynamodb-simulator@1.17.7 - amplify-e2e-core@1.14.0 - amplify-e2e-tests@2.34.0 - amplify-frontend-android@2.14.5 - amplify-frontend-flutter@0.3.0 - amplify-frontend-ios@2.18.5 - amplify-frontend-javascript@2.20.5 - amplify-go-function-runtime-provider@1.5.7 - @aws-amplify/graphql-model-transformer@0.3.1 - @aws-amplify/graphql-transformer-core@0.3.1 - amplify-graphql-types-generator@2.7.0 - amplify-java-function-runtime-provider@1.5.7 - amplify-migration-tests@2.20.0 - amplify-nodejs-function-runtime-provider@1.4.3 - amplify-nodejs-function-template-provider@1.5.8 - amplify-provider-awscloudformation@4.37.0 - amplify-python-function-runtime-provider@1.5.7 - amplify-python-function-template-provider@1.3.3 - amplify-ui-tests@2.14.2 - amplify-util-import@1.3.9 - amplify-util-mock@3.27.8 - amplify-velocity-template@1.4.3 - graphql-auth-transformer@6.23.4 - graphql-connection-transformer@4.20.0 - graphql-dynamodb-transformer@6.21.5 - graphql-elasticsearch-transformer@4.10.1 - graphql-function-transformer@2.4.5 - graphql-http-transformer@4.16.5 - graphql-key-transformer@2.21.0 - graphql-predictions-transformer@2.4.5 - graphql-transformer-core@6.26.0 - graphql-transformers-e2e-tests@6.22.0 - graphql-versioned-transformer@4.16.5 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 0e4c8034aa..9eb37987e8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 2147bfe137..b083cc61a5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.28.2", + "version": "2.28.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.14.1", + "amplify-cli-core": "1.15.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.1", - "graphql-transformer-core": "6.25.1", + "graphql-transformer-core": "6.26.0", "inquirer": "^7.3.3", "open": "^7.0.0", "ora": "^4.0.3", From 722c6809158ea43ac40c73bd7b069e3d303f145a Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Tue, 9 Feb 2021 17:22:05 -0800 Subject: [PATCH 388/587] feat: dont open urls when CLI is running in CI (#6503) Updated the CLI not to open browser window when running in CI mode re #5973 --- packages/amplify-category-api/package.json | 1 - .../service-walkthroughs/apigw-walkthrough.ts | 3 +-- .../service-walkthroughs/appSync-walkthrough.ts | 2 +- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b083cc61a5..3f7e0f416e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -71,7 +71,6 @@ "graphql-relational-schema-transformer": "2.16.1", "graphql-transformer-core": "6.26.0", "inquirer": "^7.3.3", - "open": "^7.0.0", "ora": "^4.0.3", "uuid": "^3.4.0" }, 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 index 9688332d98..cfaddf7b33 100644 --- 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 @@ -3,10 +3,9 @@ import path from 'path'; import fs from 'fs-extra'; import os from 'os'; import uuid from 'uuid'; -import open from 'open'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; -import { ResourceDoesNotExistError, exitOnNextTick, $TSContext, stateManager } from 'amplify-cli-core'; +import { ResourceDoesNotExistError, exitOnNextTick, $TSContext, stateManager, open } from 'amplify-cli-core'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; 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 index b43b927ef6..9a36030b3f 100644 --- 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 @@ -3,7 +3,6 @@ import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; import inquirer from 'inquirer'; import fs from 'fs-extra'; import path from 'path'; -import open from 'open'; import { rootAssetDir } from '../aws-constants'; import { collectDirectivesByTypeNames, readProjectConfiguration, ConflictHandlerType } from 'graphql-transformer-core'; import { category } from '../../../category-constants'; @@ -19,6 +18,7 @@ import { exitOnNextTick, stateManager, $TSContext, + open, } from 'amplify-cli-core'; const serviceName = 'AppSync'; From 14a1ed7165ccf72c773b16a19458cfdc081e4b8e Mon Sep 17 00:00:00 2001 From: Akshay Date: Fri, 29 Jan 2021 15:51:01 -0800 Subject: [PATCH 389/587] fix: sets policy resource name in api update flow --- .../legacy-update-resource.test.ts.snap | 17 ++++++++++ .../legacy-update-resource.test.ts | 34 +++++++++++++++++++ .../awscloudformation/legacy-add-resource.ts | 2 +- .../legacy-update-resource.ts | 11 +++--- 4 files changed, 58 insertions(+), 6 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts 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 new file mode 100644 index 0000000000..f44b0a4e9b --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/__snapshots__/legacy-update-resource.test.ts.snap @@ -0,0 +1,17 @@ +// 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/legacy-update-resource.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts new file mode 100644 index 0000000000..135f62250f --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/legacy-update-resource.test.ts @@ -0,0 +1,34 @@ +import { legacyUpdateResource } from '../../../provider-utils/awscloudformation/legacy-update-resource'; +import { category } from '../../../category-constants'; + +jest.mock('fs-extra'); + +describe('legacy update resource', () => { + const contextStub = { + amplify: { + pathManager: { + getBackendDirPath: jest.fn(_ => 'mock/backend/path'), + }, + 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, category, 'API Gateway'); + expect(contextStub.amplify.copyBatch.mock.calls[0][2]).toMatchSnapshot(); + }); +}); 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 index 3e9769b193..211ea1c1fb 100644 --- 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 @@ -69,7 +69,7 @@ export const copyCfnTemplate = (context, category, options, cfnFilename) => { return context.amplify.copyBatch(context, copyJobs, options, true, false); }; -const addPolicyResourceNameToPaths = paths => { +export const addPolicyResourceNameToPaths = paths => { if (Array.isArray(paths)) { paths.forEach(p => { const pathName = p.name; 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 index 2a08cbfa61..99a15a9365 100644 --- 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 @@ -1,14 +1,14 @@ -import { serviceMetadataFor } from "./utils/dynamic-imports"; -import { copyCfnTemplate } from "./legacy-add-resource"; +import { serviceMetadataFor } from './utils/dynamic-imports'; +import { copyCfnTemplate, addPolicyResourceNameToPaths } from './legacy-add-resource'; import fs from 'fs-extra'; import path from 'path'; -import { parametersFileName } from "./aws-constants"; +import { parametersFileName } from './aws-constants'; export const legacyUpdateResource = async (updateWalkthroughPromise: Promise, context, category, service) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - const result = await updateWalkthroughPromise + const result = await updateWalkthroughPromise; const options: any = {}; if (result) { if (result.answers) { @@ -22,6 +22,7 @@ export const legacyUpdateResource = async (updateWalkthroughPromise: Promise Date: Thu, 11 Feb 2021 23:32:54 +0000 Subject: [PATCH 390/587] chore(release): Publish [ci skip] - amplify-app@2.21.1 - amplify-appsync-simulator@1.25.2 - amplify-category-analytics@2.20.0 - amplify-category-api@2.29.0 - amplify-category-auth@2.28.0 - amplify-category-function@2.29.0 - amplify-category-hosting@2.6.0 - amplify-category-notifications@2.18.0 - amplify-category-predictions@2.7.0 - amplify-category-storage@2.10.11 - amplify-category-xr@2.7.0 - amplify-cli-core@1.16.0 - @aws-amplify/cli@4.43.0 - amplify-codegen@2.21.1 - amplify-console-hosting@1.7.0 - amplify-console-integration-tests@1.3.13 - amplify-container-hosting@1.2.0 - amplify-dotnet-function-template-provider@1.4.11 - amplify-dynamodb-simulator@1.17.8 - amplify-e2e-core@1.14.1 - amplify-e2e-tests@2.34.1 - amplify-frontend-ios@2.18.6 - amplify-frontend-javascript@2.20.6 - amplify-go-function-runtime-provider@1.5.8 - amplify-graphiql-explorer@1.4.2 - @aws-amplify/graphql-model-transformer@0.3.2 - @aws-amplify/graphql-transformer-core@0.3.2 - @aws-amplify/graphql-transformer-interfaces@1.3.1 - amplify-java-function-runtime-provider@1.5.8 - amplify-migration-tests@2.20.1 - amplify-nodejs-function-template-provider@1.5.9 - amplify-provider-awscloudformation@4.38.0 - amplify-python-function-runtime-provider@1.5.8 - amplify-ui-tests@2.14.3 - amplify-util-import@1.3.10 - amplify-util-mock@3.27.9 - graphql-auth-transformer@6.23.5 - graphql-connection-transformer@4.20.1 - graphql-dynamodb-transformer@6.21.6 - graphql-elasticsearch-transformer@4.10.2 - graphql-function-transformer@2.4.6 - graphql-http-transformer@4.16.6 - graphql-key-transformer@2.21.1 - graphql-predictions-transformer@2.4.6 - graphql-relational-schema-transformer@2.16.2 - graphql-transformer-common@4.18.2 - graphql-transformer-core@6.26.1 - graphql-transformers-e2e-tests@6.22.1 - graphql-versioned-transformer@4.16.6 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9eb37987e8..3e48462c49 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3f7e0f416e..fe0724ba32 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.28.3", + "version": "2.29.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.15.0", + "amplify-cli-core": "1.16.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.1", - "graphql-transformer-core": "6.26.0", + "graphql-relational-schema-transformer": "2.16.2", + "graphql-transformer-core": "6.26.1", "inquirer": "^7.3.3", "ora": "^4.0.3", "uuid": "^3.4.0" From 7f02d287820bc743d0929370c63ad96ff388548f Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 17 Feb 2021 03:55:09 +0000 Subject: [PATCH 391/587] chore(release): Publish [ci skip] - amplify-app@2.21.2 - amplify-category-analytics@2.20.1 - amplify-category-api@2.29.1 - amplify-category-auth@2.28.1 - amplify-category-function@2.30.0 - amplify-category-hosting@2.6.1 - amplify-category-predictions@2.7.1 - amplify-category-storage@2.10.12 - amplify-category-xr@2.7.1 - amplify-cli-core@1.17.0 - @aws-amplify/cli@4.44.0 - amplify-codegen@2.21.2 - amplify-console-hosting@1.7.1 - amplify-console-integration-tests@1.3.14 - amplify-container-hosting@1.2.1 - amplify-dotnet-function-runtime-provider@1.5.0 - amplify-dotnet-function-template-provider@1.4.12 - amplify-dynamodb-simulator@1.17.9 - amplify-e2e-core@1.15.0 - amplify-e2e-tests@2.34.2 - amplify-frontend-ios@2.18.7 - amplify-frontend-javascript@2.20.7 - amplify-function-plugin-interface@1.7.0 - amplify-go-function-runtime-provider@1.6.0 - amplify-go-function-template-provider@1.3.3 - amplify-java-function-runtime-provider@1.6.0 - amplify-java-function-template-provider@1.5.3 - amplify-migration-tests@2.20.2 - amplify-nodejs-function-runtime-provider@1.5.0 - amplify-nodejs-function-template-provider@1.5.10 - amplify-provider-awscloudformation@4.39.0 - amplify-python-function-runtime-provider@1.6.0 - amplify-python-function-template-provider@1.3.4 - amplify-util-import@1.3.11 - amplify-util-mock@3.28.0 - graphql-auth-transformer@6.23.6 - graphql-connection-transformer@4.20.2 - graphql-dynamodb-transformer@6.21.7 - graphql-elasticsearch-transformer@4.10.3 - graphql-function-transformer@2.4.7 - graphql-http-transformer@4.16.7 - graphql-key-transformer@2.21.2 - graphql-predictions-transformer@2.4.7 - graphql-transformer-core@6.26.2 - graphql-transformers-e2e-tests@6.22.2 - graphql-versioned-transformer@4.16.7 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 3e48462c49..5e59f1dcca 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index fe0724ba32..64471e3661 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.0", + "version": "2.29.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.16.0", + "amplify-cli-core": "1.17.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.2", - "graphql-transformer-core": "6.26.1", + "graphql-transformer-core": "6.26.2", "inquirer": "^7.3.3", "ora": "^4.0.3", "uuid": "^3.4.0" From a4ce06b9b2a81b33eafde9753f7317be8e090aa5 Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Wed, 17 Feb 2021 10:00:02 -0800 Subject: [PATCH 392/587] chore: update aws-sdk version (#6644) --- .../dockercompose-rest-express/express/package.json | 2 +- .../container-templates/dockerfile-rest-express/package.json | 2 +- .../container-templates/graphql-express/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index bad38cf5e9..7beb4e19d3 100644 --- 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 @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.792.0", + "aws-sdk": "^2.845.0", "axios": "^0.21.1", "body-parser": "^1.19.0", "express": "^4.17.1", 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 index 7df3fe7aae..9c72bb598f 100644 --- 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 @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.792.0", + "aws-sdk": "^2.845.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 index 964344a7e9..ee61e94075 100644 --- 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 @@ -7,7 +7,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.790.0", + "aws-sdk": "^2.845.0", "express": "^4.17.1", "express-graphql": "^0.11.0", "graphql": "^15.4.0" From f166e7504337f0f1b238ed54fe4064fa1bac5c7b Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 24 Feb 2021 20:37:17 +0000 Subject: [PATCH 393/587] chore(release): Publish [ci skip] - amplify-app@2.21.3 - amplify-appsync-simulator@1.25.3 - amplify-category-analytics@2.20.2 - amplify-category-api@2.29.2 - amplify-category-auth@2.28.2 - amplify-category-function@2.30.1 - amplify-category-hosting@2.6.2 - amplify-category-predictions@2.7.2 - amplify-category-storage@2.10.13 - amplify-category-xr@2.7.2 - amplify-cli-core@1.17.1 - @aws-amplify/cli@4.44.1 - amplify-codegen@2.21.3 - amplify-console-hosting@1.7.2 - amplify-console-integration-tests@1.3.15 - amplify-container-hosting@1.2.2 - amplify-dotnet-function-template-provider@1.4.13 - amplify-dynamodb-simulator@1.17.10 - amplify-e2e-core@1.15.1 - amplify-e2e-tests@2.34.3 - amplify-frontend-ios@2.18.8 - amplify-frontend-javascript@2.20.8 - amplify-function-plugin-interface@1.7.1 - amplify-go-function-runtime-provider@1.6.1 - amplify-java-function-runtime-provider@1.6.1 - amplify-migration-tests@2.20.3 - amplify-nodejs-function-template-provider@1.5.11 - amplify-provider-awscloudformation@4.39.1 - amplify-python-function-runtime-provider@1.6.1 - amplify-storage-simulator@1.5.2 - amplify-util-import@1.3.12 - amplify-util-mock@3.28.1 - graphql-auth-transformer@6.23.7 - graphql-connection-transformer@4.20.3 - graphql-dynamodb-transformer@6.21.8 - graphql-elasticsearch-transformer@4.10.4 - graphql-function-transformer@2.4.8 - graphql-http-transformer@4.16.8 - graphql-key-transformer@2.21.3 - graphql-predictions-transformer@2.4.8 - graphql-relational-schema-transformer@2.16.3 - graphql-transformer-core@6.26.3 - graphql-transformers-e2e-tests@6.22.3 - graphql-versioned-transformer@4.16.8 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5e59f1dcca..bc3c3bbc53 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 64471e3661..3aa43baa9e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.1", + "version": "2.29.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.17.0", + "amplify-cli-core": "1.17.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.2", - "graphql-transformer-core": "6.26.2", + "graphql-relational-schema-transformer": "2.16.3", + "graphql-transformer-core": "6.26.3", "inquirer": "^7.3.3", "ora": "^4.0.3", "uuid": "^3.4.0" From e025026cb1adb7d97a29396f6e938dc6b1448afc Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Wed, 24 Feb 2021 15:21:48 -0800 Subject: [PATCH 394/587] build: update package versions (#6731) --- .../utils/service-walkthrough-result-to-add-api-request.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 519935b7a0..0a742a6c62 100644 --- 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 @@ -1,5 +1,5 @@ import { serviceWalkthroughResultToAddApiRequest } from '../../../../provider-utils/awscloudformation/utils/service-walkthrough-result-to-add-api-request'; -import { AppSyncAuthType, ConflictResolution } from 'amplify-headless-interface/src'; +import { AppSyncAuthType, ConflictResolution } from 'amplify-headless-interface'; jest.mock('../../../../provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper', () => ({ authConfigToAppSyncAuthType: jest.fn((): AppSyncAuthType => ({ mode: 'AWS_IAM' })), From fb0687628e610652b7c7a9c970e4536482fa6b90 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 26 Feb 2021 23:01:18 +0000 Subject: [PATCH 395/587] chore(release): Publish [ci skip] - amplify-app@2.21.4 - amplify-category-analytics@2.20.3 - amplify-category-api@2.29.3 - amplify-category-auth@2.28.3 - amplify-category-function@2.30.2 - amplify-category-hosting@2.6.3 - amplify-category-predictions@2.7.3 - amplify-category-storage@2.10.14 - amplify-category-xr@2.7.3 - amplify-cli-core@1.17.2 - @aws-amplify/cli@4.44.2 - amplify-codegen@2.21.4 - amplify-console-hosting@1.7.3 - amplify-console-integration-tests@1.3.16 - amplify-container-hosting@1.2.3 - amplify-dotnet-function-runtime-provider@1.5.2 - amplify-dotnet-function-template-provider@1.4.14 - amplify-dynamodb-simulator@1.17.11 - amplify-e2e-core@1.15.2 - amplify-e2e-tests@2.35.0 - amplify-frontend-ios@2.18.9 - amplify-frontend-javascript@2.20.9 - amplify-function-plugin-interface@1.7.2 - amplify-go-function-runtime-provider@1.6.2 - amplify-go-function-template-provider@1.3.5 - @aws-amplify/graphql-model-transformer@0.3.3 - @aws-amplify/graphql-transformer-core@0.3.3 - amplify-java-function-runtime-provider@1.6.2 - amplify-java-function-template-provider@1.5.5 - amplify-migration-tests@2.20.4 - amplify-nodejs-function-runtime-provider@1.5.2 - amplify-nodejs-function-template-provider@1.5.12 - amplify-provider-awscloudformation@4.39.2 - amplify-python-function-runtime-provider@1.6.2 - amplify-python-function-template-provider@1.3.6 - amplify-util-import@1.3.13 - amplify-util-mock@3.28.2 - graphql-auth-transformer@6.23.8 - graphql-connection-transformer@4.20.4 - graphql-dynamodb-transformer@6.21.9 - graphql-elasticsearch-transformer@4.10.5 - graphql-function-transformer@2.4.9 - graphql-http-transformer@4.16.9 - graphql-key-transformer@2.22.0 - graphql-predictions-transformer@2.4.9 - graphql-relational-schema-transformer@2.16.4 - graphql-transformer-common@4.19.0 - graphql-transformer-core@6.26.4 - graphql-transformers-e2e-tests@6.22.4 - graphql-versioned-transformer@4.16.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index bc3c3bbc53..1f09e83043 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3aa43baa9e..3f6c89f029 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.2", + "version": "2.29.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.17.1", + "amplify-cli-core": "1.17.2", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.3", - "graphql-transformer-core": "6.26.3", + "graphql-relational-schema-transformer": "2.16.4", + "graphql-transformer-core": "6.26.4", "inquirer": "^7.3.3", "ora": "^4.0.3", "uuid": "^3.4.0" From 941a887b03468bbc2e81f98d04a0b1cb35382095 Mon Sep 17 00:00:00 2001 From: Richard McClellan Date: Fri, 26 Feb 2021 17:34:38 -0600 Subject: [PATCH 396/587] fix: wording: Enable, instead of Configure, conflict detection (#6708) --- .../service-walkthroughs/appSync-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 9a36030b3f..08599dba60 100644 --- 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 @@ -361,7 +361,7 @@ async function askAdditionalQuestions(context, authConfig, defaultAuthType, mode async function askResolverConflictQuestion(context, modelTypes?) { let resolverConfig: any = {}; - if (await context.prompt.confirm('Configure conflict detection?')) { + if (await context.prompt.confirm('Enable conflict detection?')) { const askConflictResolutionStrategy = async msg => { let conflictResolutionStrategy; From fb87b807b40222788aed353c93d65bf4c280f8f0 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Tue, 2 Mar 2021 11:58:32 -0800 Subject: [PATCH 397/587] fixes: #5901 update node.js version handling for CLI (#6560) * chore: update node.js version handling for CLI * Lambda resource handlers will use 12.x by default * Lambda functions and triggers will use 14.x by default * Any <10.x will be migrated to 12.x Today Cloudformation Custom Resource handlers does not support 14.x. --- packages/amplify-category-api/package.json | 4 ++ .../sync-conflict-handler-template.json.ejs | 18 ++++---- .../docker-compose/DockerUtils.ts | 44 ++++++++++++------- .../pipeline-with-awaiter.ts | 41 +++++++++-------- 4 files changed, 64 insertions(+), 43 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3f6c89f029..c22db59428 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -71,9 +71,13 @@ "graphql-relational-schema-transformer": "2.16.4", "graphql-transformer-core": "6.26.4", "inquirer": "^7.3.3", + "js-yaml": "^4.0.0", "ora": "^4.0.3", "uuid": "^3.4.0" }, + "devDependencies": { + "@types/js-yaml": "^4.0.0" + }, "jest": { "testURL": "http://localhost", "transform": { 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 index 169b9ec33a..0cb2bca1ec 100644 --- 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 @@ -38,7 +38,7 @@ "FunctionName": { "Fn::If": [ "ShouldNotCreateEnvResources", - "<%= props.functionName %>", + "<%= props.functionName %>", { "Fn::Join": [ @@ -51,7 +51,7 @@ } ] ] - } + } ] }, "Environment": { @@ -59,14 +59,14 @@ "ENV": { "Ref": "env" }, - "REGION": { + "REGION": { "Ref": "AWS::Region" } <% if (props.resourceProperties && props.resourceProperties.length > 0) { %>,<%- props.resourceProperties%> <% } %> } }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, - "Runtime": "nodejs10.x", + "Runtime": "nodejs14.x", "Timeout": "25" } }, @@ -76,7 +76,7 @@ "RoleName": { "Fn::If": [ "ShouldNotCreateEnvResources", - "<%=props.roleName %>", + "<%=props.roleName %>", { "Fn::Join": [ @@ -89,7 +89,7 @@ } ] ] - } + } ] }, "AssumeRolePolicyDocument": { @@ -127,7 +127,7 @@ "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", + "Effect": "Allow", "Action": ["dynamodb:GetItem","dynamodb:Query","dynamodb:Scan","dynamodb:PutItem","dynamodb:UpdateItem","dynamodb:DeleteItem"], "Resource": [ <% if (props.database && props.database.Arn) { %> @@ -140,7 +140,7 @@ "index/*" ] ] - } + } <% } else { %> { "Ref": "storage<%= props.database.resourceName %>Arn" }, { @@ -151,7 +151,7 @@ "index/*" ] ] - } + } <% } %> ] } 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 index 6bb37bd57a..89b0016feb 100644 --- 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 @@ -1,11 +1,11 @@ -import yaml from 'js-yaml'; +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.safeLoad(yamlFileContents); + const doc = yaml.load(yamlFileContents); return doc as v2Types.ConfigSchemaV24Json | v1Types.ConfigSchemaV1Json; } catch (e) { console.log(e); @@ -21,14 +21,21 @@ export const dockerfileToObject = (dockerfileContents: string): v2Types.ConfigSc const composeContents = `version: "3" services: api: - build: .${ports.length > 0 ? ` - ports: ${ports.map(port => ` - - '${port}:${port}'`).join('') - }` : ``} + 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 @@ -48,22 +55,27 @@ phases: build: commands: - echo Build started on \`date\` - - echo Building the Docker image...${Object.keys(containerMap).map(item => ` + - 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') - } + - 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 => ` + - 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')} + - docker push $${item}_REPOSITORY_URI:$IMAGE_TAG`, + ) + .join('\n')} - "echo \\"[${Object.keys(containerMap) - .map(name => `{\\\\\\\"name\\\\\\\":\\\\\\\"${name}\\\\\\\", \\\\\\\"imageUri\\\\\\\":\\\\\\\"$${name}_REPOSITORY_URI\\\\\\\"}`) - .join(',') - }]\\" > imagedefinitions.json" + .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/pipeline-with-awaiter.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/pipeline-with-awaiter.ts index b7e7d19788..2ca6459bb3 100644 --- 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 @@ -13,7 +13,6 @@ import * as path from 'path'; import { DEPLOYMENT_MECHANISM } from './base-api-stack'; import { getGitHubOwnerRepoFromPath } from './utils/github'; - type PipelineAwaiterProps = { pipeline: codepipeline.Pipeline; artifactBucketName?: string; @@ -26,6 +25,9 @@ export type GitHubSourceActionInfo = { tokenSecretArn: string; }; +// TODO update when CDK is updated to newer version that supports NODEJS_14_X +const lambdaRuntimeNodeVersion = lambda.Runtime.NODEJS_12_X; + const lambdasDir = path.resolve(__dirname, '../../../resources/awscloudformation/lambdas'); class PipelineAwaiter extends cdk.Construct { @@ -38,7 +40,7 @@ class PipelineAwaiter extends cdk.Construct { const onEventHandlerCode = fs.readFileSync(pipelineOnEventCodeFilePath, 'utf8'); const onEventHandler = new lambda.Function(scope, `${id}CustomEventHandler`, { - runtime: lambda.Runtime.NODEJS_12_X, + runtime: lambdaRuntimeNodeVersion, handler: 'index.handler', code: lambda.Code.fromInline(onEventHandlerCode), timeout: cdk.Duration.seconds(15), @@ -48,7 +50,7 @@ class PipelineAwaiter extends cdk.Construct { const isCompleteHandlerCode = fs.readFileSync(pipelineCodeFilePath, 'utf8'); const isCompleteHandler = new lambda.Function(scope, `${id}CustomCompleteHandler`, { - runtime: lambda.Runtime.NODEJS_12_X, + runtime: lambdaRuntimeNodeVersion, handler: 'index.handler', timeout: cdk.Duration.seconds(15), code: lambda.Code.fromInline(isCompleteHandlerCode), @@ -172,19 +174,22 @@ export class PipelineWithAwaiter extends cdk.Construct { sourceOutput, }); - const environmentVariables = containersInfo.reduce((acc, c) => { - acc[`${c.container.containerName}_REPOSITORY_URI`] = { - type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, - value: c.repository.repositoryUri, - }; + 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); + return acc; + }, + { + AWS_ACCOUNT_ID: { + type: codebuild.BuildEnvironmentVariableType.PLAINTEXT, + value: cdk.Aws.ACCOUNT_ID, + }, + } as Record, + ); const stagesWithDeploy = ([] as codepipeline.StageOptions[]).concat(prebuildStages, [ { @@ -212,7 +217,7 @@ export class PipelineWithAwaiter extends cdk.Construct { const action = new lambda.Function(scope, 'PreDeployLambda', { code: lambda.Code.fromInline(lambdaHandlerCode), handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_12_X, + runtime: lambdaRuntimeNodeVersion, environment: { DESIRED_COUNT: `${desiredCount}`, CLUSTER_NAME: service.cluster, @@ -278,7 +283,7 @@ export class PipelineWithAwaiter extends cdk.Construct { }); } - new cdk.CfnOutput(scope, 'PipelineName', { value: this.pipelineName }) + new cdk.CfnOutput(scope, 'PipelineName', { value: this.pipelineName }); } getPipelineName(): string { @@ -336,7 +341,7 @@ function createPreBuildStages( lambda: new lambda.Function(scope, 'PreBuildLambda', { code: lambda.S3Code.fromBucket(bucket, 'codepipeline-action-buildspec-generator-lambda.zip'), handler: 'index.handler', - runtime: lambda.Runtime.NODEJS_12_X, + runtime: lambdaRuntimeNodeVersion, timeout: cdk.Duration.seconds(15), }), inputs: [preBuildOutput], From dd4190b93a3b2535b7db6852c2988c16f7c81b0c Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Thu, 4 Mar 2021 10:43:00 -0800 Subject: [PATCH 398/587] chore: use latest prod versions of docker images (#6793) --- .../dockercompose-rest-express/express/Dockerfile | 3 +-- .../dockercompose-rest-express/python/Dockerfile | 2 +- .../container-templates/dockerfile-rest-express/Dockerfile | 2 +- .../container-templates/graphql-express/Dockerfile | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) 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 index b7a7be80ef..189a7e546e 100644 --- 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 @@ -1,4 +1,4 @@ -FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 +FROM public.ecr.aws/bitnami/node:14-prod-debian-10 ENV PORT=8080 EXPOSE 8080 @@ -10,4 +10,3 @@ RUN npm install COPY . . CMD [ "node", "index.js" ] - \ 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 index 8dd986b2b8..ceac55382f 100644 --- 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 @@ -1,5 +1,5 @@ # set base image (host OS) -FROM public.ecr.aws/bitnami/python:3.8-debian-10 +FROM public.ecr.aws/bitnami/python:3.8-prod-debian-10 # set the working directory in the container WORKDIR /code 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 index 5409fbc7e0..189a7e546e 100644 --- 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 @@ -1,4 +1,4 @@ -FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 +FROM public.ecr.aws/bitnami/node:14-prod-debian-10 ENV PORT=8080 EXPOSE 8080 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 index b9fd49c25c..8c5be4eb09 100644 --- a/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile +++ b/packages/amplify-category-api/resources/awscloudformation/container-templates/graphql-express/Dockerfile @@ -1,4 +1,4 @@ -FROM public.ecr.aws/bitnami/node:14.15.1-debian-10-r8 +FROM public.ecr.aws/bitnami/node:14-prod-debian-10 WORKDIR /usr/src/app COPY package*.json ./ From f170902ad2b0d528427e01543d11c76d175fc8f9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 5 Mar 2021 18:50:27 +0000 Subject: [PATCH 399/587] chore(release): Publish [ci skip] - amplify-app@2.21.5 - amplify-appsync-simulator@1.25.4 - amplify-category-analytics@2.20.4 - amplify-category-api@2.29.4 - amplify-category-auth@2.29.0 - amplify-category-function@2.30.3 - amplify-category-hosting@2.6.4 - amplify-category-interactions@2.6.2 - amplify-category-notifications@2.18.1 - amplify-category-predictions@2.7.4 - amplify-category-storage@2.10.15 - amplify-category-xr@2.7.4 - amplify-cli-core@1.18.0 - @aws-amplify/cli@4.45.0 - amplify-console-hosting@1.7.4 - amplify-console-integration-tests@1.4.0 - amplify-container-hosting@1.2.4 - amplify-dotnet-function-template-provider@1.4.15 - amplify-dynamodb-simulator@1.17.12 - amplify-e2e-core@1.16.0 - amplify-e2e-tests@2.36.0 - amplify-frontend-ios@2.18.10 - amplify-frontend-javascript@2.20.10 - amplify-go-function-runtime-provider@1.6.3 - amplify-graphiql-explorer@1.4.3 - @aws-amplify/graphql-model-transformer@0.3.4 - @aws-amplify/graphql-transformer-core@0.3.4 - amplify-java-function-runtime-provider@1.6.3 - amplify-migration-tests@2.20.5 - amplify-nodejs-function-runtime-provider@1.5.3 - amplify-nodejs-function-template-provider@1.5.13 - amplify-provider-awscloudformation@4.40.0 - amplify-python-function-runtime-provider@1.6.3 - amplify-util-import@1.3.14 - amplify-util-mock@3.29.0 - amplify-velocity-template@1.4.4 - graphql-auth-transformer@6.23.9 - graphql-connection-transformer@4.20.5 - graphql-dynamodb-transformer@6.21.10 - graphql-elasticsearch-transformer@4.10.6 - graphql-function-transformer@2.4.10 - graphql-http-transformer@4.16.10 - graphql-key-transformer@2.22.1 - graphql-predictions-transformer@2.4.10 - graphql-relational-schema-transformer@2.16.5 - graphql-transformer-common@4.19.1 - graphql-transformer-core@6.26.5 - graphql-transformers-e2e-tests@6.22.5 - graphql-versioned-transformer@4.16.10 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1f09e83043..54b4d7fe1c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c22db59428..783e085461 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.3", + "version": "2.29.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.17.2", + "amplify-cli-core": "1.18.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.4", - "graphql-transformer-core": "6.26.4", + "graphql-relational-schema-transformer": "2.16.5", + "graphql-transformer-core": "6.26.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 3caa72017633cb3e92c4d56e1fdeaea729fe3f6f Mon Sep 17 00:00:00 2001 From: Raj Rajhans Date: Sat, 6 Mar 2021 00:46:03 +0530 Subject: [PATCH 400/587] docs: add readme to vtl resolvers directory (#6718) * docs: add readme to vtl resolvers directory --- .../resources/awscloudformation/resolver-readme/README.md | 2 ++ .../awscloudformation/cfn-api-artifact-handler.test.ts | 4 ++-- .../awscloudformation/cfn-api-artifact-handler.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md diff --git a/packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md b/packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md new file mode 100644 index 0000000000..89e564c5b3 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md @@ -0,0 +1,2 @@ +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/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 index 9fa8ebe762..4bd19bfc02 100644 --- 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 @@ -105,8 +105,8 @@ describe('create artifacts', () => { it('writes the default custom resources stack', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fs_mock.copyFileSync.mock.calls.length).toBe(1); - expect(fs_mock.copyFileSync.mock.calls[0]).toEqual([ + expect(fs_mock.copyFileSync.mock.calls.length).toBe(2); + expect(fs_mock.copyFileSync.mock.calls[1]).toEqual([ path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'stacks', 'CustomResources.json'), ]); 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 index 9edb251d80..9805bc557c 100644 --- 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 @@ -59,6 +59,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const stacksDirectoryPath = path.join(resourceDir, stacksDirName); if (!fs.existsSync(stacksDirectoryPath)) { fs.mkdirSync(stacksDirectoryPath); + fs.copyFileSync(path.join(rootAssetDir, 'resolver-readme', '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. From 1bcbbbf1c3f57248047d74fba084a99db575bfc3 Mon Sep 17 00:00:00 2001 From: Nikhil Lingireddy Date: Tue, 9 Mar 2021 15:49:29 -0800 Subject: [PATCH 401/587] Revert "docs: add readme to vtl resolvers directory (#6718)" (#6845) This reverts commit 3caa72017633cb3e92c4d56e1fdeaea729fe3f6f. --- .../resources/awscloudformation/resolver-readme/README.md | 2 -- .../awscloudformation/cfn-api-artifact-handler.test.ts | 4 ++-- .../awscloudformation/cfn-api-artifact-handler.ts | 1 - 3 files changed, 2 insertions(+), 5 deletions(-) delete mode 100644 packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md diff --git a/packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md b/packages/amplify-category-api/resources/awscloudformation/resolver-readme/README.md deleted file mode 100644 index 89e564c5b3..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/resolver-readme/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/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 index 4bd19bfc02..9fa8ebe762 100644 --- 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 @@ -105,8 +105,8 @@ describe('create artifacts', () => { it('writes the default custom resources stack', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fs_mock.copyFileSync.mock.calls.length).toBe(2); - expect(fs_mock.copyFileSync.mock.calls[1]).toEqual([ + expect(fs_mock.copyFileSync.mock.calls.length).toBe(1); + expect(fs_mock.copyFileSync.mock.calls[0]).toEqual([ path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'stacks', 'CustomResources.json'), ]); 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 index 9805bc557c..9edb251d80 100644 --- 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 @@ -59,7 +59,6 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const stacksDirectoryPath = path.join(resourceDir, stacksDirName); if (!fs.existsSync(stacksDirectoryPath)) { fs.mkdirSync(stacksDirectoryPath); - fs.copyFileSync(path.join(rootAssetDir, 'resolver-readme', '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. From 847780100e7e0371336b5cfd33f9cf2de2a1c193 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 11 Mar 2021 22:54:02 +0000 Subject: [PATCH 402/587] chore(release): Publish [ci skip] - amplify-app@2.21.6 - amplify-category-analytics@2.20.5 - amplify-category-api@2.29.5 - amplify-category-auth@2.29.1 - amplify-category-function@2.30.4 - amplify-category-hosting@2.6.5 - amplify-category-predictions@2.7.5 - amplify-category-storage@2.10.16 - amplify-category-xr@2.7.5 - amplify-cli-core@1.18.1 - @aws-amplify/cli@4.45.1 - amplify-console-hosting@1.7.5 - amplify-console-integration-tests@1.4.1 - amplify-container-hosting@1.2.5 - amplify-dotnet-function-template-provider@1.4.16 - amplify-dynamodb-simulator@1.17.13 - amplify-e2e-core@1.16.1 - amplify-e2e-tests@2.36.1 - amplify-frontend-ios@2.18.11 - amplify-frontend-javascript@2.20.11 - amplify-go-function-runtime-provider@1.6.4 - amplify-java-function-runtime-provider@1.6.4 - amplify-migration-tests@2.20.6 - amplify-nodejs-function-template-provider@1.5.14 - amplify-provider-awscloudformation@4.40.1 - amplify-python-function-runtime-provider@1.6.4 - amplify-util-import@1.3.15 - amplify-util-mock@3.29.1 - graphql-auth-transformer@6.23.10 - graphql-connection-transformer@4.20.6 - graphql-dynamodb-transformer@6.21.11 - graphql-elasticsearch-transformer@4.10.7 - graphql-function-transformer@2.4.11 - graphql-http-transformer@4.16.11 - graphql-key-transformer@2.22.2 - graphql-predictions-transformer@2.4.11 - graphql-transformer-core@6.26.6 - graphql-transformers-e2e-tests@6.22.6 - graphql-versioned-transformer@4.16.11 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 54b4d7fe1c..b92ab9ce1c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 783e085461..73fdf19c20 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.4", + "version": "2.29.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.18.0", + "amplify-cli-core": "1.18.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.5", - "graphql-transformer-core": "6.26.5", + "graphql-transformer-core": "6.26.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From e63c332143ad969fff0298f6d952e19606092eac Mon Sep 17 00:00:00 2001 From: Emilien Escalle Date: Fri, 19 Mar 2021 01:53:12 +0100 Subject: [PATCH 403/587] feat: allows adding graphql datasource with an empty graphql schema file (#4464) --- .../commands/api/add-graphql-datasource.test.js | 5 +++++ .../commands/api/mock-data/empty_schema.graphql | 0 .../api/mock-data/invalid_schema.graphql | 7 +++++++ .../src/commands/api/add-graphql-datasource.js | 16 +++++++++++++++- 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/mock-data/empty_schema.graphql diff --git a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js index 118ae14401..701aadaa8c 100644 --- a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js +++ b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js @@ -14,4 +14,9 @@ describe('read schema', () => { } expect(invalidSchema).toThrowError('Could not parse graphql schema'); }); + + 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 new file mode 100644 index 0000000000..e69de29bb2 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 index e69de29bb2..4d56fbd77d 100644 --- 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 @@ -0,0 +1,7 @@ +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/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 56dcd87315..957fdce03e 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -114,8 +114,17 @@ module.exports = { const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); if (schemaFileExists) { + const typesToBeMerged = [rdsGraphQLSchemaDoc]; const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - const concatGraphQLSchemaDoc = mergeTypeDefs([currGraphQLSchemaDoc, rdsGraphQLSchemaDoc], { all: true }); + + if (currGraphQLSchemaDoc) { + typesToBeMerged.unshift(currGraphQLSchemaDoc); + } else { + context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); + context.print.info(''); + } + + const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged, { all: true }); fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); } else if (schemaDirectoryExists) { const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); @@ -222,6 +231,11 @@ async function getAwsClient(context, action) { function readSchema(graphqlSchemaFilePath) { const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); + const graphqlSchemaIsEmpty = graphqlSchemaRaw.trim().length === 0; + if (graphqlSchemaIsEmpty) { + return null; + } + let currGraphQLSchemaDoc; try { currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); From c3538f579c7d574a0c2b0dccde7a9a3c2860f22c Mon Sep 17 00:00:00 2001 From: Josue Ruiz Date: Fri, 19 Mar 2021 11:44:09 -0700 Subject: [PATCH 404/587] fix(amplify-category-api): mantain ff in iam api policy (#6723) when using the ff for generating the appsync iam policy use the old format if the ff is empty ref #6675 --- .../appSync-walkthrough.test.ts | 57 +++++++++++++++++-- .../appSync-walkthrough.ts | 41 ++++++++++--- 2 files changed, 84 insertions(+), 14 deletions(-) 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 index b497d07111..a664b0b469 100644 --- 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 @@ -3,10 +3,13 @@ import { askAdditionalAuthQuestions, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +import { FeatureFlags, CLIEnvironmentProvider, FeatureFlagRegistration } from 'amplify-cli-core'; jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), })); +jest.mock('amplify-cli-core'); +const mockGetBoolean = FeatureFlags.getBoolean as jest.Mock; const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; @@ -21,28 +24,70 @@ const context_stub = (prompt: jest.Mock) => ({ }, }); +type IAMArtifact = { + attributes: string[], + policy: any, +}; + + describe('get IAM policies', () => { - it('does not include API key if none exists', () => { + beforeEach(() => { + jest.resetModules(); + }); +it('does not include API key if none exists', async () => { + mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => false); - const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub(confirmPromptFalse_mock)); - expect(attributes).toMatchInlineSnapshot(` + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); + 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', () => { +it('includes API key if it exists', async () => { + mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const { attributes } = getIAMPolicies('testResourceName', ['read'], context_stub(confirmPromptFalse_mock)); - expect(attributes).toMatchInlineSnapshot(` + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); + 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'], context_stub(confirmPromptFalse_mock)); + 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'], context_stub(confirmPromptFalse_mock)); + 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('/*'); }); }); 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 index 08599dba60..f2878dbb50 100644 --- 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 @@ -17,6 +17,7 @@ import { UnknownResourceTypeError, exitOnNextTick, stateManager, + FeatureFlags, $TSContext, open, } from 'amplify-cli-core'; @@ -721,15 +722,39 @@ export const migrate = async context => { }); }; -export const getIAMPolicies = (resourceName, operations, context) => { - let policy = {}; +export const getIAMPolicies = (resourceName: string, operations: string[], context: any) => { + let policy: any = {}; const resources = []; - - operations.forEach(operation => resources.push(buildPolicyResource(resourceName, operation))); + 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: + console.log(`${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: ['appsync:GraphQL'], + Action: actions, Resource: resources, }; @@ -741,7 +766,7 @@ export const getIAMPolicies = (resourceName, operations, context) => { return { policy, attributes }; }; -const buildPolicyResource = (resourceName, operation) => { +const buildPolicyResource = (resourceName: string, path: string | null) => { return { 'Fn::Join': [ '', @@ -754,8 +779,8 @@ const buildPolicyResource = (resourceName, operation) => { { Ref: `${category}${resourceName}GraphQLAPIIdOutput`, }, - `/types/${operation}/*`, - ], + ...(path ? [path] : []) + ] ], }; }; From f9bd0df487f0e0fae44f4b2d6113639dde2b077f Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 23 Mar 2021 00:31:25 +0000 Subject: [PATCH 405/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.25.5 - amplify-category-api@2.30.0 - amplify-category-auth@2.29.2 - amplify-category-function@2.30.5 - amplify-category-predictions@2.7.6 - amplify-category-storage@2.10.17 - @aws-amplify/cli@4.46.0 - amplify-console-integration-tests@1.4.2 - amplify-container-hosting@1.2.6 - amplify-dotnet-function-template-provider@1.4.17 - amplify-e2e-core@1.16.2 - amplify-e2e-tests@2.37.0 - amplify-migration-tests@2.20.7 - amplify-nodejs-function-template-provider@1.5.15 - amplify-provider-awscloudformation@4.40.3 - amplify-python-function-runtime-provider@1.6.5 - amplify-python-function-template-provider@1.3.7 - amplify-util-mock@3.29.3 - graphql-auth-transformer@6.23.11 - graphql-connection-transformer@4.20.7 - graphql-dynamodb-transformer@6.21.12 - graphql-elasticsearch-transformer@4.10.8 - graphql-function-transformer@2.4.12 - graphql-http-transformer@4.16.12 - graphql-key-transformer@2.22.3 - graphql-predictions-transformer@2.4.12 - graphql-transformer-core@6.27.0 - graphql-transformers-e2e-tests@6.22.7 - graphql-versioned-transformer@4.16.12 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index b92ab9ce1c..a5c5e8d88c 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 73fdf19c20..f1712bcb8b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.29.5", + "version": "2.30.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -69,7 +69,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.16.5", - "graphql-transformer-core": "6.26.6", + "graphql-transformer-core": "6.27.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 5899be1a622afbf79e6e38ec7a051875539bee2e Mon Sep 17 00:00:00 2001 From: Raj Rajhans Date: Wed, 24 Mar 2021 06:33:41 +0530 Subject: [PATCH 406/587] docs: add RESOLVER_README to vtl resolvers directory (#6874) --- .../awscloudformation/resolver-readme/RESOLVER_README.md | 2 ++ .../awscloudformation/cfn-api-artifact-handler.test.ts | 4 ++-- .../awscloudformation/cfn-api-artifact-handler.ts | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md 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 new file mode 100644 index 0000000000..89e564c5b3 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/resolver-readme/RESOLVER_README.md @@ -0,0 +1,2 @@ +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/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 index 9fa8ebe762..4bd19bfc02 100644 --- 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 @@ -105,8 +105,8 @@ describe('create artifacts', () => { it('writes the default custom resources stack', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fs_mock.copyFileSync.mock.calls.length).toBe(1); - expect(fs_mock.copyFileSync.mock.calls[0]).toEqual([ + expect(fs_mock.copyFileSync.mock.calls.length).toBe(2); + expect(fs_mock.copyFileSync.mock.calls[1]).toEqual([ path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), path.join(backendDirPathStub, category, addRequestStub.serviceConfiguration.apiName, 'stacks', 'CustomResources.json'), ]); 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 index 9edb251d80..8532ec14ed 100644 --- 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 @@ -59,6 +59,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { 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. From 1c42597fb25d5fc58c65d2d8d5f319736c67ab2b Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Tue, 23 Mar 2021 21:07:30 -0400 Subject: [PATCH 407/587] fix(cli): use more inclusive language (#6919) This commit replaces the use of whitelist and blacklist throughout the codebase with allowlist and denylist. Refs: https://github.com/aws-amplify/amplify-cli/pull/6331 Refs: https://github.com/aws-amplify/amplify-cli/pull/5497 Co-authored-by: Colin Ihrig --- .../awscloudformation/utils/rest-api-path-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 6bce9e16a0..37370c2dea 100644 --- 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 @@ -1,7 +1,7 @@ // 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) => { - // "Whitelist" the path / + // Allow the path / if (name === '/') { return true; } From a6a4d3df4787720f6dc98b46b4c0eca8ff43bbd6 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 8 Apr 2021 16:30:31 -0700 Subject: [PATCH 408/587] chore: manually bump up minor versions to avoid git tag conflicts --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f1712bcb8b..5297e12346 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.30.0", + "version": "2.30.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.18.1", + "amplify-cli-core": "^1.18.2", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.16.5", - "graphql-transformer-core": "6.27.0", + "graphql-relational-schema-transformer": "^2.16.6", + "graphql-transformer-core": "^6.27.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From c963e94c56d512c96cd55e4565e70d120e383b03 Mon Sep 17 00:00:00 2001 From: Ghosh Date: Thu, 8 Apr 2021 17:15:17 -0700 Subject: [PATCH 409/587] chore: manually bumpup minor versions to avoid git tag conflicts --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5297e12346..0d93f2e55c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.30.1", + "version": "2.31.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "^1.18.2", + "amplify-cli-core": "^1.19.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "^2.16.6", - "graphql-transformer-core": "^6.27.1", + "graphql-relational-schema-transformer": "^2.17.0", + "graphql-transformer-core": "^6.28.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 0dcb1bf8c7dec9eba676e9e2a36b395cc3b42e80 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 9 Apr 2021 21:59:33 +0000 Subject: [PATCH 410/587] chore(release): Publish [ci skip] - amplify-app@2.23.0 - amplify-appsync-simulator@1.26.1 - amplify-category-analytics@2.21.1 - amplify-category-api@2.31.1 - amplify-category-auth@2.30.1 - amplify-category-function@2.31.1 - amplify-category-hosting@2.7.1 - amplify-category-notifications@2.19.1 - amplify-category-predictions@2.8.1 - amplify-category-storage@2.11.1 - amplify-category-xr@2.8.1 - amplify-cli-core@1.19.1 - @aws-amplify/cli@4.47.1 - amplify-console-hosting@1.8.1 - amplify-console-integration-tests@1.5.1 - amplify-container-hosting@1.3.1 - amplify-dotnet-function-template-provider@1.5.1 - amplify-dynamodb-simulator@1.18.1 - amplify-e2e-core@1.17.1 - amplify-e2e-tests@2.38.1 - amplify-frontend-android@2.15.1 - amplify-frontend-flutter@0.4.1 - amplify-frontend-ios@2.19.1 - amplify-frontend-javascript@2.21.1 - amplify-go-function-runtime-provider@1.7.1 - amplify-graphql-types-generator@2.8.1 - amplify-java-function-runtime-provider@1.7.1 - amplify-migration-tests@2.21.1 - amplify-nodejs-function-template-provider@1.6.1 - amplify-provider-awscloudformation@4.42.0 - amplify-python-function-runtime-provider@1.7.1 - amplify-util-import@1.4.1 - amplify-util-mock@3.30.1 - graphql-auth-transformer@6.24.1 - graphql-connection-transformer@4.21.1 - graphql-dynamodb-transformer@6.22.1 - graphql-elasticsearch-transformer@4.11.1 - graphql-function-transformer@2.5.1 - graphql-http-transformer@4.17.1 - graphql-key-transformer@2.23.1 - graphql-predictions-transformer@2.5.1 - graphql-relational-schema-transformer@2.17.1 - graphql-transformer-core@6.28.1 - graphql-transformers-e2e-tests@6.23.1 - graphql-versioned-transformer@4.17.1 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a5c5e8d88c..71777b9a2d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0d93f2e55c..824ff6bb64 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.0", + "version": "2.31.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "^1.19.0", + "amplify-cli-core": "1.19.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "^2.17.0", - "graphql-transformer-core": "^6.28.0", + "graphql-relational-schema-transformer": "2.17.1", + "graphql-transformer-core": "6.28.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From f70eeff39fe610a70fb9d91adcc1631a6682157c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 14 Apr 2021 03:41:55 +0000 Subject: [PATCH 411/587] chore(release): Publish [ci skip] - amplify-app@2.23.1 - amplify-appsync-simulator@1.26.2 - amplify-category-analytics@2.21.2 - amplify-category-api@2.31.2 - amplify-category-auth@2.30.2 - amplify-category-function@2.31.2 - amplify-category-hosting@2.7.2 - amplify-category-predictions@2.8.2 - amplify-category-storage@2.11.2 - amplify-category-xr@2.8.2 - amplify-cli-core@1.20.0 - @aws-amplify/cli@4.48.0 - amplify-console-hosting@1.8.2 - amplify-console-integration-tests@1.5.2 - amplify-container-hosting@1.3.2 - amplify-dotnet-function-template-provider@1.5.2 - amplify-dynamodb-simulator@1.18.2 - amplify-e2e-core@1.17.2 - amplify-e2e-tests@2.38.2 - amplify-frontend-ios@2.19.2 - amplify-frontend-javascript@2.21.2 - amplify-go-function-runtime-provider@1.7.2 - amplify-java-function-runtime-provider@1.7.2 - amplify-migration-tests@2.21.2 - amplify-nodejs-function-template-provider@1.6.2 - amplify-provider-awscloudformation@4.43.0 - amplify-python-function-runtime-provider@1.7.2 - amplify-util-import@1.4.2 - amplify-util-mock@3.30.2 - graphql-auth-transformer@6.24.2 - graphql-connection-transformer@4.21.2 - graphql-dynamodb-transformer@6.22.2 - graphql-elasticsearch-transformer@4.11.2 - graphql-function-transformer@2.5.2 - graphql-http-transformer@4.17.2 - graphql-key-transformer@2.23.2 - graphql-predictions-transformer@2.5.2 - graphql-transformer-core@6.28.2 - graphql-transformers-e2e-tests@6.23.2 - graphql-versioned-transformer@4.17.2 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 71777b9a2d..f322cd2d32 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 824ff6bb64..14e329d33b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.1", + "version": "2.31.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.19.1", + "amplify-cli-core": "1.20.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.1", - "graphql-transformer-core": "6.28.1", + "graphql-transformer-core": "6.28.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From e585db4a5ed57ae403d00ff3fd33bd565805b308 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 19 Apr 2021 16:57:35 +0000 Subject: [PATCH 412/587] chore(release): Publish [ci skip] - amplify-app@2.23.2 - amplify-category-analytics@2.21.3 - amplify-category-api@2.31.3 - amplify-category-auth@2.30.3 - amplify-category-function@2.31.3 - amplify-category-hosting@2.7.3 - amplify-category-predictions@2.8.3 - amplify-category-storage@2.11.3 - amplify-category-xr@2.8.3 - amplify-cli-core@1.20.1 - @aws-amplify/cli@4.49.0 - amplify-console-hosting@1.8.3 - amplify-console-integration-tests@1.5.3 - amplify-container-hosting@1.3.3 - amplify-dotnet-function-template-provider@1.5.3 - amplify-dynamodb-simulator@1.18.3 - amplify-e2e-core@1.17.3 - amplify-e2e-tests@2.38.3 - amplify-frontend-ios@2.19.3 - amplify-frontend-javascript@2.21.3 - amplify-go-function-runtime-provider@1.7.3 - amplify-java-function-runtime-provider@1.7.3 - amplify-migration-tests@2.21.3 - amplify-nodejs-function-template-provider@1.6.3 - amplify-provider-awscloudformation@4.44.0 - amplify-python-function-runtime-provider@1.7.3 - amplify-util-import@1.4.3 - amplify-util-mock@3.30.3 - graphql-auth-transformer@6.24.3 - graphql-connection-transformer@4.21.3 - graphql-dynamodb-transformer@6.22.3 - graphql-elasticsearch-transformer@4.11.3 - graphql-function-transformer@2.5.3 - graphql-http-transformer@4.17.3 - graphql-key-transformer@2.23.3 - graphql-predictions-transformer@2.5.3 - graphql-transformer-core@6.28.3 - graphql-transformers-e2e-tests@6.23.3 - graphql-versioned-transformer@4.17.3 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f322cd2d32..d69be55d19 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 14e329d33b..8b503ca0b6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.2", + "version": "2.31.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.20.0", + "amplify-cli-core": "1.20.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.1", - "graphql-transformer-core": "6.28.2", + "graphql-transformer-core": "6.28.3", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 2820ba7157ece78d08c598c30eb7c011176da839 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Mon, 19 Apr 2021 19:49:19 -0400 Subject: [PATCH 413/587] fix: consolidate REST API IAM policies (#6904) (ref #2084) --- ...w-cloudformation-template-default.json.ejs | 244 ++---------------- .../awscloudformation/legacy-add-resource.ts | 15 +- 2 files changed, 21 insertions(+), 238 deletions(-) diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs index 7e61a219e5..959fb43c00 100644 --- a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -3,12 +3,6 @@ "Description": "API Gateway resource stack creation using Amplify CLI", <% if (props.dependsOn) { %> "Parameters": { - "authRoleName": { - "Type": "String" - }, - "unauthRoleName": { - "Type": "String" - }, "env": { "Type": "String" }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> @@ -18,7 +12,7 @@ "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) { %>,<% } %> - + <% } %> <% } %> <% } %> @@ -34,107 +28,6 @@ } }, "Resources": { - <%if (props.privacy.auth) { %> - "PolicyAPIGW<%= props.apiName %>auth": { - "DependsOn": [ - "<%= props.apiName %>" - ], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "PolicyAPIGW<%= props.apiName %>auth", - "Roles": [ - {"Ref": "authRoleName"} - ], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "execute-api:Invoke" - ], - "Resource": [ - <% for(var i=0; i < props.paths.length; i++) { %> - <% if (props.paths[i].privacy && props.paths[i].privacy.auth) { %> - <% for(var x=0; x < props.paths[i].privacy.auth.length; x++) { %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.auth[x] %>", - "<%= props.paths[i].policyResourceName %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.auth[x] %>", - "<%= props.paths[i].policyResourceName %>" - ] - ] - } - <% if (x !== props.paths[i].privacy.auth.length - 1) { %> - , - <% } %> - <% } %> - <% if (i !== props.paths.length - 1) { %> - , - <% } %> - <% } %> - <% } %> - ] - } - ] - } - } - }, - <% } %> <% for(var i=0; i < props.paths.length; i++) { %> <%if (props.paths[i].privacy && props.paths[i].privacy.userPoolGroups) { %> <% let selectedUserPoolGroupList = Object.keys(props.paths[i].privacy.userPoolGroups); %> @@ -168,7 +61,7 @@ "execute-api:Invoke" ], "Resource": [ - + <% for(var x=0; x < props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length; x++) { %> { "Fn::Join": [ @@ -190,10 +83,10 @@ { "Fn::If": [ "ShouldNotCreateEnvResources", - "Prod", + "Prod", { "Ref": "env" - } + } ] }, "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", @@ -245,107 +138,6 @@ <% } %> <% } %> <% } %> - <%if (props.privacy.unauth) { %> - "PolicyAPIGW<%= props.apiName %>unauth": { - "DependsOn": [ - "<%= props.apiName %>" - ], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "PolicyAPIGW<%= props.apiName %>unauth", - "Roles": [ - {"Ref": "unauthRoleName"} - ], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "execute-api:Invoke" - ], - "Resource": [ - <% for(var i=0; i < props.paths.length; i++) { %> - <% if (props.paths[i].privacy && props.paths[i].privacy.unauth) { %> - <% for(var x=0; x < props.paths[i].privacy.unauth.length; x++) { %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.unauth[x] %>", - "<%= props.paths[i].policyResourceName %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.unauth[x] %>", - "<%= props.paths[i].policyResourceName %>" - ] - ] - } - <% if (x !== props.paths[i].privacy.unauth.length - 1) { %> - , - <% } %> - <% } %> - <% if (i !== props.paths.length - 1) { %> - , - <% } %> - <% } %> - <% } %> - ] - } - ] - } - } - }, - <% } %> "<%= props.apiName %>": { "Type": "AWS::ApiGateway::RestApi", "Properties": { @@ -383,7 +175,7 @@ } ] ] - } + } ] }, "schemes": [ @@ -458,7 +250,7 @@ } } }, - <%if (!props.paths[i].privacy.open) { %> + <%if (!props.paths[i].privacy.open) { %> "security": [ { "sigv4": [] @@ -480,11 +272,11 @@ "Ref": "AWS::Region" }, ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn ) { %> - "<%= props.paths[i].lambdaArn %>", + <% if (props.paths[i].lambdaArn ) { %> + "<%= props.paths[i].lambdaArn %>", <% } else { %> { - + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" }, <% } %> @@ -565,7 +357,7 @@ } } }, - <%if (!props.paths[i].privacy.open) { %> + <%if (!props.paths[i].privacy.open) { %> "security": [ { "sigv4": [] @@ -587,11 +379,11 @@ "Ref": "AWS::Region" }, ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn) { %> + <% if (props.paths[i].lambdaArn) { %> "<%= props.paths[i].lambdaArn %>", <% } else { %> { - + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" }, <% } %> @@ -604,7 +396,7 @@ "type": "aws_proxy" } } - }<% if (i !== props.paths.length - 1) { %>,<% } %> + }<% if (i !== props.paths.length - 1) { %>,<% } %> <% } %> }, "securityDefinitions": { @@ -646,9 +438,9 @@ } }, - <%if (props.functionArns) { %> + <%if (props.functionArns) { %> <% for (var i=0; i < props.functionArns.length; i++) { %> - + "function<%= props.functionArns[i].lambdaFunction.replace(/[^0-9a-zA-Z]/gi, '') %>Permission<%= props.apiName %>": { "Type": "AWS::Lambda::Permission", "Properties": { @@ -683,7 +475,7 @@ }, <% } %> <% } %> - + "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { "Type": "AWS::ApiGateway::Deployment", "Properties": { @@ -691,10 +483,10 @@ "StageName": { "Fn::If": [ "ShouldNotCreateEnvResources", - "Prod", + "Prod", { "Ref": "env" - } + } ] }, "RestApiId": { 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 index 211ea1c1fb..fe756c786f 100644 --- 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 @@ -1,3 +1,4 @@ +import { JSONUtilities } from 'amplify-cli-core'; import { serviceMetadataFor } from './utils/dynamic-imports'; import fs from 'fs-extra'; import path from 'path'; @@ -29,24 +30,14 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; - const cfnParameters = { - authRoleName: { - Ref: 'AuthRoleName', - }, - unauthRoleName: { - Ref: 'UnauthRoleName', - }, - }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let jsonString = JSON.stringify(parameters, null, 4); - fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); + JSONUtilities.writeJson(parametersFilePath, parameters); const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - jsonString = JSON.stringify(cfnParameters, null, 4); - fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); + JSONUtilities.writeJson(cfnParametersFilePath, {}); } context.amplify.updateamplifyMetaAfterResourceAdd(category, answers.resourceName, options); return answers.resourceName; From b583d8d13d2e90c8bc97ff011453072de77df1ab Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Mon, 19 Apr 2021 20:17:19 -0400 Subject: [PATCH 414/587] fix: handle errors and provide better error message when adding data source (#7117) (ref #4384) --- .../appSync-rds-walkthrough.js | 34 +++++++++++++------ 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js index 0235550962..441450bb9b 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js @@ -167,26 +167,38 @@ async function selectDatabase(context, 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...'); - const dataApiResult = await DataApi.executeStatement(params).promise(); - // eslint-disable-next-line prefer-destructuring - const records = dataApiResult.records; - const databaseList = []; + try { + const dataApiResult = await DataApi.executeStatement(params).promise(); - for (let i = 0; i < records.length; i += 1) { - const recordValue = records[i][0].stringValue; - // ignore the three meta tables that the cluster creates - if (!['information_schema', 'performance_schema', 'mysql'].includes(recordValue)) { - databaseList.push(recordValue); + // eslint-disable-next-line prefer-destructuring + const records = dataApiResult.records; + + for (const record of records) { + const recordValue = record[0].stringValue; + // ignore the three meta tables that the cluster creates + if (!['information_schema', 'performance_schema', 'mysql'].includes(recordValue)) { + databaseList.push(recordValue); + } } - } - spinner.succeed('Fetched Aurora Serverless cluster.'); + 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.'; + context.print.error(msg); + } + } if (databaseList.length > 0) { return await promptWalkthroughQuestion(inputs, 3, databaseList); From 3dd6c2bd82a875db0098b9367535f13ae2e53fa9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 27 Apr 2021 16:09:34 +0000 Subject: [PATCH 415/587] chore(release): Publish [ci skip] - amplify-app@2.23.3 - amplify-category-analytics@2.21.4 - amplify-category-api@2.31.4 - amplify-category-auth@2.30.4 - amplify-category-function@2.31.4 - amplify-category-hosting@2.7.4 - amplify-category-predictions@2.8.4 - amplify-category-storage@2.11.4 - amplify-category-xr@2.8.4 - amplify-cli-core@1.21.0 - @aws-amplify/cli@4.50.0 - amplify-console-hosting@1.8.4 - amplify-console-integration-tests@1.5.4 - amplify-container-hosting@1.3.4 - amplify-dotnet-function-template-provider@1.5.4 - amplify-dynamodb-simulator@1.18.4 - amplify-e2e-core@1.18.0 - amplify-e2e-tests@2.39.0 - amplify-frontend-ios@2.19.4 - amplify-frontend-javascript@2.21.4 - amplify-go-function-runtime-provider@1.7.4 - amplify-java-function-runtime-provider@1.7.4 - amplify-migration-tests@2.21.4 - amplify-nodejs-function-template-provider@1.6.4 - amplify-provider-awscloudformation@4.45.0 - amplify-python-function-runtime-provider@1.7.4 - amplify-util-import@1.4.4 - amplify-util-mock@3.30.4 - graphql-auth-transformer@6.24.4 - graphql-connection-transformer@4.21.4 - graphql-dynamodb-transformer@6.22.4 - graphql-elasticsearch-transformer@4.11.4 - graphql-function-transformer@2.5.4 - graphql-http-transformer@4.17.4 - graphql-key-transformer@2.23.4 - graphql-predictions-transformer@2.5.4 - graphql-transformer-core@6.28.4 - graphql-transformers-e2e-tests@6.23.4 - graphql-versioned-transformer@4.17.4 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d69be55d19..7d4289a9e9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8b503ca0b6..06539e59df 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.3", + "version": "2.31.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.20.1", + "amplify-cli-core": "1.21.0", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.1", - "graphql-transformer-core": "6.28.3", + "graphql-transformer-core": "6.28.4", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From d93928c307fabcd94602b203111befe778272dc6 Mon Sep 17 00:00:00 2001 From: cjihrig Date: Mon, 3 May 2021 15:52:31 -0400 Subject: [PATCH 416/587] Publish - amplify-app@2.23.4 - amplify-appsync-simulator@1.26.3 - amplify-category-analytics@2.21.5 - amplify-category-api@2.31.5 - amplify-category-auth@2.30.5 - amplify-category-function@2.31.5 - amplify-category-hosting@2.7.5 - amplify-category-predictions@2.8.5 - amplify-category-storage@2.11.5 - amplify-category-xr@2.8.5 - amplify-cli-core@1.21.1 - @aws-amplify/cli@4.50.1 - amplify-console-hosting@1.8.5 - amplify-console-integration-tests@1.5.5 - amplify-container-hosting@1.3.5 - amplify-dotnet-function-runtime-provider@1.5.3 - amplify-dotnet-function-template-provider@1.5.5 - amplify-dynamodb-simulator@1.18.5 - amplify-e2e-core@1.18.1 - amplify-e2e-tests@2.39.1 - amplify-frontend-android@2.15.2 - amplify-frontend-flutter@0.4.2 - amplify-frontend-ios@2.19.5 - amplify-frontend-javascript@2.21.5 - amplify-go-function-runtime-provider@1.7.5 - amplify-go-function-template-provider@1.3.6 - amplify-graphiql-explorer@1.5.0 - amplify-graphql-docs-generator@2.2.2 - @aws-amplify/graphql-function-transformer@0.2.0 - @aws-amplify/graphql-http-transformer@0.2.0 - @aws-amplify/graphql-model-transformer@0.3.5 - @aws-amplify/graphql-transformer-core@0.4.0 - @aws-amplify/graphql-transformer-interfaces@1.4.0 - amplify-graphql-types-generator@2.8.2 - amplify-java-function-runtime-provider@1.7.5 - amplify-migration-tests@2.21.5 - amplify-nodejs-function-runtime-provider@1.5.4 - amplify-nodejs-function-template-provider@1.6.5 - amplify-provider-awscloudformation@4.46.0 - amplify-python-function-runtime-provider@1.7.5 - amplify-python-function-template-provider@1.3.8 - amplify-util-import@1.4.5 - amplify-util-mock@3.30.5 - graphql-auth-transformer@6.24.5 - graphql-connection-transformer@4.21.5 - graphql-dynamodb-transformer@6.22.5 - graphql-elasticsearch-transformer@4.11.5 - graphql-function-transformer@2.5.5 - graphql-http-transformer@4.17.5 - graphql-key-transformer@2.23.5 - graphql-predictions-transformer@2.5.5 - graphql-relational-schema-transformer@2.17.2 - graphql-transformer-common@4.19.2 - graphql-transformer-core@6.28.5 - graphql-transformers-e2e-tests@6.23.5 - graphql-versioned-transformer@4.17.5 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7d4289a9e9..55ff80435a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 06539e59df..b907edbfef 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.4", + "version": "2.31.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.21.0", + "amplify-cli-core": "1.21.1", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.17.1", - "graphql-transformer-core": "6.28.4", + "graphql-relational-schema-transformer": "2.17.2", + "graphql-transformer-core": "6.28.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 1fed9f1332a4353b0948151f776bf3409c7011d6 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 3 May 2021 22:01:18 +0000 Subject: [PATCH 417/587] chore(release): Publish [ci skip] - amplify-app@2.23.5 - amplify-appsync-simulator@1.26.4 - amplify-category-analytics@2.21.6 - amplify-category-api@2.31.6 - amplify-category-auth@2.30.6 - amplify-category-function@2.31.6 - amplify-category-hosting@2.7.6 - amplify-category-predictions@2.8.6 - amplify-category-storage@2.11.6 - amplify-category-xr@2.8.6 - amplify-cli-core@1.21.2 - @aws-amplify/cli@4.50.2 - amplify-console-hosting@1.8.6 - amplify-console-integration-tests@1.5.6 - amplify-container-hosting@1.3.6 - amplify-dotnet-function-runtime-provider@1.5.4 - amplify-dotnet-function-template-provider@1.5.6 - amplify-dynamodb-simulator@1.18.6 - amplify-e2e-core@1.18.2 - amplify-e2e-tests@2.39.2 - amplify-frontend-android@2.15.3 - amplify-frontend-flutter@0.4.3 - amplify-frontend-ios@2.19.6 - amplify-frontend-javascript@2.21.6 - amplify-go-function-runtime-provider@1.7.6 - amplify-go-function-template-provider@1.3.7 - amplify-graphiql-explorer@1.6.0 - amplify-graphql-docs-generator@2.2.3 - @aws-amplify/graphql-function-transformer@0.3.0 - @aws-amplify/graphql-http-transformer@0.3.0 - @aws-amplify/graphql-model-transformer@0.3.6 - @aws-amplify/graphql-transformer-core@0.5.0 - @aws-amplify/graphql-transformer-interfaces@1.5.0 - amplify-graphql-types-generator@2.8.3 - amplify-java-function-runtime-provider@1.7.6 - amplify-migration-tests@2.21.6 - amplify-nodejs-function-runtime-provider@1.5.5 - amplify-nodejs-function-template-provider@1.6.6 - amplify-provider-awscloudformation@4.47.0 - amplify-python-function-runtime-provider@1.7.6 - amplify-python-function-template-provider@1.3.9 - amplify-util-import@1.4.6 - amplify-util-mock@3.30.6 - graphql-auth-transformer@6.24.6 - graphql-connection-transformer@4.21.6 - graphql-dynamodb-transformer@6.22.6 - graphql-elasticsearch-transformer@4.11.6 - graphql-function-transformer@2.5.6 - graphql-http-transformer@4.17.6 - graphql-key-transformer@2.23.6 - graphql-predictions-transformer@2.5.6 - graphql-relational-schema-transformer@2.17.3 - graphql-transformer-common@4.19.3 - graphql-transformer-core@6.28.6 - graphql-transformers-e2e-tests@6.23.6 - graphql-versioned-transformer@4.17.6 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 55ff80435a..a51e4c3f31 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b907edbfef..e6dc4803cb 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.5", + "version": "2.31.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.21.1", + "amplify-cli-core": "1.21.2", "amplify-util-headless-input": "1.4.3", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.17.2", - "graphql-transformer-core": "6.28.5", + "graphql-relational-schema-transformer": "2.17.3", + "graphql-transformer-core": "6.28.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 2ef548d6991e1d08d7d670013e4e1f6b6201174c Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Wed, 5 May 2021 06:17:52 -0700 Subject: [PATCH 418/587] fix: carry existing container secret config over (#7224) When a customer selected "don't update secrets" when deploying changes to a containers resource, the existing secrets config was removed rather than retained. This change adds logic to parse the existing secret config and apply it to the updated template --- .../set-existing-secret-arns.test.ts | 60 +++++++++++++++++++ .../utils/containers-artifacts.ts | 14 ++++- .../containers/set-existing-secret-arns.ts | 42 +++++++++++++ 3 files changed, 113 insertions(+), 3 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts 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 new file mode 100644 index 0000000000..63a0ccbbd4 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.test.ts @@ -0,0 +1,60 @@ +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/provider-utils/awscloudformation/utils/containers-artifacts.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers-artifacts.ts index 1aba546cae..c33ca68fbf 100644 --- 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 @@ -9,8 +9,12 @@ 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 { JSONUtilities } from 'amplify-cli-core'; +import { JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; +import { setExistingSecretArns } from './containers/set-existing-secret-arns'; +import { category } from '../../../category-constants'; + +export const cfnFileName = (resourceName: string) => `${resourceName}-cloudformation-template.json`; export type ApiResource = { category: string; @@ -106,8 +110,7 @@ export async function generateContainersArtifacts( const cfn = stack.toCloudFormation(); - const cfnFileName = `${resourceName}-cloudformation-template.json`; - JSONUtilities.writeJson(path.normalize(path.join(resourceDir, cfnFileName)), cfn); + JSONUtilities.writeJson(path.normalize(path.join(resourceDir, cfnFileName(resourceName))), cfn); return { exposedContainer, @@ -286,6 +289,11 @@ export async function processDockerConfig(context: any, resource: ApiResource, s secretsArns.set(secretName, secretArn); } + } else { + const { cfnTemplate } = await 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) 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 new file mode 100644 index 0000000000..e425a26da5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/containers/set-existing-secret-arns.ts @@ -0,0 +1,42 @@ +import { $TSAny } from 'amplify-cli-core'; +import _ from 'lodash'; +/** + * 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: $TSAny) => { + if (_.isEmpty(cfnObj)) { + return; + } + const taskDef = Object.values(cfnObj?.Resources) // get all the resources + .find((value: $TSAny) => value?.Type === 'AWS::ECS::TaskDefinition') as $TSAny; // find the task definition + const containerDefs = taskDef?.Properties?.ContainerDefinitions as $TSAny[]; // 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 => secretsMap.set(secretDef.Name, secretDef.ValueFrom)); // add it to the secretsMap map +}; From 44f7c028073076c1ab1b32d579724d44d510c714 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Wed, 5 May 2021 10:50:57 -0400 Subject: [PATCH 419/587] fix: conditionally rebuild container apis on push (#7175) This commit adds logic to rebuild container based APIs during push if necessary. Refs: https://github.com/aws-amplify/amplify-cli/issues/6684 Co-authored-by: Colin Ihrig --- packages/amplify-category-api/src/index.ts | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 88591e6da9..af7f162501 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -4,12 +4,16 @@ import path from 'path'; import { run } from './commands/api/console'; import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler'; -export { NETWORK_STACK_LOGICAL_ID } from './category-constants' +export { NETWORK_STACK_LOGICAL_ID } from './category-constants'; export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack'; export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; export { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; -export { generateContainersArtifacts, ApiResource, processDockerConfig } from './provider-utils/awscloudformation/utils/containers-artifacts'; +export { + generateContainersArtifacts, + ApiResource, + processDockerConfig, +} from './provider-utils/awscloudformation/utils/containers-artifacts'; export { getContainers } from './provider-utils/awscloudformation/docker-compose'; const category = 'api'; From e79c26225b67760d23bafb315507339dcca781da Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 7 May 2021 08:18:06 -0700 Subject: [PATCH 420/587] fix: update overlapping REST path warning (#7276) Update warning message when creating overlapping REST API paths --- .../awscloudformation/service-walkthroughs/apigw-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index cfaddf7b33..c488f48717 100644 --- 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 @@ -469,7 +469,7 @@ async function askPaths(context, answers, currentPath) { await inquirer.prompt({ name: 'isOverlappingPathOK', type: 'confirm', - message: `This path ${lowerOrderPath} is overlapping with ${higherOrderPath}. ${higherOrderPath} is going to catch all requests from ${lowerOrderPath}. Are you sure you want to continue?`, + message: `The path ${lowerOrderPath} overlaps with ${higherOrderPath}. Users authorized to access ${higherOrderPath} will also have access to ${lowerOrderPath}. Are you sure you want to continue?`, default: false, }) ).isOverlappingPathOK; From 7c4536a1c4525a91e18688596081e9ed8dce930b Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 14 May 2021 02:43:00 +0000 Subject: [PATCH 421/587] chore(release): Publish [ci skip] - amplify-app@2.24.0 - amplify-category-analytics@2.21.7 - amplify-category-api@2.31.7 - amplify-category-auth@2.31.0 - amplify-category-function@2.31.7 - amplify-category-hosting@2.7.7 - amplify-category-predictions@2.8.7 - amplify-category-storage@2.11.7 - amplify-category-xr@2.8.7 - amplify-cli-core@1.22.0 - @aws-amplify/cli@4.51.0 - amplify-console-hosting@1.8.7 - amplify-console-integration-tests@1.6.0 - amplify-container-hosting@1.3.7 - amplify-dotnet-function-template-provider@1.5.7 - amplify-dynamodb-simulator@1.18.7 - amplify-e2e-core@1.19.0 - amplify-e2e-tests@2.40.0 - amplify-frontend-ios@2.20.0 - amplify-frontend-javascript@2.22.0 - amplify-go-function-runtime-provider@1.8.0 - amplify-graphql-docs-generator@2.2.4 - amplify-headless-interface@1.6.0 - amplify-java-function-runtime-provider@1.8.0 - amplify-migration-tests@2.21.7 - amplify-nodejs-function-template-provider@1.6.7 - amplify-provider-awscloudformation@4.48.0 - amplify-python-function-runtime-provider@1.8.0 - amplify-util-headless-input@1.4.4 - amplify-util-import@1.4.7 - amplify-util-mock@3.31.0 - graphql-auth-transformer@6.24.7 - graphql-connection-transformer@4.21.7 - graphql-dynamodb-transformer@6.22.7 - graphql-elasticsearch-transformer@4.11.7 - graphql-function-transformer@2.5.7 - graphql-http-transformer@4.17.7 - graphql-key-transformer@2.23.7 - graphql-predictions-transformer@2.5.7 - graphql-transformer-core@6.28.7 - graphql-transformers-e2e-tests@6.23.7 - graphql-versioned-transformer@4.17.7 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a51e4c3f31..26bd684245 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e6dc4803cb..ac31fc6e5a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.6", + "version": "2.31.7", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.21.2", - "amplify-util-headless-input": "1.4.3", + "amplify-cli-core": "1.22.0", + "amplify-util-headless-input": "1.4.4", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.3", - "graphql-transformer-core": "6.28.6", + "graphql-transformer-core": "6.28.7", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 009ffe64ae3016324dca1529249e9664fd91d434 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Sat, 15 May 2021 12:40:40 -0400 Subject: [PATCH 422/587] fix: make ECR repository name validation more strict (#7337) Co-authored-by: Colin Ihrig --- .../service-walkthroughs/containers-walkthrough.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 199ff52e30..9b38fb744f 100644 --- 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 @@ -69,8 +69,8 @@ async function askResourceName(context, allDefaultValues) { validate: amplify.inputValidation({ validation: { operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric', + value: '^(?:[a-z0-9]+(?:[._-][a-z0-9]+)*/)*[a-z0-9]+(?:[._-][a-z0-9]+)*$', + onErrorMsg: 'Resource name should be alphanumeric with no uppercase letters', }, required: true, }), From 660fc1ae2ef896adddf8e54884f8523c5810c88d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 18 May 2021 17:14:44 +0000 Subject: [PATCH 423/587] chore(release): Publish [ci skip] - amplify-app@2.24.1 - amplify-appsync-simulator@1.26.5 - amplify-category-analytics@2.21.8 - amplify-category-api@2.31.8 - amplify-category-auth@2.31.1 - amplify-category-function@2.31.8 - amplify-category-hosting@2.7.8 - amplify-category-predictions@2.8.8 - amplify-category-storage@2.11.8 - amplify-category-xr@2.8.8 - amplify-cli-core@1.22.1 - @aws-amplify/cli@4.51.1 - amplify-console-hosting@1.8.8 - amplify-console-integration-tests@1.6.1 - amplify-container-hosting@1.3.8 - amplify-dotnet-function-template-provider@1.5.8 - amplify-dynamodb-simulator@1.18.8 - amplify-e2e-core@1.19.1 - amplify-e2e-tests@2.40.1 - amplify-frontend-ios@2.20.1 - amplify-frontend-javascript@2.22.1 - amplify-go-function-runtime-provider@1.8.1 - amplify-graphiql-explorer@1.6.1 - @aws-amplify/graphql-function-transformer@0.3.1 - @aws-amplify/graphql-http-transformer@0.3.1 - @aws-amplify/graphql-model-transformer@0.4.0 - @aws-amplify/graphql-searchable-transformer@0.2.0 - @aws-amplify/graphql-transformer-core@0.6.0 - @aws-amplify/graphql-transformer-interfaces@1.6.0 - amplify-headless-interface@1.6.1 - amplify-java-function-runtime-provider@1.8.1 - amplify-migration-tests@2.21.8 - amplify-nodejs-function-template-provider@1.6.8 - amplify-provider-awscloudformation@4.49.0 - amplify-python-function-runtime-provider@1.8.1 - amplify-util-headless-input@1.4.5 - amplify-util-import@1.4.8 - amplify-util-mock@3.31.1 - graphql-auth-transformer@6.24.8 - graphql-connection-transformer@4.21.8 - graphql-dynamodb-transformer@6.22.8 - graphql-elasticsearch-transformer@4.11.8 - graphql-function-transformer@2.5.8 - graphql-http-transformer@4.17.8 - graphql-key-transformer@2.23.8 - graphql-predictions-transformer@2.5.8 - graphql-transformer-core@6.28.8 - graphql-transformers-e2e-tests@6.23.8 - graphql-versioned-transformer@4.17.8 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 26bd684245..b8d8a4e562 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ac31fc6e5a..d3315af66a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.7", + "version": "2.31.8", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.22.0", - "amplify-util-headless-input": "1.4.4", + "amplify-cli-core": "1.22.1", + "amplify-util-headless-input": "1.4.5", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.3", - "graphql-transformer-core": "6.28.7", + "graphql-transformer-core": "6.28.8", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 881a895c0f69c33ca704a1505d3248e8b89a0b97 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 26 May 2021 20:46:36 +0000 Subject: [PATCH 424/587] chore(release): Publish [ci skip] - amplify-app@2.24.2 - amplify-appsync-simulator@1.26.6 - amplify-category-analytics@2.21.9 - amplify-category-api@2.31.9 - amplify-category-auth@2.32.1 - amplify-category-function@2.31.10 - amplify-category-hosting@2.7.9 - amplify-category-notifications@2.19.2 - amplify-category-predictions@2.8.9 - amplify-category-storage@2.11.9 - amplify-category-xr@2.8.9 - amplify-cli-core@1.22.2 - @aws-amplify/cli@4.51.3 - amplify-console-hosting@1.8.9 - amplify-console-integration-tests@1.6.3 - amplify-container-hosting@1.3.9 - amplify-dotnet-function-template-provider@1.5.9 - amplify-dynamodb-simulator@1.18.9 - amplify-e2e-core@1.19.3 - amplify-e2e-tests@2.40.3 - amplify-frontend-ios@2.20.2 - amplify-frontend-javascript@2.22.2 - amplify-go-function-runtime-provider@1.8.2 - @aws-amplify/graphql-function-transformer@0.3.2 - @aws-amplify/graphql-http-transformer@0.3.2 - @aws-amplify/graphql-model-transformer@0.4.1 - @aws-amplify/graphql-searchable-transformer@0.2.1 - @aws-amplify/graphql-transformer-core@0.6.1 - amplify-java-function-runtime-provider@1.8.2 - amplify-java-function-template-provider@1.5.6 - amplify-migration-tests@2.21.10 - amplify-nodejs-function-template-provider@1.6.9 - amplify-provider-awscloudformation@4.50.1 - amplify-python-function-runtime-provider@1.8.2 - amplify-util-import@1.4.9 - amplify-util-mock@3.31.3 - amplify-velocity-template@1.4.5 - graphql-auth-transformer@6.24.9 - graphql-connection-transformer@4.21.9 - graphql-dynamodb-transformer@6.22.9 - graphql-elasticsearch-transformer@4.11.9 - graphql-function-transformer@2.5.9 - graphql-http-transformer@4.17.9 - graphql-key-transformer@2.23.9 - graphql-predictions-transformer@2.5.9 - graphql-transformer-core@6.28.9 - graphql-transformers-e2e-tests@6.23.9 - graphql-versioned-transformer@4.17.9 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index b8d8a4e562..46dee05015 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d3315af66a..eab4d11530 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.8", + "version": "2.31.9", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.22.1", + "amplify-cli-core": "1.22.2", "amplify-util-headless-input": "1.4.5", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.17.3", - "graphql-transformer-core": "6.28.8", + "graphql-transformer-core": "6.28.9", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 94a77f5c66aae2645e7cd891276ee6730384b019 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 2 Jun 2021 02:09:23 +0000 Subject: [PATCH 425/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@1.27.0 - amplify-category-api@2.31.10 - amplify-category-auth@2.33.0 - amplify-category-predictions@2.9.0 - amplify-category-storage@2.11.10 - @aws-amplify/cli@4.52.0 - amplify-console-hosting@1.9.0 - amplify-console-integration-tests@1.7.0 - amplify-container-hosting@1.3.10 - amplify-dynamodb-simulator@1.19.0 - amplify-e2e-tests@2.41.0 - amplify-migration-tests@2.22.0 - amplify-provider-awscloudformation@4.51.0 - amplify-storage-simulator@1.6.0 - amplify-util-import@1.5.0 - amplify-util-mock@3.32.0 - graphql-relational-schema-transformer@2.18.0 - graphql-transformers-e2e-tests@6.24.0 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 46dee05015..38f84e4c6d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index eab4d11530..d588b68849 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.9", + "version": "2.31.10", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -68,7 +68,7 @@ "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.17.3", + "graphql-relational-schema-transformer": "2.18.0", "graphql-transformer-core": "6.28.9", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", From f308299654ecf8bcc9269ab27a64e767b4a9cebc Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 15 Jun 2021 20:51:46 +0000 Subject: [PATCH 426/587] chore(release): Publish [ci skip] - amplify-app@3.0.0 - amplify-category-analytics@2.21.10 - amplify-category-api@2.31.11 - amplify-category-auth@2.33.1 - amplify-category-function@2.32.0 - amplify-category-hosting@2.7.10 - amplify-category-predictions@2.9.1 - amplify-category-storage@2.11.11 - amplify-category-xr@2.8.10 - amplify-cli-core@1.23.0 - @aws-amplify/cli@5.0.0 - amplify-console-hosting@1.9.1 - amplify-console-integration-tests@1.7.1 - amplify-container-hosting@1.3.11 - amplify-dotnet-function-runtime-provider@1.6.0 - amplify-dotnet-function-template-provider@1.5.10 - amplify-dynamodb-simulator@1.19.1 - amplify-e2e-core@1.20.0 - amplify-e2e-tests@2.42.0 - amplify-frontend-ios@2.20.3 - amplify-frontend-javascript@2.22.3 - amplify-function-plugin-interface@1.8.0 - amplify-go-function-runtime-provider@1.8.3 - amplify-go-function-template-provider@1.3.8 - amplify-java-function-runtime-provider@1.8.3 - amplify-java-function-template-provider@1.5.7 - amplify-migration-tests@3.0.0 - amplify-nodejs-function-runtime-provider@1.6.0 - amplify-nodejs-function-template-provider@1.6.10 - amplify-provider-awscloudformation@4.52.0 - amplify-python-function-runtime-provider@1.9.0 - amplify-python-function-template-provider@1.3.10 - amplify-util-import@1.5.1 - amplify-util-mock@3.33.0 - graphql-auth-transformer@6.24.11 - graphql-connection-transformer@4.21.11 - graphql-dynamodb-transformer@6.22.11 - graphql-elasticsearch-transformer@4.11.11 - graphql-function-transformer@2.5.10 - graphql-http-transformer@4.17.10 - graphql-key-transformer@2.23.11 - graphql-predictions-transformer@2.5.10 - graphql-transformer-core@6.28.10 - graphql-transformers-e2e-tests@6.24.1 - graphql-versioned-transformer@4.17.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 38f84e4c6d..352755de53 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d588b68849..2f3c5a39e4 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.10", + "version": "2.31.11", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.22.2", + "amplify-cli-core": "1.23.0", "amplify-util-headless-input": "1.4.5", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.0", - "graphql-transformer-core": "6.28.9", + "graphql-transformer-core": "6.28.10", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 28f9bc617ccfeebe99329a3daf744c21515ec1cb Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Mon, 21 Jun 2021 18:12:20 -0400 Subject: [PATCH 427/587] fix: support adding REST API paths in 'add api' (#7229) --- .../src/commands/api/add.js | 33 ++++++++++++++++++- .../provider-utils/awscloudformation/index.ts | 3 +- .../service-walkthroughs/apigw-walkthrough.ts | 7 ++++ 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js index 21ccf2a4f6..d883208b45 100644 --- a/packages/amplify-category-api/src/commands/api/add.js +++ b/packages/amplify-category-api/src/commands/api/add.js @@ -1,5 +1,7 @@ +const inquirer = require('inquirer'); const subcommand = 'add'; const category = 'api'; +const apiGatewayService = 'API Gateway'; let options; @@ -10,7 +12,7 @@ module.exports = { const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; return amplify .serviceSelectionPrompt(context, category, servicesMetadata) - .then(result => { + .then(async result => { options = { service: result.service, providerPlugin: result.providerName, @@ -21,6 +23,10 @@ module.exports = { return; } + if ((await shouldUpdateExistingRestApi(context, result.service)) === true) { + return providerController.updateResource(context, category, result.service, { allowContainers: false }); + } + return providerController.addResource(context, category, result.service, options); }) .then(resourceName => { @@ -42,3 +48,28 @@ module.exports = { }); }, }; + +async function shouldUpdateExistingRestApi(context, selectedService) { + if (selectedService !== apiGatewayService) { + return false; + } + + const { allResources } = await context.amplify.getResourceStatus(); + const hasRestApis = allResources.some(resource => resource.service === apiGatewayService && resource.mobileHubMigrated !== true); + + if (!hasRestApis) { + return false; + } + + const question = [ + { + name: 'update', + message: 'Would you like to add a new path to an existing REST API:', + type: 'confirm', + default: true, + }, + ]; + const answer = await inquirer.prompt(question); + + return answer.update; +} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index 556d3dd76c..4ee7ce6fee 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -136,9 +136,10 @@ async function isRestContainer(context) { } export async function updateResource(context, category, service, options) { + const allowContainers = options?.allowContainers ?? true; let useContainerResource = false; let apiType = API_TYPE.GRAPHQL; - if (isContainersEnabled(context)) { + if (allowContainers && isContainersEnabled(context)) { const { hasAPIGatewayContainerResource, hasAPIGatewayLambdaResource, 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 index c488f48717..2b31cf0d1c 100644 --- 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 @@ -66,6 +66,7 @@ export async function updateWalkthrough(context, defaultValuesFilename) { name: 'operation', message: 'What would you like to do', type: 'list', + when: context.input.command !== 'add', choices: [ { name: 'Add another path', value: 'add' }, { name: 'Update path', value: 'update' }, @@ -76,6 +77,12 @@ export async function updateWalkthrough(context, defaultValuesFilename) { const updateApi = await inquirer.prompt(question); + // 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') { + updateApi.operation = 'add'; + } + if (updateApi.resourceName === 'AdminQueries') { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; context.print.warning(errMessage); From 9db4b2e6c8573066aa3d4c1973508640a6cccdd3 Mon Sep 17 00:00:00 2001 From: John Corser Date: Mon, 21 Jun 2021 18:15:45 -0400 Subject: [PATCH 428/587] fix(graphql-transformer-common): improve generated graphql pluralization (#7258) This commit adds the `pluralize` npm library instead of blindly appending an "s" to acheive pluralization. For example, a model named "Match" should pluralize to "Matches", but before this commit Amplify would pluralize it to "Matchs" fix #4224 --- .../src/commands/api/add-graphql-datasource.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 957fdce03e..415da07562 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -5,8 +5,7 @@ const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); - +const { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; @@ -143,7 +142,11 @@ module.exports = { context[rdsResourceName] = resourceName; context[rdsDatasource] = datasource; let template = templateGenerator.createTemplate(context); - template = templateGenerator.addRelationalResolvers(template, resolversDir); + template = templateGenerator.addRelationalResolvers( + template, + resolversDir, + FeatureFlags.getBoolean('graphqltransformer.improvePluralization'), + ); const cfn = templateGenerator.printCloudformationTemplate(template); /** From aab1bf3e697f5017958e5b87a3f7a32f96ac8747 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Tue, 22 Jun 2021 10:58:10 -0700 Subject: [PATCH 429/587] Revert "fix(graphql-transformer-common): improve generated graphql pluralization (#7258)" (#7578) --- .../src/commands/api/add-graphql-datasource.js | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 415da07562..957fdce03e 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -5,7 +5,8 @@ const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); +const { ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); + const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; @@ -142,11 +143,7 @@ module.exports = { context[rdsResourceName] = resourceName; context[rdsDatasource] = datasource; let template = templateGenerator.createTemplate(context); - template = templateGenerator.addRelationalResolvers( - template, - resolversDir, - FeatureFlags.getBoolean('graphqltransformer.improvePluralization'), - ); + template = templateGenerator.addRelationalResolvers(template, resolversDir); const cfn = templateGenerator.printCloudformationTemplate(template); /** From a6ddc415c172eec3ffeade0149672fdd4418aa23 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 24 Jun 2021 18:32:53 +0000 Subject: [PATCH 430/587] chore(release): Publish [ci skip] - amplify-app@3.0.1 - amplify-appsync-simulator@1.27.1 - amplify-category-analytics@2.21.11 - amplify-category-api@2.31.12 - amplify-category-auth@2.34.0 - amplify-category-function@2.32.2 - amplify-category-hosting@2.7.11 - amplify-category-notifications@2.19.3 - amplify-category-predictions@2.9.2 - amplify-category-storage@2.11.12 - amplify-category-xr@2.8.11 - amplify-cli-core@1.23.1 - @aws-amplify/cli@5.0.2 - amplify-console-hosting@1.9.2 - amplify-console-integration-tests@1.7.2 - amplify-container-hosting@1.3.12 - amplify-dotnet-function-template-provider@1.5.11 - amplify-dynamodb-simulator@1.19.2 - amplify-e2e-core@1.21.0 - amplify-e2e-tests@2.43.0 - amplify-frontend-ios@2.20.4 - amplify-frontend-javascript@2.22.4 - amplify-go-function-runtime-provider@1.8.4 - @aws-amplify/graphql-function-transformer@0.3.3 - @aws-amplify/graphql-http-transformer@0.3.3 - @aws-amplify/graphql-model-transformer@0.4.2 - @aws-amplify/graphql-searchable-transformer@0.2.2 - @aws-amplify/graphql-transformer-core@0.6.2 - @aws-amplify/graphql-transformer-interfaces@1.6.1 - amplify-headless-interface@1.7.0 - amplify-java-function-runtime-provider@1.8.4 - amplify-migration-tests@3.0.1 - amplify-nodejs-function-runtime-provider@1.6.1 - amplify-nodejs-function-template-provider@1.6.11 - amplify-provider-awscloudformation@4.53.0 - amplify-python-function-runtime-provider@1.9.1 - amplify-util-headless-input@1.5.0 - amplify-util-import@1.5.2 - amplify-util-mock@3.33.2 - graphql-auth-transformer@6.24.12 - graphql-connection-transformer@4.21.12 - graphql-dynamodb-transformer@6.22.12 - graphql-elasticsearch-transformer@4.11.12 - graphql-function-transformer@2.5.11 - graphql-http-transformer@4.17.11 - graphql-key-transformer@2.23.12 - graphql-predictions-transformer@2.5.11 - graphql-transformer-core@6.28.11 - graphql-transformers-e2e-tests@6.24.2 - graphql-versioned-transformer@4.17.12 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 352755de53..0090bd27e9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 2f3c5a39e4..61e2015f3f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.11", + "version": "2.31.12", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.23.0", - "amplify-util-headless-input": "1.4.5", + "amplify-cli-core": "1.23.1", + "amplify-util-headless-input": "1.5.0", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.0", - "graphql-transformer-core": "6.28.10", + "graphql-transformer-core": "6.28.11", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 9f5873fed7e2c0a594ca3239ee55152e44291f67 Mon Sep 17 00:00:00 2001 From: John Corser Date: Thu, 24 Jun 2021 19:01:25 -0400 Subject: [PATCH 431/587] Fix e2e tests for pluralization (#7590) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Currently, we’re testing the iterative update by renaming the intial Todo model and updating it to Todos. Previously, this created a resolver called listTodoss (because it incorrectly blindly appended s). With the pluralization fix, it creates a resolver called listTodos - which unfortunately already exists and therefore appsync throws a Only one resolver is allowed per field error (https://github.com/aws/aws-appsync-community/issues/128) --- .../src/commands/api/add-graphql-datasource.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js index 957fdce03e..415da07562 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js @@ -5,8 +5,7 @@ const path = require('path'); const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); - +const { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; @@ -143,7 +142,11 @@ module.exports = { context[rdsResourceName] = resourceName; context[rdsDatasource] = datasource; let template = templateGenerator.createTemplate(context); - template = templateGenerator.addRelationalResolvers(template, resolversDir); + template = templateGenerator.addRelationalResolvers( + template, + resolversDir, + FeatureFlags.getBoolean('graphqltransformer.improvePluralization'), + ); const cfn = templateGenerator.printCloudformationTemplate(template); /** From 7900ba398cf585e5a5c4105f3dca91b0a60625a2 Mon Sep 17 00:00:00 2001 From: John Corser Date: Thu, 24 Jun 2021 19:21:26 -0400 Subject: [PATCH 432/587] fix: api resource name case sensitivity failure (#7452) --- .../utils/check-case-sensitivity.test.ts | 32 +++++++++++++++++++ .../cfn-api-artifact-handler.ts | 4 +++ .../awscloudformation/legacy-add-resource.ts | 4 +++ .../utils/check-case-sensitivity.ts | 21 ++++++++++++ 4 files changed, 61 insertions(+) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts new file mode 100644 index 0000000000..aa63c8d038 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts @@ -0,0 +1,32 @@ +import fs from 'fs-extra'; +import { checkCaseSensitivityIssue } from '../../../../provider-utils/awscloudformation/utils/check-case-sensitivity'; + +const mockExit = jest.spyOn(process, 'exit').mockImplementation(); +jest.spyOn(fs, 'readdir').mockImplementation(_ => new Promise(resolve => resolve(['testBlog', 'testblogcasesensitivefs']))); + +const contextStub = { + amplify: { + pathManager: { + getBackendDirPath: jest.fn(_ => 'mock/backend/path'), + }, + }, + print: { + error: jest.fn(), + }, +}; + +test('conflict does not exist if the name matches exactly', async () => { + await checkCaseSensitivityIssue(contextStub, 'api', 'testBlog'); + expect(mockExit).toBeCalledTimes(0); +}); + +test('conflict does not exist if names do not match whatsoever', async () => { + await checkCaseSensitivityIssue(contextStub, 'api', 'newname'); + expect(mockExit).toBeCalledTimes(0); +}); + +test('conflict exists if names are different by case only', async () => { + await checkCaseSensitivityIssue(contextStub, 'api', 'testblog'); + expect(mockExit).toBeCalledTimes(1); + mockExit.mockRestore(); +}); 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 index 8532ec14ed..4b8bf60a13 100644 --- 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 @@ -17,6 +17,7 @@ import uuid from 'uuid'; import _ from 'lodash'; import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from './utils/amplify-meta-utils'; import { printApiKeyWarnings } from './utils/print-api-key-warnings'; +import { checkCaseSensitivityIssue } from './utils/check-case-sensitivity'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -48,6 +49,9 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { throw new Error(`GraphQL API ${existingApiName} already exists in the project. Use 'amplify update api' to make modifications.`); } const serviceConfig = request.serviceConfiguration; + + checkCaseSensitivityIssue(this.context, 'api', serviceConfig.apiName); + const resourceDir = this.getResourceDir(serviceConfig.apiName); // Ensure the project directory exists and create the stacks & resolvers directories. 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 index fe756c786f..03a211e01b 100644 --- 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 @@ -1,5 +1,6 @@ import { JSONUtilities } from 'amplify-cli-core'; import { serviceMetadataFor } from './utils/dynamic-imports'; +import { checkCaseSensitivityIssue } from './utils/check-case-sensitivity'; import fs from 'fs-extra'; import path from 'path'; import { parametersFileName, cfnParametersFilename, rootAssetDir } from './aws-constants'; @@ -31,6 +32,9 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, const parameters = { ...answers }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + + checkCaseSensitivityIssue(context, category, parameters.resourceName); + fs.ensureDirSync(resourceDirPath); const parametersFilePath = path.join(resourceDirPath, parametersFileName); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts new file mode 100644 index 0000000000..2da10989f4 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts @@ -0,0 +1,21 @@ +import fs from 'fs-extra'; +import path from 'path'; + +export const checkCaseSensitivityIssue = async (context: any, category: string, resourceName: string) => { + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + + const caseSensitivityConflict = async () => { + const basePath = path.join(projectBackendDirPath, category); + const filenames = await fs.readdir(basePath); + const lowerCaseMatch = filenames.find(name => name.toLowerCase() === resourceName.toLowerCase()); + return lowerCaseMatch === resourceName ? false : lowerCaseMatch; + }; + + const conflict = await caseSensitivityConflict(); + if (conflict) { + context.print.error( + `Unable to create resource with name ${resourceName} since a resource named ${conflict} already exists. Amplify resource names are case-insensitive.`, + ); + process.exit(1); + } +}; From d8eade3be250eb41ea167f4c6aab9eaca9524ecb Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 25 Jun 2021 12:21:49 -0700 Subject: [PATCH 433/587] fix: unique api name check works when no existing apis (#7615) --- .../cfn-api-artifact-handler.ts | 4 +-- .../awscloudformation/legacy-add-resource.ts | 4 +-- .../service-walkthroughs/apigw-walkthrough.ts | 23 ++++++++------ .../utils/check-case-sensitivity.ts | 30 ++++++++----------- 4 files changed, 30 insertions(+), 31 deletions(-) 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 index 4b8bf60a13..0b4a49a2a7 100644 --- 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 @@ -17,7 +17,7 @@ import uuid from 'uuid'; import _ from 'lodash'; import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from './utils/amplify-meta-utils'; import { printApiKeyWarnings } from './utils/print-api-key-warnings'; -import { checkCaseSensitivityIssue } from './utils/check-case-sensitivity'; +import { isNameUnique } from './utils/check-case-sensitivity'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -50,7 +50,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { } const serviceConfig = request.serviceConfiguration; - checkCaseSensitivityIssue(this.context, 'api', serviceConfig.apiName); + isNameUnique('api', serviceConfig.apiName); const resourceDir = this.getResourceDir(serviceConfig.apiName); 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 index 03a211e01b..ba3089e483 100644 --- 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 @@ -1,6 +1,6 @@ import { JSONUtilities } from 'amplify-cli-core'; import { serviceMetadataFor } from './utils/dynamic-imports'; -import { checkCaseSensitivityIssue } from './utils/check-case-sensitivity'; +import { isNameUnique } from './utils/check-case-sensitivity'; import fs from 'fs-extra'; import path from 'path'; import { parametersFileName, cfnParametersFilename, rootAssetDir } from './aws-constants'; @@ -33,7 +33,7 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, const parameters = { ...answers }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); - checkCaseSensitivityIssue(context, category, parameters.resourceName); + isNameUnique(category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); 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 index 2b31cf0d1c..3c19b13ca1 100644 --- 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 @@ -6,6 +6,7 @@ import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; import { ResourceDoesNotExistError, exitOnNextTick, $TSContext, stateManager, open } from 'amplify-cli-core'; +import { isNameUnique } from '../utils/check-case-sensitivity'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -183,21 +184,25 @@ async function pathFlow(context, answers, currentPath?) { async function askApiNames(context, defaults) { const { amplify } = context; - // TODO: Check if default name is already taken + const apiNameValidator = (input: string) => { + const amplifyValidatorOutput = amplify.inputValidation({ + validation: { + operator: 'regex', + value: '^[a-zA-Z0-9]+$', + onErrorMsg: 'Resource name should be alphanumeric', + }, + required: true, + })(input); + const uniqueCheck = isNameUnique(category, input, false); + return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : typeof uniqueCheck === 'string' ? uniqueCheck : true; + }; const answer: { apiName?: string; resourceName: string } = 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: defaults.resourceName, - validate: amplify.inputValidation({ - validation: { - operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'Resource name should be alphanumeric', - }, - required: true, - }), + validate: apiNameValidator, }, ]); diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts index 2da10989f4..4bbf478a68 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts @@ -1,21 +1,15 @@ -import fs from 'fs-extra'; -import path from 'path'; +import { stateManager } from 'amplify-cli-core'; -export const checkCaseSensitivityIssue = async (context: any, category: string, resourceName: string) => { - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - - const caseSensitivityConflict = async () => { - const basePath = path.join(projectBackendDirPath, category); - const filenames = await fs.readdir(basePath); - const lowerCaseMatch = filenames.find(name => name.toLowerCase() === resourceName.toLowerCase()); - return lowerCaseMatch === resourceName ? false : lowerCaseMatch; - }; - - const conflict = await caseSensitivityConflict(); - if (conflict) { - context.print.error( - `Unable to create resource with name ${resourceName} since a resource named ${conflict} already exists. Amplify resource names are case-insensitive.`, - ); - process.exit(1); +export const isNameUnique = (category: string, resourceName: string, throwOnMatch = true) => { + const resourceNames = Object.keys(stateManager.getMeta()?.[category] || {}); + const matchIdx = resourceNames.map(name => name.toLowerCase()).indexOf(resourceName.toLowerCase()); + if (matchIdx === -1) { + return true; + } + const msg = `A resource named ${resourceNames[matchIdx]} already exists. Amplify resource names must be unique and are case-insensitive.`; + if (throwOnMatch) { + throw new Error(msg); + } else { + return msg; } }; From 7ed725ea6d8a2bff0f836399fe4578c2cd57aab6 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 25 Jun 2021 14:07:48 -0700 Subject: [PATCH 434/587] test: update tests for api name fix (#7616) --- .../cfn-api-artifact-handler.test.ts | 2 + .../legacy-add-resource.test.ts | 1 + .../utils/check-case-sensitivity.test.ts | 39 +++++++------------ 3 files changed, 18 insertions(+), 24 deletions(-) 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 index 4bd19bfc02..28e2aec71d 100644 --- 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 @@ -28,6 +28,8 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', getImportedAuthUserPoolId: jest.fn(() => undefined), })); +jest.mock('amplify-cli-core'); + const fs_mock = (fs as unknown) as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; 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 index 209e3e13aa..4dc7ed152f 100644 --- 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 @@ -2,6 +2,7 @@ import { legacyAddResource } from '../../../provider-utils/awscloudformation/leg import { category } from '../../../category-constants'; jest.mock('fs-extra'); +jest.mock('amplify-cli-core'); describe('legacy add resource', () => { const contextStub = { diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts index aa63c8d038..b8c81c95af 100644 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts @@ -1,32 +1,23 @@ -import fs from 'fs-extra'; -import { checkCaseSensitivityIssue } from '../../../../provider-utils/awscloudformation/utils/check-case-sensitivity'; +import { isNameUnique } from '../../../../provider-utils/awscloudformation/utils/check-case-sensitivity'; +import { stateManager } from 'amplify-cli-core'; -const mockExit = jest.spyOn(process, 'exit').mockImplementation(); -jest.spyOn(fs, 'readdir').mockImplementation(_ => new Promise(resolve => resolve(['testBlog', 'testblogcasesensitivefs']))); +jest.mock('amplify-cli-core'); -const contextStub = { - amplify: { - pathManager: { - getBackendDirPath: jest.fn(_ => 'mock/backend/path'), - }, - }, - print: { - error: jest.fn(), - }, -}; +const stateManager_mock = stateManager as jest.Mocked; -test('conflict does not exist if the name matches exactly', async () => { - await checkCaseSensitivityIssue(contextStub, 'api', 'testBlog'); - expect(mockExit).toBeCalledTimes(0); +stateManager_mock.getMeta.mockReturnValue({ + api: { + testBlog: {}, + }, }); -test('conflict does not exist if names do not match whatsoever', async () => { - await checkCaseSensitivityIssue(contextStub, 'api', 'newname'); - expect(mockExit).toBeCalledTimes(0); +test('conflict exists if names differ by case only', () => { + expect(() => isNameUnique('api', 'testblog')).toThrowErrorMatchingInlineSnapshot( + `"A resource named testBlog already exists. Amplify resource names must be unique and are case-insensitive."`, + ); }); -test('conflict exists if names are different by case only', async () => { - await checkCaseSensitivityIssue(contextStub, 'api', 'testblog'); - expect(mockExit).toBeCalledTimes(1); - mockExit.mockRestore(); +test('conflict does not exist if names differ by characters', () => { + const result = isNameUnique('api', 'newname'); + expect(result).toBe(true); }); From b8e6f9b0d7f8a83edb437340e17fe3e58eeba71d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 30 Jun 2021 21:31:32 +0000 Subject: [PATCH 435/587] chore(release): Publish [ci skip] - amplify-app@3.0.2 - amplify-category-analytics@2.21.12 - amplify-category-api@2.31.13 - amplify-category-auth@2.34.1 - amplify-category-function@2.33.0 - amplify-category-hosting@2.7.12 - amplify-category-predictions@2.9.3 - amplify-category-storage@2.12.0 - amplify-category-xr@2.8.12 - amplify-cli-core@1.24.0 - @aws-amplify/cli@5.1.0 - amplify-console-hosting@1.9.3 - amplify-console-integration-tests@1.7.3 - amplify-container-hosting@1.3.13 - amplify-dotnet-function-runtime-provider@1.6.1 - amplify-dotnet-function-template-provider@1.5.12 - amplify-dynamodb-simulator@1.19.3 - amplify-e2e-core@1.22.0 - amplify-e2e-tests@2.44.0 - amplify-frontend-ios@2.20.5 - amplify-frontend-javascript@2.22.5 - amplify-function-plugin-interface@1.9.0 - amplify-go-function-runtime-provider@1.8.5 - amplify-go-function-template-provider@1.3.9 - @aws-amplify/graphql-function-transformer@0.3.4 - @aws-amplify/graphql-http-transformer@0.4.0 - @aws-amplify/graphql-model-transformer@0.4.3 - @aws-amplify/graphql-searchable-transformer@0.2.3 - @aws-amplify/graphql-transformer-core@0.6.3 - amplify-java-function-runtime-provider@1.8.5 - amplify-java-function-template-provider@1.5.8 - amplify-migration-tests@3.0.2 - amplify-nodejs-function-runtime-provider@1.6.2 - amplify-nodejs-function-template-provider@1.6.12 - amplify-provider-awscloudformation@4.54.0 - amplify-python-function-runtime-provider@1.9.2 - amplify-python-function-template-provider@1.3.11 - amplify-util-import@1.5.3 - amplify-util-mock@3.33.3 - graphql-auth-transformer@6.24.13 - graphql-connection-transformer@4.21.13 - graphql-dynamodb-transformer@6.22.13 - graphql-elasticsearch-transformer@4.11.13 - graphql-function-transformer@2.5.12 - graphql-http-transformer@4.18.0 - graphql-key-transformer@2.23.13 - graphql-predictions-transformer@2.5.12 - graphql-relational-schema-transformer@2.18.1 - graphql-transformer-common@4.19.4 - graphql-transformer-core@6.28.12 - graphql-transformers-e2e-tests@6.24.3 - graphql-versioned-transformer@4.17.13 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 0090bd27e9..6495b3e09b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 61e2015f3f..c5224f6f77 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.12", + "version": "2.31.13", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.23.1", + "amplify-cli-core": "1.24.0", "amplify-util-headless-input": "1.5.0", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.0", - "graphql-transformer-core": "6.28.11", + "graphql-relational-schema-transformer": "2.18.1", + "graphql-transformer-core": "6.28.12", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 19a7921bbae701f77ef4741d598c4ab3c7297b5a Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 12 Jul 2021 16:47:37 +0000 Subject: [PATCH 436/587] chore(release): Publish [ci skip] - amplify-app@3.0.3 - amplify-appsync-simulator@1.27.2 - amplify-category-api@2.31.14 - amplify-category-auth@2.35.0 - @aws-amplify/cli@5.1.1 - amplify-console-integration-tests@1.8.0 - amplify-container-hosting@1.3.14 - amplify-e2e-core@1.23.0 - amplify-e2e-tests@2.45.0 - amplify-frontend-javascript@2.23.0 - amplify-go-function-runtime-provider@1.8.6 - @aws-amplify/graphql-function-transformer@0.3.5 - @aws-amplify/graphql-http-transformer@0.4.1 - @aws-amplify/graphql-model-transformer@0.4.4 - @aws-amplify/graphql-predictions-transformer@0.2.0 - @aws-amplify/graphql-searchable-transformer@0.3.0 - @aws-amplify/graphql-transformer-core@0.7.0 - @aws-amplify/graphql-transformer-interfaces@1.7.0 - amplify-headless-interface@1.8.0 - amplify-migration-tests@3.1.0 - amplify-provider-awscloudformation@4.55.0 - amplify-util-headless-input@1.5.1 - amplify-util-mock@3.33.4 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6495b3e09b..013c6d1e05 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c5224f6f77..b553bb4f01 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.13", + "version": "2.31.14", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,7 +63,7 @@ "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", "amplify-cli-core": "1.24.0", - "amplify-util-headless-input": "1.5.0", + "amplify-util-headless-input": "1.5.1", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", From bf1505c1b5225c86270bc29c73ba6b38c64ac3ba Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 16 Jul 2021 20:24:40 +0000 Subject: [PATCH 437/587] chore(release): Publish [ci skip] - amplify-app@3.0.4 - amplify-appsync-simulator@1.27.3 - amplify-category-analytics@2.21.13 - amplify-category-api@2.31.15 - amplify-category-auth@2.35.1 - amplify-category-function@2.33.1 - amplify-category-hosting@2.7.13 - amplify-category-notifications@2.19.4 - amplify-category-predictions@2.9.4 - amplify-category-storage@2.12.1 - amplify-category-xr@2.8.13 - amplify-cli-core@1.24.1 - @aws-amplify/cli@5.1.2 - amplify-console-hosting@1.9.4 - amplify-console-integration-tests@1.8.1 - amplify-container-hosting@1.3.15 - amplify-dotnet-function-template-provider@1.5.13 - amplify-dynamodb-simulator@1.19.4 - amplify-e2e-core@1.23.1 - amplify-e2e-tests@2.45.1 - amplify-frontend-ios@2.20.6 - amplify-frontend-javascript@2.23.1 - amplify-go-function-runtime-provider@1.8.7 - @aws-amplify/graphql-function-transformer@0.3.6 - @aws-amplify/graphql-http-transformer@0.4.2 - @aws-amplify/graphql-model-transformer@0.4.5 - @aws-amplify/graphql-predictions-transformer@0.2.1 - @aws-amplify/graphql-searchable-transformer@0.3.1 - @aws-amplify/graphql-transformer-core@0.7.1 - amplify-java-function-runtime-provider@1.8.6 - amplify-migration-tests@3.1.1 - amplify-nodejs-function-runtime-provider@1.6.3 - amplify-nodejs-function-template-provider@1.6.13 - amplify-provider-awscloudformation@4.55.1 - amplify-python-function-runtime-provider@1.9.3 - amplify-util-import@1.5.4 - amplify-util-mock@3.33.5 - graphql-auth-transformer@6.24.14 - graphql-connection-transformer@4.21.14 - graphql-dynamodb-transformer@6.22.14 - graphql-elasticsearch-transformer@4.11.14 - graphql-function-transformer@2.5.13 - graphql-http-transformer@4.18.1 - graphql-key-transformer@2.23.14 - graphql-predictions-transformer@2.5.13 - graphql-relational-schema-transformer@2.18.2 - graphql-transformer-common@4.19.5 - graphql-transformer-core@6.28.13 - graphql-transformers-e2e-tests@6.24.4 - graphql-versioned-transformer@4.17.14 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 013c6d1e05..bc53de57bf 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b553bb4f01..1fe6254e37 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.14", + "version": "2.31.15", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.24.0", + "amplify-cli-core": "1.24.1", "amplify-util-headless-input": "1.5.1", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.1", - "graphql-transformer-core": "6.28.12", + "graphql-relational-schema-transformer": "2.18.2", + "graphql-transformer-core": "6.28.13", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 79d21b936b7780742b698375fa90d43ad6ea5f6d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 27 Jul 2021 20:14:32 +0000 Subject: [PATCH 438/587] chore(release): Publish [ci skip] - amplify-app@3.0.5 - amplify-appsync-simulator@1.27.4 - amplify-category-analytics@2.21.14 - amplify-category-api@2.31.16 - amplify-category-auth@2.36.0 - amplify-category-function@2.34.0 - amplify-category-hosting@2.7.14 - amplify-category-predictions@2.9.5 - amplify-category-storage@2.12.2 - amplify-category-xr@2.8.14 - amplify-cli-core@1.25.0 - @aws-amplify/cli@5.2.0 - amplify-console-hosting@1.9.5 - amplify-console-integration-tests@1.8.2 - amplify-container-hosting@1.3.16 - amplify-dotnet-function-template-provider@1.5.14 - amplify-dynamodb-simulator@1.19.5 - amplify-e2e-core@1.24.0 - amplify-e2e-tests@2.46.0 - amplify-frontend-ios@2.20.7 - amplify-frontend-javascript@2.23.2 - amplify-go-function-runtime-provider@1.8.8 - @aws-amplify/graphql-function-transformer@0.3.7 - @aws-amplify/graphql-http-transformer@0.4.3 - @aws-amplify/graphql-model-transformer@0.4.6 - @aws-amplify/graphql-predictions-transformer@0.2.2 - @aws-amplify/graphql-searchable-transformer@0.3.2 - @aws-amplify/graphql-transformer-core@0.7.2 - amplify-headless-interface@1.9.0 - amplify-java-function-runtime-provider@1.8.7 - amplify-migration-tests@3.1.2 - amplify-nodejs-function-runtime-provider@1.6.4 - amplify-nodejs-function-template-provider@1.6.14 - amplify-provider-awscloudformation@4.55.2 - amplify-python-function-runtime-provider@1.9.4 - amplify-util-headless-input@1.5.2 - amplify-util-import@1.5.5 - amplify-util-mock@3.33.6 - graphql-auth-transformer@6.24.15 - graphql-connection-transformer@4.21.15 - graphql-dynamodb-transformer@6.22.15 - graphql-elasticsearch-transformer@4.11.15 - graphql-function-transformer@2.5.14 - graphql-http-transformer@4.18.2 - graphql-key-transformer@2.23.15 - graphql-predictions-transformer@2.5.14 - graphql-relational-schema-transformer@2.18.3 - graphql-transformer-common@4.19.6 - graphql-transformer-core@6.29.0 - graphql-transformers-e2e-tests@6.24.5 - graphql-versioned-transformer@4.17.15 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index bc53de57bf..d07463b123 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1fe6254e37..843c0e4925 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.15", + "version": "2.31.16", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.24.1", - "amplify-util-headless-input": "1.5.1", + "amplify-cli-core": "1.25.0", + "amplify-util-headless-input": "1.5.2", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.2", - "graphql-transformer-core": "6.28.13", + "graphql-relational-schema-transformer": "2.18.3", + "graphql-transformer-core": "6.29.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 30ed3f4772a0eb321ef106199cb623a083ffd71d Mon Sep 17 00:00:00 2001 From: Michael Brewer Date: Tue, 27 Jul 2021 15:09:48 -0700 Subject: [PATCH 439/587] fix: lambda timeout should be an integer type (#7699) --- .../sync-conflict-handler-template.json.ejs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 0cb2bca1ec..f898077cbd 100644 --- 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 @@ -67,7 +67,7 @@ }, "Role": { "Fn::GetAtt" : ["LambdaExecutionRole", "Arn"] }, "Runtime": "nodejs14.x", - "Timeout": "25" + "Timeout": 25 } }, "LambdaExecutionRole": { From c789d9c1d3953ab32209217c9a28e956fd7ad193 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 30 Jul 2021 00:43:32 +0000 Subject: [PATCH 440/587] chore(release): Publish [ci skip] - amplify-app@3.0.6 - amplify-appsync-simulator@1.27.5 - amplify-category-analytics@2.21.15 - amplify-category-api@2.31.17 - amplify-category-auth@2.36.1 - amplify-category-function@2.34.1 - amplify-category-hosting@2.7.15 - amplify-category-interactions@2.6.3 - amplify-category-predictions@2.9.6 - amplify-category-storage@2.12.3 - amplify-category-xr@2.8.15 - amplify-cli-core@1.25.1 - @aws-amplify/cli@5.2.1 - amplify-console-hosting@1.9.6 - amplify-console-integration-tests@1.8.3 - amplify-container-hosting@1.3.17 - amplify-dotnet-function-runtime-provider@1.6.2 - amplify-dotnet-function-template-provider@1.5.15 - amplify-dynamodb-simulator@1.19.6 - amplify-e2e-core@1.24.1 - amplify-e2e-tests@2.46.1 - amplify-frontend-ios@2.20.8 - amplify-frontend-javascript@2.23.3 - amplify-function-plugin-interface@1.9.1 - amplify-go-function-runtime-provider@1.8.9 - amplify-go-function-template-provider@1.3.10 - @aws-amplify/graphql-function-transformer@0.4.0 - @aws-amplify/graphql-http-transformer@0.5.0 - @aws-amplify/graphql-index-transformer@0.2.0 - @aws-amplify/graphql-model-transformer@0.5.0 - @aws-amplify/graphql-predictions-transformer@0.3.0 - @aws-amplify/graphql-searchable-transformer@0.4.0 - @aws-amplify/graphql-transformer-core@0.8.0 - @aws-amplify/graphql-transformer-interfaces@1.8.0 - amplify-graphql-types-generator@2.8.4 - amplify-java-function-runtime-provider@1.8.8 - amplify-java-function-template-provider@1.5.9 - amplify-migration-tests@3.1.3 - amplify-nodejs-function-runtime-provider@1.6.5 - amplify-nodejs-function-template-provider@1.6.15 - amplify-provider-awscloudformation@4.56.0 - amplify-python-function-runtime-provider@1.9.5 - amplify-python-function-template-provider@1.3.12 - amplify-util-import@1.5.6 - amplify-util-mock@3.33.7 - graphql-auth-transformer@6.24.16 - graphql-connection-transformer@4.21.16 - graphql-dynamodb-transformer@6.22.16 - graphql-elasticsearch-transformer@4.11.16 - graphql-function-transformer@2.5.15 - graphql-http-transformer@4.18.3 - graphql-key-transformer@2.23.16 - graphql-predictions-transformer@2.5.15 - graphql-transformer-core@6.29.1 - graphql-transformers-e2e-tests@6.24.6 - graphql-versioned-transformer@4.17.16 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d07463b123..58632274d5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 843c0e4925..f33c48cc23 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.16", + "version": "2.31.17", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.25.0", + "amplify-cli-core": "1.25.1", "amplify-util-headless-input": "1.5.2", "chalk": "^3.0.0", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.3", - "graphql-transformer-core": "6.29.0", + "graphql-transformer-core": "6.29.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 7ee4c569ffbde53f46d5862ccfaf7b8875f9c1bf Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 30 Jul 2021 15:51:07 -0700 Subject: [PATCH 441/587] chore: update lerna and chalk dependencies, remove unused chalk-pipe (#7823) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f33c48cc23..a6581498ff 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -64,7 +64,7 @@ "@graphql-tools/merge": "^6.0.18", "amplify-cli-core": "1.25.1", "amplify-util-headless-input": "1.5.2", - "chalk": "^3.0.0", + "chalk": "^4.1.1", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", From 0e2edacbde06d2c0b8626c7ed56b675f44f6976d Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Tue, 3 Aug 2021 09:44:20 -0700 Subject: [PATCH 442/587] fix: multi-env container hosting (#7009) (#7346) * fix: #7009 - Bug Fix for Multi-Env Container Hosting * Update packages/amplify-cli/src/initialize-env.ts Co-authored-by: John Hockett * fix: multi-Env container hosting - format fixed * Update to use hosting key from TPI * add domain and restrictAccess to the template * fix lint errors * fix lint errors * add allowed values for restrictAccess * added tests for container based testing * update tests Co-authored-by: John Hockett --- .../provider-utils/awscloudformation/base-api-stack.ts | 8 ++++++++ 1 file changed, 8 insertions(+) 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 index e197d4522e..4b2bc6df8f 100644 --- 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 @@ -133,6 +133,12 @@ export abstract class ContainersStack extends cdk.Stack { // 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' }); + const paramRestrictAccess = new cdk.CfnParameter(this, 'restrictAccess', { + type: 'String', + allowedValues: ['true', 'false'], + }); + const paramZipPath = new cdk.CfnParameter(this, 'ParamZipPath', { type: 'String', // Required only for FULLY_MANAGED @@ -142,6 +148,8 @@ export abstract class ContainersStack extends cdk.Stack { const parameters: Map = new Map(); parameters.set('ParamZipPath', paramZipPath); + parameters.set('domain', paramDomain); + parameters.set('restrictAccess', paramRestrictAccess); const authParams: { UserPoolId?: cdk.CfnParameter; From 165772e6f4e73dd5b8921637a5189576662ba316 Mon Sep 17 00:00:00 2001 From: lazpavel <85319655+lazpavel@users.noreply.github.com> Date: Tue, 3 Aug 2021 15:02:04 -0400 Subject: [PATCH 443/587] fix(graphql-model-transformer): model input fields transform (#7857) * Add .circleci/config.yml * test: ported @model v1 test suite to v2 * chore(graphql-model-transformer): removed improvePluralization check, V2 uses improvePluralization * chore(graphql-model-transformer): added parse() to tests that generate a valid schema * test(graphql-model-transformer): added validateModelSchema check to existing model v2 tests * fix(graphql-model-transformer): fixed @model transform input object fields type Converted fields of input type objects to also be of input type. Small typo fixes. * Add .circleci/config.yml * Add .circleci/config.yml * chore(graphql-model-transformer): removed test for deprecated @model feature flag --- .../awscloudformation/base-api-stack.ts | 918 +++++++++--------- 1 file changed, 457 insertions(+), 461 deletions(-) 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 index 4b2bc6df8f..61030462f8 100644 --- 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 @@ -10,498 +10,494 @@ import * as cdk from '@aws-cdk/core'; import { prepareApp } from '@aws-cdk/core/lib/private/prepare-app'; import { NETWORK_STACK_LOGICAL_ID } from '../../category-constants'; import Container from './docker-compose/ecs-objects/container'; -import { GitHubSourceActionInfo, PipelineWithAwaiter } from "./pipeline-with-awaiter"; +import { GitHubSourceActionInfo, PipelineWithAwaiter } from './pipeline-with-awaiter'; const PIPELINE_AWAITER_ZIP = 'custom-resource-pipeline-awaiter.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', -}; + /** + * 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; - envName: string; - categoryName: string; - apiName: string; - deploymentBucketName: 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; + skipWait?: boolean; + envName: string; + categoryName: string; + apiName: string; + deploymentBucketName: 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; }>; 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; - - constructor(scope: cdk.Construct, id: string, private readonly props: ContainersStackProps) { - super(scope, id); - - const { - parameters, - vpcId, - vpcCidrBlock, - subnets, - clusterName, - zipPath, - cloudMapNamespaceId, - vpcLinkId, - isAuthCondition, - appClientId, - userPoolId, - } = 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; - - 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, - gitHubSourceActionInfo, - }); - - this.pipelineWithAwaiter = pipelineWithAwaiter; + 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; + + constructor(scope: cdk.Construct, id: string, private readonly props: ContainersStackProps) { + super(scope, id); + + const { + parameters, + vpcId, + vpcCidrBlock, + subnets, + clusterName, + zipPath, + cloudMapNamespaceId, + vpcLinkId, + isAuthCondition, + appClientId, + userPoolId, + } = 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; + + 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, + 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' }); + const paramRestrictAccess = new cdk.CfnParameter(this, 'restrictAccess', { + type: 'String', + allowedValues: ['true', '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 ?? '', '')), + ), + }); - new cdk.CfnOutput(this, 'ContainerNames', { - value: cdk.Fn.join(',', containersInfo.map(({ container: { containerName } }) => containerName)) - }); + 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, + }; + } + + private ecs() { + const { + envName, + categoryName, + apiName, + policies, + containers, + secretsArns, + taskEnvironmentVariables, + exposedContainer, + taskPorts, + isInitialDeploy, + desiredCount, + 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, + }, + }); } - 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' }); - const paramRestrictAccess = new cdk.CfnParameter(this, 'restrictAccess', { - type: 'String', - allowedValues: ['true', 'false'], + const task = new ecs.TaskDefinition(this, 'TaskDefinition', { + compatibility: ecs.Compatibility.FARGATE, + memoryMiB: '1024', + cpu: '512', + family: `${envName}-${apiName}`, + }); + (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); + policies.forEach(policy => { + const statement = isPolicyStatement(policy) ? policy : wrapJsonPoliciesInCdkPolicies(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/${envName}-${apiName}-${name}`, + retention: logs.RetentionDays.ONE_MONTH, + removalPolicy: cdk.RemovalPolicy.DESTROY, }); - 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 { 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 = `${envName}-${categoryName}-${apiName}-${name}`; + + if (this.props.existingEcrRepositories.has(repositoryName)) { + repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); + } else { + repository = new ecr.Repository(this, logicalId, { + repositoryName: `${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); + } - 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 ?? '', '')), - ), - }); + // Needed because the image will be pulled from ecr repository later + repository.grantPull(task.obtainExecutionRole()); + } - 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, - }; - } + const secrets: ecs.ContainerDefinitionOptions['secrets'] = {}; + const environmentWithoutSecrets = environment || {}; - private ecs() { - const { - envName, - categoryName, - apiName, - policies, - containers, - secretsArns, - taskEnvironmentVariables, - exposedContainer, - taskPorts, - isInitialDeploy, - desiredCount, - 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, - }, - }); - } + containerSecrets.forEach((s, i) => { + if (secretsArns.has(s)) { + secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretCompleteArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); + } - const task = new ecs.TaskDefinition(this, 'TaskDefinition', { - compatibility: ecs.Compatibility.FARGATE, - memoryMiB: '1024', - cpu: '512', - family: `${envName}-${apiName}`, + delete environmentWithoutSecrets[s]; }); - (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); - policies.forEach(policy => { - const statement = isPolicyStatement(policy) ? policy : wrapJsonPoliciesInCdkPolicies(policy); - task.addToTaskRolePolicy(statement); + 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, }); - 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/${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 = `${envName}-${categoryName}-${apiName}-${name}`; - - if (this.props.existingEcrRepositories.has(repositoryName)) { - repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); - } else { - repository = new ecr.Repository(this, logicalId, { - repositoryName: `${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.fromSecretCompleteArn(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, - }); - - if (build) { - 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, - }); - }); - }, - ); + if (build) { + containersInfo.push({ + container, + repository, + }); + } - 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, - })), + // 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, + }, + ]; + } - let serviceRegistries: ecs.CfnService.ServiceRegistryProperty[] = undefined; + 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, + }); - if (cloudMapService) { - serviceRegistries = [{ - containerName: exposedContainer.name, - containerPort: exposedContainer.port, - registryArn: cloudMapService.attrArn, - }]; - } + new cdk.CfnOutput(this, 'ServiceName', { + value: service.serviceName, + }); - 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, 'ClusterName', { + value: this.clusterName, + }); - new cdk.CfnOutput(this, 'ServiceName', { - value: service.serviceName - }); + 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 { envName, deploymentBucketName, deploymentMechanism, desiredCount } = this.props; - new cdk.CfnOutput(this, 'ClusterName', { - value: this.clusterName - }); + const s3SourceActionKey = this.zipPath; - return { - service, - serviceSecurityGroup, - containersInfo, - cloudMapService, - }; - } + const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); - private pipeline({ - skipWait = false, - service, - containersInfo, - gitHubSourceActionInfo, - }: { - skipWait?: boolean; - service: ecs.CfnService, - containersInfo: { - container: ecs.ContainerDefinition; - repository: ecr.IRepository; - }[], - gitHubSourceActionInfo?: GitHubSourceActionInfo - }) { - const { - envName, - deploymentBucketName, - deploymentMechanism, - desiredCount, - } = this.props; - - const s3SourceActionKey = this.zipPath; - - const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); - - const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { - skipWait, - envName, - containersInfo, - service, - bucket, - s3SourceActionKey, - deploymentMechanism, - gitHubSourceActionInfo, - desiredCount, - }); + const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { + skipWait, + envName, + containersInfo, + service, + bucket, + s3SourceActionKey, + deploymentMechanism, + gitHubSourceActionInfo, + desiredCount, + }); - pipelineWithAwaiter.node.addDependency(service); + pipelineWithAwaiter.node.addDependency(service); - return { pipelineWithAwaiter }; - } + return { pipelineWithAwaiter }; + } - protected getPipelineName() { - return this.pipelineWithAwaiter.getPipelineName(); - } + 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`; - } + getPipelineConsoleUrl(region: string) { + const pipelineName = this.getPipelineName(); + return `https://${region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipelineName}/view`; + } - toCloudFormation() { - prepareApp(this); + toCloudFormation() { + prepareApp(this); - const cfn = this._toCloudFormation(); + const cfn = this._toCloudFormation(); - Object.keys(cfn.Parameters).forEach(k => { - if (k.startsWith('AssetParameters')) { - let value = ''; + Object.keys(cfn.Parameters).forEach(k => { + if (k.startsWith('AssetParameters')) { + let value = ''; - if (k.includes('Bucket')) { - value = this.props.deploymentBucketName; - } else if (k.includes('VersionKey')) { - value = `${PIPELINE_AWAITER_ZIP}||`; - } + if (k.includes('Bucket')) { + value = this.props.deploymentBucketName; + } else if (k.includes('VersionKey')) { + value = `${PIPELINE_AWAITER_ZIP}||`; + } - cfn.Parameters[k].Default = value; - } - }); + cfn.Parameters[k].Default = value; + } + }); - return cfn; - } + return cfn; + } } /** @@ -514,17 +510,17 @@ export abstract class ContainersStack extends cdk.Stack { * @returns {iam.PolicyStatement} CDK compatible policy statement */ function wrapJsonPoliciesInCdkPolicies(policy: Record): iam.PolicyStatement { - return { - toStatementJson() { - return policy; - }, - } as iam.PolicyStatement; + return { + toStatementJson() { + return policy; + }, + } as iam.PolicyStatement; } function isPolicyStatement(obj: any): obj is iam.PolicyStatement { - if (obj && typeof (obj).toStatementJson === 'function') { - return true; - } + if (obj && typeof (obj).toStatementJson === 'function') { + return true; + } - return false; -} \ No newline at end of file + return false; +} From 939e4f33b0e9dda38b0912b8887730308e63211c Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Wed, 4 Aug 2021 16:57:57 -0700 Subject: [PATCH 444/587] fix(container-hosting): ignore test cases (#7895) * fix(container-hosting): ignore test cases * used it.skip instead of comments * used it.skip instead of comments --- .../src/provider-utils/awscloudformation/base-api-stack.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 61030462f8..f495cbff5c 100644 --- 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 @@ -132,10 +132,11 @@ export abstract class ContainersStack extends cdk.Stack { // 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' }); + 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', { From 53d6a0896d962ffe10c1bae7b00fb6c3a19a49ad Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 6 Aug 2021 03:10:11 +0000 Subject: [PATCH 445/587] chore(release): Publish [ci skip] - amplify-app@3.0.7 - amplify-appsync-simulator@1.27.6 - amplify-category-analytics@2.21.16 - amplify-category-api@2.31.18 - amplify-category-auth@2.36.2 - amplify-category-function@2.34.2 - amplify-category-hosting@2.7.16 - amplify-category-predictions@2.9.7 - amplify-category-storage@2.12.4 - amplify-category-xr@2.8.16 - amplify-cli-core@1.26.0 - @aws-amplify/cli@5.3.0 - amplify-codegen-appsync-model-plugin@1.22.4 - amplify-console-hosting@1.9.7 - amplify-console-integration-tests@1.8.4 - amplify-container-hosting@1.3.18 - amplify-dotnet-function-template-provider@1.5.16 - amplify-dynamodb-simulator@1.19.7 - amplify-e2e-core@1.24.2 - amplify-e2e-tests@2.46.2 - amplify-frontend-android@2.15.4 - amplify-frontend-flutter@0.4.4 - amplify-frontend-ios@2.20.9 - amplify-frontend-javascript@2.23.4 - amplify-go-function-runtime-provider@1.8.10 - @aws-amplify/graphql-function-transformer@0.4.1 - @aws-amplify/graphql-http-transformer@0.5.1 - @aws-amplify/graphql-index-transformer@0.2.1 - @aws-amplify/graphql-model-transformer@0.5.1 - @aws-amplify/graphql-predictions-transformer@0.3.1 - @aws-amplify/graphql-searchable-transformer@0.4.1 - @aws-amplify/graphql-transformer-core@0.8.1 - @aws-amplify/graphql-transformer-interfaces@1.8.1 - amplify-headless-interface@1.10.0 - amplify-java-function-runtime-provider@1.8.9 - amplify-migration-tests@3.1.4 - amplify-nodejs-function-runtime-provider@1.6.6 - amplify-nodejs-function-template-provider@1.6.16 - amplify-prompts@1.1.0 - amplify-provider-awscloudformation@4.56.1 - amplify-python-function-runtime-provider@1.9.6 - amplify-util-headless-input@1.5.3 - amplify-util-import@1.5.7 - amplify-util-mock@3.34.0 - graphql-auth-transformer@6.24.17 - graphql-connection-transformer@4.21.17 - graphql-dynamodb-transformer@6.22.17 - graphql-elasticsearch-transformer@4.11.17 - graphql-function-transformer@2.5.16 - graphql-http-transformer@4.18.4 - graphql-key-transformer@2.23.17 - graphql-mapping-template@4.18.2 - graphql-predictions-transformer@2.5.16 - graphql-relational-schema-transformer@2.18.4 - graphql-transformer-common@4.19.7 - graphql-transformer-core@6.29.2 - graphql-transformers-e2e-tests@6.24.7 - graphql-versioned-transformer@4.17.17 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 58632274d5..133a4689cc 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a6581498ff..9f264fd227 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.17", + "version": "2.31.18", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.72.0", "@aws-cdk/region-info": "~1.72.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.25.1", - "amplify-util-headless-input": "1.5.2", + "amplify-cli-core": "1.26.0", + "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", "constructs": "^3.2.0", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.3", - "graphql-transformer-core": "6.29.1", + "graphql-relational-schema-transformer": "2.18.4", + "graphql-transformer-core": "6.29.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From d3479f475adc70bac002380953368463fff10007 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Tue, 17 Aug 2021 20:19:49 -0700 Subject: [PATCH 446/587] chore: revert awscdk to 1.118.0, upgrade pkg to latest (#7983) --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9f264fd227..8bd4c0679c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -25,11 +25,11 @@ "@aws-cdk/aws-autoscaling-common": "~1.72.0", "@aws-cdk/aws-autoscaling-hooktargets": "~1.72.0", "@aws-cdk/aws-certificatemanager": "~1.72.0", - "@aws-cdk/aws-cloudformation": "1.72.0", + "@aws-cdk/aws-cloudformation": "~1.72.0", "@aws-cdk/aws-cloudfront": "~1.72.0", "@aws-cdk/aws-cloudwatch": "~1.72.0", "@aws-cdk/aws-codebuild": "~1.72.0", - "@aws-cdk/aws-codeguruprofiler": "1.72.0", + "@aws-cdk/aws-codeguruprofiler": "~1.72.0", "@aws-cdk/aws-codepipeline": "~1.72.0", "@aws-cdk/aws-codepipeline-actions": "~1.72.0", "@aws-cdk/aws-cognito": "~1.72.0", @@ -37,7 +37,7 @@ "@aws-cdk/aws-ecr": "~1.72.0", "@aws-cdk/aws-ecr-assets": "~1.72.0", "@aws-cdk/aws-ecs": "~1.72.0", - "@aws-cdk/aws-efs": "1.72.0", + "@aws-cdk/aws-efs": "~1.72.0", "@aws-cdk/aws-elasticloadbalancing": "~1.72.0", "@aws-cdk/aws-elasticloadbalancingv2": "~1.72.0", "@aws-cdk/aws-events": "~1.72.0", @@ -49,7 +49,7 @@ "@aws-cdk/aws-route53-targets": "~1.72.0", "@aws-cdk/aws-s3": "~1.72.0", "@aws-cdk/aws-s3-assets": "~1.72.0", - "@aws-cdk/aws-sam": "1.72.0", + "@aws-cdk/aws-sam": "~1.72.0", "@aws-cdk/aws-secretsmanager": "~1.72.0", "@aws-cdk/aws-servicediscovery": "~1.72.0", "@aws-cdk/aws-sns": "~1.72.0", From 7b041de93ad9331b37e9e3107fe9f18e55007805 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 20 Aug 2021 10:13:14 -0700 Subject: [PATCH 447/587] chore: update dependencies (#7913) * chore: update dependencies aws-sdk, execa, xmldom * chore: use same version of base64-js in tests * chore: remove added cdk dependency * chore: bump aws-cdk, constructs, pino, archiver. Rebuild yarn.lock * chore: use latest patch for all aws-cdk, remove comment * chore: update yarn.lock * test: add missing dependency to package.json, use import instead of require --- packages/amplify-category-api/package.json | 90 +++++++++---------- .../pipeline-with-awaiter.ts | 2 +- .../utils/containers-artifacts.ts | 4 +- 3 files changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8bd4c0679c..d9166264d5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,55 +17,55 @@ "test": "jest" }, "dependencies": { - "@aws-cdk/assets": "~1.72.0", - "@aws-cdk/aws-apigateway": "~1.72.0", - "@aws-cdk/aws-apigatewayv2": "~1.72.0", - "@aws-cdk/aws-applicationautoscaling": "~1.72.0", - "@aws-cdk/aws-autoscaling": "~1.72.0", - "@aws-cdk/aws-autoscaling-common": "~1.72.0", - "@aws-cdk/aws-autoscaling-hooktargets": "~1.72.0", - "@aws-cdk/aws-certificatemanager": "~1.72.0", - "@aws-cdk/aws-cloudformation": "~1.72.0", - "@aws-cdk/aws-cloudfront": "~1.72.0", - "@aws-cdk/aws-cloudwatch": "~1.72.0", - "@aws-cdk/aws-codebuild": "~1.72.0", - "@aws-cdk/aws-codeguruprofiler": "~1.72.0", - "@aws-cdk/aws-codepipeline": "~1.72.0", - "@aws-cdk/aws-codepipeline-actions": "~1.72.0", - "@aws-cdk/aws-cognito": "~1.72.0", - "@aws-cdk/aws-ec2": "~1.72.0", - "@aws-cdk/aws-ecr": "~1.72.0", - "@aws-cdk/aws-ecr-assets": "~1.72.0", - "@aws-cdk/aws-ecs": "~1.72.0", - "@aws-cdk/aws-efs": "~1.72.0", - "@aws-cdk/aws-elasticloadbalancing": "~1.72.0", - "@aws-cdk/aws-elasticloadbalancingv2": "~1.72.0", - "@aws-cdk/aws-events": "~1.72.0", - "@aws-cdk/aws-iam": "~1.72.0", - "@aws-cdk/aws-kms": "~1.72.0", - "@aws-cdk/aws-lambda": "~1.72.0", - "@aws-cdk/aws-logs": "~1.72.0", - "@aws-cdk/aws-route53": "~1.72.0", - "@aws-cdk/aws-route53-targets": "~1.72.0", - "@aws-cdk/aws-s3": "~1.72.0", - "@aws-cdk/aws-s3-assets": "~1.72.0", - "@aws-cdk/aws-sam": "~1.72.0", - "@aws-cdk/aws-secretsmanager": "~1.72.0", - "@aws-cdk/aws-servicediscovery": "~1.72.0", - "@aws-cdk/aws-sns": "~1.72.0", - "@aws-cdk/aws-sns-subscriptions": "~1.72.0", - "@aws-cdk/aws-sqs": "~1.72.0", - "@aws-cdk/aws-ssm": "~1.72.0", - "@aws-cdk/cloud-assembly-schema": "~1.72.0", - "@aws-cdk/core": "~1.72.0", - "@aws-cdk/custom-resources": "~1.72.0", - "@aws-cdk/cx-api": "~1.72.0", - "@aws-cdk/region-info": "~1.72.0", + "@aws-cdk/assets": "~1.119.0", + "@aws-cdk/aws-apigateway": "~1.119.0", + "@aws-cdk/aws-apigatewayv2": "~1.119.0", + "@aws-cdk/aws-applicationautoscaling": "~1.119.0", + "@aws-cdk/aws-autoscaling": "~1.119.0", + "@aws-cdk/aws-autoscaling-common": "~1.119.0", + "@aws-cdk/aws-autoscaling-hooktargets": "~1.119.0", + "@aws-cdk/aws-certificatemanager": "~1.119.0", + "@aws-cdk/aws-cloudformation": "~1.119.0", + "@aws-cdk/aws-cloudfront": "~1.119.0", + "@aws-cdk/aws-cloudwatch": "~1.119.0", + "@aws-cdk/aws-codebuild": "~1.119.0", + "@aws-cdk/aws-codeguruprofiler": "~1.119.0", + "@aws-cdk/aws-codepipeline": "~1.119.0", + "@aws-cdk/aws-codepipeline-actions": "~1.119.0", + "@aws-cdk/aws-cognito": "~1.119.0", + "@aws-cdk/aws-ec2": "~1.119.0", + "@aws-cdk/aws-ecr": "~1.119.0", + "@aws-cdk/aws-ecr-assets": "~1.119.0", + "@aws-cdk/aws-ecs": "~1.119.0", + "@aws-cdk/aws-efs": "~1.119.0", + "@aws-cdk/aws-elasticloadbalancing": "~1.119.0", + "@aws-cdk/aws-elasticloadbalancingv2": "~1.119.0", + "@aws-cdk/aws-events": "~1.119.0", + "@aws-cdk/aws-iam": "~1.119.0", + "@aws-cdk/aws-kms": "~1.119.0", + "@aws-cdk/aws-lambda": "~1.119.0", + "@aws-cdk/aws-logs": "~1.119.0", + "@aws-cdk/aws-route53": "~1.119.0", + "@aws-cdk/aws-route53-targets": "~1.119.0", + "@aws-cdk/aws-s3": "~1.119.0", + "@aws-cdk/aws-s3-assets": "~1.119.0", + "@aws-cdk/aws-sam": "~1.119.0", + "@aws-cdk/aws-secretsmanager": "~1.119.0", + "@aws-cdk/aws-servicediscovery": "~1.119.0", + "@aws-cdk/aws-sns": "~1.119.0", + "@aws-cdk/aws-sns-subscriptions": "~1.119.0", + "@aws-cdk/aws-sqs": "~1.119.0", + "@aws-cdk/aws-ssm": "~1.119.0", + "@aws-cdk/cloud-assembly-schema": "~1.119.0", + "@aws-cdk/core": "~1.119.0", + "@aws-cdk/custom-resources": "~1.119.0", + "@aws-cdk/cx-api": "~1.119.0", + "@aws-cdk/region-info": "~1.119.0", "@graphql-tools/merge": "^6.0.18", "amplify-cli-core": "1.26.0", "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", - "constructs": "^3.2.0", + "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.4", 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 index 2ca6459bb3..2711c0f674 100644 --- 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 @@ -251,7 +251,7 @@ export class PipelineWithAwaiter extends cdk.Construct { clusterName: service.cluster, env: {}, } as ecs.ICluster; - serviceArn = cdk.Fn.ref(service.serviceArn); + serviceArn = cdk.Fn.ref(service.attrServiceArn); serviceName = service.serviceName; stack = cdk.Stack.of(this); env = {} as any; 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 index c33ca68fbf..c1745a4fb9 100644 --- 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 @@ -159,12 +159,12 @@ export async function processDockerConfig(context: any, resource: ApiResource, s try { const { data: { content, encoding }, - } = await octokit.repos.getContent({ + } = (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) { From 3ba93eba11a2e6e0a637476a90b1e66ba6b3bf35 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 24 Aug 2021 20:39:02 +0000 Subject: [PATCH 448/587] chore(release): Publish [ci skip] - amplify-app@3.0.8 - amplify-appsync-simulator@1.27.7 - amplify-category-analytics@2.21.17 - amplify-category-api@2.31.19 - amplify-category-auth@2.36.3 - amplify-category-function@2.34.3 - amplify-category-hosting@2.7.17 - amplify-category-predictions@2.9.8 - amplify-category-storage@2.12.5 - amplify-category-xr@2.8.17 - amplify-cli-core@1.26.1 - @aws-amplify/cli@5.3.1 - amplify-console-hosting@1.9.8 - amplify-console-integration-tests@1.8.5 - amplify-container-hosting@1.3.19 - amplify-dotnet-function-runtime-provider@1.6.3 - amplify-dotnet-function-template-provider@1.5.17 - amplify-dynamodb-simulator@1.19.8 - amplify-e2e-core@1.24.3 - amplify-e2e-tests@2.47.0 - amplify-frontend-ios@2.20.10 - amplify-frontend-javascript@2.23.5 - amplify-go-function-runtime-provider@1.9.0 - @aws-amplify/graphql-function-transformer@0.4.2 - @aws-amplify/graphql-http-transformer@0.5.2 - @aws-amplify/graphql-index-transformer@0.3.0 - @aws-amplify/graphql-model-transformer@0.6.0 - @aws-amplify/graphql-predictions-transformer@0.3.2 - @aws-amplify/graphql-searchable-transformer@0.5.0 - @aws-amplify/graphql-transformer-core@0.8.2 - @aws-amplify/graphql-transformer-interfaces@1.8.2 - amplify-java-function-runtime-provider@1.8.10 - amplify-migration-tests@3.1.5 - amplify-nodejs-function-runtime-provider@1.6.7 - amplify-nodejs-function-template-provider@1.6.17 - amplify-prompts@1.1.1 - amplify-provider-awscloudformation@4.57.0 - amplify-python-function-runtime-provider@1.9.7 - amplify-storage-simulator@1.6.1 - amplify-util-import@1.5.8 - amplify-util-mock@3.34.1 - graphql-auth-transformer@6.24.18 - graphql-connection-transformer@4.21.18 - graphql-dynamodb-transformer@6.22.18 - graphql-elasticsearch-transformer@4.11.18 - graphql-function-transformer@2.5.17 - graphql-http-transformer@4.18.5 - graphql-key-transformer@2.23.18 - graphql-mapping-template@4.18.3 - graphql-predictions-transformer@2.5.17 - graphql-relational-schema-transformer@2.18.5 - graphql-transformer-common@4.19.8 - graphql-transformer-core@6.29.3 - graphql-transformers-e2e-tests@6.25.0 - graphql-versioned-transformer@4.17.18 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 133a4689cc..d228f7d666 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d9166264d5..b9515c9b09 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.18", + "version": "2.31.19", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.119.0", "@aws-cdk/region-info": "~1.119.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.26.0", + "amplify-cli-core": "1.26.1", "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.4", - "graphql-transformer-core": "6.29.2", + "graphql-relational-schema-transformer": "2.18.5", + "graphql-transformer-core": "6.29.3", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From ec4e1a3fb09cffcabfa6292afd4e16e4decba9c1 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Wed, 25 Aug 2021 08:15:19 -0700 Subject: [PATCH 449/587] test: modified jest config for code cov to collect (#7931) * test: added jest config for code cov to detect coverage * test: modified config --- packages/amplify-category-api/package.json | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b9515c9b09..690d7222d0 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -92,10 +92,6 @@ "json", "node" ], - "collectCoverage": true, - "coverageReporters": [ - "json", - "html" - ] + "collectCoverage": true } } From 84e46d6c63d0adaf88b4c3530565f3406d8286b8 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 2 Sep 2021 18:57:09 +0000 Subject: [PATCH 450/587] chore(release): Publish [ci skip] - amplify-app@3.0.9 - amplify-category-analytics@2.21.18 - amplify-category-api@2.31.20 - amplify-category-auth@2.36.4 - amplify-category-function@2.34.4 - amplify-category-hosting@2.7.18 - amplify-category-predictions@2.9.9 - amplify-category-storage@2.12.6 - amplify-category-xr@2.8.18 - amplify-cli-core@1.26.2 - @aws-amplify/cli@5.4.0 - amplify-console-hosting@1.9.9 - amplify-console-integration-tests@1.8.6 - amplify-container-hosting@1.3.20 - amplify-dotnet-function-template-provider@1.5.18 - amplify-dynamodb-simulator@1.19.9 - amplify-e2e-core@1.24.4 - amplify-e2e-tests@2.47.1 - amplify-frontend-ios@2.20.11 - amplify-frontend-javascript@2.23.6 - amplify-go-function-runtime-provider@1.9.1 - @aws-amplify/graphql-function-transformer@0.4.3 - @aws-amplify/graphql-http-transformer@0.5.3 - @aws-amplify/graphql-index-transformer@0.3.1 - @aws-amplify/graphql-model-transformer@0.6.1 - @aws-amplify/graphql-predictions-transformer@0.3.3 - @aws-amplify/graphql-relational-transformer@0.2.0 - @aws-amplify/graphql-searchable-transformer@0.5.1 - @aws-amplify/graphql-transformer-core@0.9.0 - @aws-amplify/graphql-transformer-interfaces@1.9.0 - amplify-graphql-types-generator@2.8.5 - amplify-java-function-runtime-provider@1.8.11 - amplify-migration-tests@3.1.6 - amplify-nodejs-function-runtime-provider@1.6.8 - amplify-nodejs-function-template-provider@1.6.18 - amplify-prompts@1.1.2 - amplify-provider-awscloudformation@4.58.0 - amplify-python-function-runtime-provider@1.9.8 - amplify-util-import@1.5.9 - amplify-util-mock@3.34.2 - graphql-auth-transformer@6.24.19 - graphql-connection-transformer@4.21.19 - graphql-dynamodb-transformer@6.22.19 - graphql-elasticsearch-transformer@4.11.19 - graphql-function-transformer@2.5.18 - graphql-http-transformer@4.18.6 - graphql-key-transformer@2.23.19 - graphql-predictions-transformer@2.5.18 - graphql-relational-schema-transformer@2.18.6 - graphql-transformer-common@4.19.9 - graphql-transformer-core@6.29.4 - graphql-transformers-e2e-tests@6.26.0 - graphql-versioned-transformer@4.17.19 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d228f7d666..81ce738fde 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 690d7222d0..173a5d856d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.19", + "version": "2.31.20", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.119.0", "@aws-cdk/region-info": "~1.119.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.26.1", + "amplify-cli-core": "1.26.2", "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.5", - "graphql-transformer-core": "6.29.3", + "graphql-relational-schema-transformer": "2.18.6", + "graphql-transformer-core": "6.29.4", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From cac12f33bfa5dfdf3ffaa37658820e85842c6685 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 9 Sep 2021 01:39:00 +0000 Subject: [PATCH 451/587] chore(release): Publish [ci skip] - amplify-app@3.0.10 - amplify-category-analytics@2.21.19 - amplify-category-api@2.31.21 - amplify-category-auth@2.36.5 - amplify-category-function@2.34.5 - amplify-category-hosting@2.7.19 - amplify-category-predictions@2.9.10 - amplify-category-storage@2.12.7 - amplify-category-xr@2.8.19 - amplify-cli-core@1.27.0 - @aws-amplify/cli@5.5.0 - amplify-console-hosting@1.9.10 - amplify-console-integration-tests@1.8.7 - amplify-container-hosting@1.3.21 - amplify-dotnet-function-template-provider@1.5.19 - amplify-dynamodb-simulator@1.19.10 - amplify-e2e-core@1.25.0 - amplify-e2e-tests@2.48.0 - amplify-frontend-ios@2.20.12 - amplify-frontend-javascript@2.23.7 - amplify-go-function-runtime-provider@1.9.2 - amplify-java-function-runtime-provider@1.8.12 - amplify-migration-tests@3.1.7 - amplify-nodejs-function-runtime-provider@1.6.9 - amplify-nodejs-function-template-provider@1.6.19 - amplify-provider-awscloudformation@4.59.0 - amplify-python-function-runtime-provider@1.9.9 - amplify-util-import@1.5.10 - amplify-util-mock@3.34.3 - graphql-auth-transformer@6.24.20 - graphql-connection-transformer@4.21.20 - graphql-dynamodb-transformer@6.22.20 - graphql-elasticsearch-transformer@4.11.20 - graphql-function-transformer@2.5.19 - graphql-http-transformer@4.18.7 - graphql-key-transformer@2.23.20 - graphql-predictions-transformer@2.5.19 - graphql-transformer-core@6.29.5 - graphql-transformers-e2e-tests@6.26.1 - graphql-versioned-transformer@4.17.20 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 81ce738fde..92102936b4 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 173a5d856d..8e440002ae 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.20", + "version": "2.31.21", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -62,14 +62,14 @@ "@aws-cdk/cx-api": "~1.119.0", "@aws-cdk/region-info": "~1.119.0", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.26.2", + "amplify-cli-core": "1.27.0", "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.6", - "graphql-transformer-core": "6.29.4", + "graphql-transformer-core": "6.29.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "ora": "^4.0.3", From 31a78155548aa54600dcd57ca90294b791732566 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 9 Sep 2021 14:52:56 -0700 Subject: [PATCH 452/587] chore: add missing dependencies to relevant package.json files (#8137) --- packages/amplify-category-api/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8e440002ae..f83c0362a9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -61,8 +61,10 @@ "@aws-cdk/custom-resources": "~1.119.0", "@aws-cdk/cx-api": "~1.119.0", "@aws-cdk/region-info": "~1.119.0", + "@octokit/rest": "^18.0.9", "@graphql-tools/merge": "^6.0.18", "amplify-cli-core": "1.27.0", + "amplify-headless-interface": "1.10.0", "amplify-util-headless-input": "1.5.3", "chalk": "^4.1.1", "constructs": "^3.3.125", @@ -72,6 +74,7 @@ "graphql-transformer-core": "6.29.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", + "lodash": "^4.17.21", "ora": "^4.0.3", "uuid": "^3.4.0" }, From fe870c6f43cb886e0cc91fe29419b931785df07c Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 9 Sep 2021 15:01:44 -0700 Subject: [PATCH 453/587] refactor: move api utility isNameUnique to core as isResourceNameUnique (#8038) --- .../utils/check-case-sensitivity.test.ts | 23 ------------------ .../cfn-api-artifact-handler.ts | 24 +++++++++---------- .../awscloudformation/legacy-add-resource.ts | 11 ++++----- .../service-walkthroughs/apigw-walkthrough.ts | 20 ++++++++++------ .../utils/check-case-sensitivity.ts | 15 ------------ 5 files changed, 30 insertions(+), 63 deletions(-) delete mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts delete mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts diff --git a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts deleted file mode 100644 index b8c81c95af..0000000000 --- a/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/check-case-sensitivity.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { isNameUnique } from '../../../../provider-utils/awscloudformation/utils/check-case-sensitivity'; -import { stateManager } from 'amplify-cli-core'; - -jest.mock('amplify-cli-core'); - -const stateManager_mock = stateManager as jest.Mocked; - -stateManager_mock.getMeta.mockReturnValue({ - api: { - testBlog: {}, - }, -}); - -test('conflict exists if names differ by case only', () => { - expect(() => isNameUnique('api', 'testblog')).toThrowErrorMatchingInlineSnapshot( - `"A resource named testBlog already exists. Amplify resource names must be unique and are case-insensitive."`, - ); -}); - -test('conflict does not exist if names differ by characters', () => { - const result = isNameUnique('api', 'newname'); - expect(result).toBe(true); -}); 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 index 0b4a49a2a7..cc421715b5 100644 --- 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 @@ -1,23 +1,23 @@ -import { ApiArtifactHandler } from '../api-artifact-handler'; +import { isResourceNameUnique } from 'amplify-cli-core'; import { AddApiRequest, - ConflictResolution, AppSyncServiceConfiguration, + ConflictResolution, ResolutionStrategy, UpdateApiRequest, } from 'amplify-headless-interface'; -import path from 'path'; -import fs from 'fs-extra'; -import { category } from '../../category-constants'; -import { rootAssetDir, provider, gqlSchemaFilename, cfnParametersFilename } from './aws-constants'; +import * as fs from 'fs-extra'; import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; -import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-conflict-resolution-bi-di-mapper'; -import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import uuid from 'uuid'; import _ from 'lodash'; -import { getAppSyncResourceName, getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from './utils/amplify-meta-utils'; +import * as path from 'path'; +import uuid from 'uuid'; +import { category } from '../../category-constants'; +import { ApiArtifactHandler } from '../api-artifact-handler'; +import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants'; +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 { isNameUnique } from './utils/check-case-sensitivity'; +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'; @@ -50,7 +50,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { } const serviceConfig = request.serviceConfiguration; - isNameUnique('api', serviceConfig.apiName); + isResourceNameUnique('api', serviceConfig.apiName); const resourceDir = this.getResourceDir(serviceConfig.apiName); 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 index ba3089e483..ff7e33a189 100644 --- 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 @@ -1,9 +1,8 @@ -import { JSONUtilities } from 'amplify-cli-core'; +import { isResourceNameUnique, JSONUtilities } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { cfnParametersFilename, parametersFileName, rootAssetDir } from './aws-constants'; import { serviceMetadataFor } from './utils/dynamic-imports'; -import { isNameUnique } from './utils/check-case-sensitivity'; -import fs from 'fs-extra'; -import path from 'path'; -import { parametersFileName, cfnParametersFilename, rootAssetDir } from './aws-constants'; // this is the old logic for generating resources in the project directory // it is still used for adding REST APIs @@ -33,7 +32,7 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, const parameters = { ...answers }; const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); - isNameUnique(category, parameters.resourceName); + isResourceNameUnique(category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); 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 index 3c19b13ca1..ac3390df3e 100644 --- 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 @@ -1,12 +1,11 @@ +import { $TSContext, exitOnNextTick, isResourceNameUnique, open, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; import inquirer from 'inquirer'; -import path from 'path'; -import fs from 'fs-extra'; import os from 'os'; +import * as path from 'path'; import uuid from 'uuid'; import { rootAssetDir } from '../aws-constants'; -import { checkForPathOverlap, validatePathName, formatCFNPathParamsForExpressJs } from '../utils/rest-api-path-utils'; -import { ResourceDoesNotExistError, exitOnNextTick, $TSContext, stateManager, open } from 'amplify-cli-core'; -import { isNameUnique } from '../utils/check-case-sensitivity'; +import { checkForPathOverlap, formatCFNPathParamsForExpressJs, validatePathName } from '../utils/rest-api-path-utils'; // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -193,9 +192,16 @@ async function askApiNames(context, defaults) { }, required: true, })(input); - const uniqueCheck = isNameUnique(category, input, false); - return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : typeof uniqueCheck === 'string' ? uniqueCheck : true; + + let uniqueCheck = false; + try { + uniqueCheck = isResourceNameUnique(category, input); + } catch (e) { + return e.message || e; + } + return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : uniqueCheck; }; + const answer: { apiName?: string; resourceName: string } = await inquirer.prompt([ { name: 'resourceName', diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts deleted file mode 100644 index 4bbf478a68..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-case-sensitivity.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { stateManager } from 'amplify-cli-core'; - -export const isNameUnique = (category: string, resourceName: string, throwOnMatch = true) => { - const resourceNames = Object.keys(stateManager.getMeta()?.[category] || {}); - const matchIdx = resourceNames.map(name => name.toLowerCase()).indexOf(resourceName.toLowerCase()); - if (matchIdx === -1) { - return true; - } - const msg = `A resource named ${resourceNames[matchIdx]} already exists. Amplify resource names must be unique and are case-insensitive.`; - if (throwOnMatch) { - throw new Error(msg); - } else { - return msg; - } -}; From 50e611cb96c2a76a69b1144032931ca3b00bfff6 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 9 Sep 2021 15:39:39 -0700 Subject: [PATCH 454/587] chore: update dependencies to bump axios everywhere (#8136) --- .../dockercompose-rest-express/express/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 7beb4e19d3..98a3659067 100644 --- 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 @@ -9,7 +9,7 @@ "license": "ISC", "dependencies": { "aws-sdk": "^2.845.0", - "axios": "^0.21.1", + "axios": "^0.21.4", "body-parser": "^1.19.0", "express": "^4.17.1", "redis": "^3.0.2" From fc0e3667144f05bb8a1acb4ac4048931ba0e071d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 14 Sep 2021 23:26:49 +0000 Subject: [PATCH 455/587] chore(release): Publish [ci skip] - amplify-app@3.0.11 - amplify-category-analytics@2.21.20 - amplify-category-api@2.31.22 - amplify-category-auth@2.37.0 - amplify-category-function@2.34.6 - amplify-category-hosting@2.7.20 - amplify-category-interactions@2.6.4 - amplify-category-predictions@2.9.11 - amplify-category-storage@2.12.8 - amplify-category-xr@2.8.20 - amplify-cli-core@1.28.0 - @aws-amplify/cli@5.6.0 - amplify-console-hosting@1.9.11 - amplify-console-integration-tests@1.8.8 - amplify-container-hosting@1.3.22 - amplify-dotnet-function-template-provider@1.5.20 - amplify-dynamodb-simulator@1.19.11 - amplify-e2e-core@1.26.0 - amplify-e2e-tests@2.49.0 - amplify-frontend-ios@2.20.13 - amplify-frontend-javascript@2.24.0 - amplify-go-function-runtime-provider@1.9.3 - @aws-amplify/graphql-index-transformer@0.3.2 - @aws-amplify/graphql-model-transformer@0.6.2 - @aws-amplify/graphql-relational-transformer@0.2.1 - @aws-amplify/graphql-searchable-transformer@0.6.0 - amplify-java-function-runtime-provider@1.8.13 - amplify-migration-tests@3.1.8 - amplify-nodejs-function-runtime-provider@1.6.10 - amplify-nodejs-function-template-provider@1.6.20 - amplify-provider-awscloudformation@4.60.0 - amplify-python-function-runtime-provider@1.9.10 - amplify-util-headless-input@1.5.4 - amplify-util-import@1.5.11 - amplify-util-mock@3.34.4 - graphql-auth-transformer@6.24.21 - graphql-connection-transformer@4.21.21 - graphql-dynamodb-transformer@6.22.21 - graphql-elasticsearch-transformer@4.12.0 - graphql-function-transformer@2.5.20 - graphql-http-transformer@4.18.8 - graphql-key-transformer@2.23.21 - graphql-predictions-transformer@2.5.20 - graphql-transformer-core@6.29.6 - graphql-transformers-e2e-tests@6.26.2 - graphql-versioned-transformer@4.17.21 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 92102936b4..6ad8a76ade 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index f83c0362a9..8f4d51acea 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.21", + "version": "2.31.22", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -61,17 +61,17 @@ "@aws-cdk/custom-resources": "~1.119.0", "@aws-cdk/cx-api": "~1.119.0", "@aws-cdk/region-info": "~1.119.0", - "@octokit/rest": "^18.0.9", "@graphql-tools/merge": "^6.0.18", - "amplify-cli-core": "1.27.0", + "@octokit/rest": "^18.0.9", + "amplify-cli-core": "1.28.0", "amplify-headless-interface": "1.10.0", - "amplify-util-headless-input": "1.5.3", + "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.6", - "graphql-transformer-core": "6.29.5", + "graphql-transformer-core": "6.29.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 829a25a9eb8068330605065c281f787226c9034b Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 18 Sep 2021 06:04:14 +0000 Subject: [PATCH 456/587] chore(release): Publish [ci skip] - amplify-app@3.0.12 - amplify-category-analytics@2.21.21 - amplify-category-api@2.31.23 - amplify-category-auth@2.38.0 - amplify-category-function@2.34.7 - amplify-category-hosting@2.7.21 - amplify-category-interactions@2.6.5 - amplify-category-predictions@2.9.12 - amplify-category-storage@2.12.9 - amplify-category-xr@2.8.21 - amplify-cli-core@1.29.0 - @aws-amplify/cli@6.0.0 - amplify-console-hosting@1.9.12 - amplify-console-integration-tests@1.8.9 - amplify-container-hosting@1.3.23 - amplify-dotnet-function-template-provider@1.5.21 - amplify-dynamodb-simulator@1.19.12 - amplify-e2e-core@1.26.1 - amplify-e2e-tests@2.50.0 - amplify-frontend-ios@2.20.14 - amplify-frontend-javascript@2.24.1 - amplify-go-function-runtime-provider@1.9.4 - amplify-java-function-runtime-provider@1.8.14 - amplify-migration-tests@3.1.9 - amplify-nodejs-function-runtime-provider@1.6.11 - amplify-nodejs-function-template-provider@1.6.21 - amplify-provider-awscloudformation@4.60.1 - amplify-python-function-runtime-provider@1.9.11 - amplify-util-import@1.5.12 - amplify-util-mock@3.34.5 - graphql-auth-transformer@6.24.22 - graphql-connection-transformer@4.21.22 - graphql-dynamodb-transformer@6.22.22 - graphql-elasticsearch-transformer@4.12.1 - graphql-function-transformer@2.5.21 - graphql-http-transformer@4.18.9 - graphql-key-transformer@2.23.22 - graphql-predictions-transformer@2.5.21 - graphql-transformer-core@6.29.7 - graphql-transformers-e2e-tests@6.26.3 - graphql-versioned-transformer@4.17.22 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 6ad8a76ade..25ae29ee68 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8f4d51acea..6c42be1830 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.22", + "version": "2.31.23", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,7 +63,7 @@ "@aws-cdk/region-info": "~1.119.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.28.0", + "amplify-cli-core": "1.29.0", "amplify-headless-interface": "1.10.0", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", @@ -71,7 +71,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.6", - "graphql-transformer-core": "6.29.6", + "graphql-transformer-core": "6.29.7", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 02bd3af425f63427a0d62268e3c527b35670113b Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Wed, 22 Sep 2021 12:01:03 -0700 Subject: [PATCH 457/587] fix: #8223, conversion to typescript (#8245) * fix: #8223, conversion to typescript * chore: address pr feedback --- .../commands/api/add-graphql-datasource.js | 250 ------------------ .../commands/api/add-graphql-datasource.ts | 244 +++++++++++++++++ ...kthrough.js => appSync-rds-walkthrough.ts} | 137 +++++----- 3 files changed, 320 insertions(+), 311 deletions(-) delete mode 100644 packages/amplify-category-api/src/commands/api/add-graphql-datasource.js create mode 100644 packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts rename packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/{appSync-rds-walkthrough.js => appSync-rds-walkthrough.ts} (61%) diff --git a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js deleted file mode 100644 index 415da07562..0000000000 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.js +++ /dev/null @@ -1,250 +0,0 @@ -const fs = require('fs-extra'); -const inquirer = require('inquirer'); -const graphql = require('graphql'); -const path = require('path'); -const { RelationalDBSchemaTransformer } = require('graphql-relational-schema-transformer'); -const { RelationalDBTemplateGenerator, AuroraServerlessMySQLDatabaseReader } = require('graphql-relational-schema-transformer'); -const { mergeTypeDefs } = require('@graphql-tools/merge'); -const { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick } = require('amplify-cli-core'); -const subcommand = 'add-graphql-datasource'; -const categories = 'categories'; -const category = 'api'; -const providerName = 'awscloudformation'; - -const rdsRegion = 'rdsRegion'; -const rdsIdentifier = 'rdsClusterIdentifier'; -const rdsSecretStoreArn = 'rdsSecretStoreArn'; -const rdsDatabaseName = 'rdsDatabaseName'; -const rdsResourceName = 'rdsResourceName'; -const rdsDatasource = 'rdsDatasource'; -const rdsInit = 'rdsInit'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-datasources').supportedDatasources; - let resourceName; - let datasource; - let databaseName; - const AWS = await getAwsClient(context, 'list'); - return datasourceSelectionPrompt(context, servicesMetadata) - .then(result => { - datasource = result.datasource; // eslint-disable-line prefer-destructuring - - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - context.print.error('Provider not configured for this category'); - return; - } - - return providerController.addDatasource(context, category, result.datasource); - }) - .then(answers => { - resourceName = answers.resourceName; // eslint-disable-line prefer-destructuring - databaseName = answers.databaseName; // eslint-disable-line prefer-destructuring - - /** - * Write the new env specific datasource information into - * the team-provider-info file - */ - const currEnv = amplify.getEnvInfo().envName; - const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); - const teamProviderInfo = context.amplify.readJsonFile(teamProviderInfoFilePath); - - if (!teamProviderInfo[currEnv][categories]) { - teamProviderInfo[currEnv][categories] = {}; - } - - if (!teamProviderInfo[currEnv][categories][category]) { - teamProviderInfo[currEnv][categories][category] = {}; - } - - if (!teamProviderInfo[currEnv][categories][category][resourceName]) { - teamProviderInfo[currEnv][categories][category][resourceName] = {}; - } - - teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] = answers.region; - teamProviderInfo[currEnv][categories][category][resourceName][rdsIdentifier] = answers.dbClusterArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; - - fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); - - const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); - const backendConfig = context.amplify.readJsonFile(backendConfigFilePath); - - backendConfig[category][resourceName][rdsInit] = true; - - fs.writeFileSync(backendConfigFilePath, JSON.stringify(backendConfig, null, 4)); - - /** - * Load the MySqlRelationalDBReader - */ - // eslint-disable-next-line max-len - const dbReader = new AuroraServerlessMySQLDatabaseReader( - answers.region, - answers.secretStoreArn, - answers.dbClusterArn, - answers.databaseName, - AWS, - ); - - /** - * Instantiate a new Relational Schema Transformer and perform - * the db instrospection to get the GraphQL Schema and Template Context - */ - const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName); - return relationalSchemaTransformer.introspectDatabaseSchema(); - }) - .then(graphqlSchemaContext => { - const projectBackendDirPath = amplify.pathManager.getBackendDirPath(); - - /** - * Merge the GraphQL Schema with the existing schema.graphql in the projects stack - * - */ - const apiDirPath = `${projectBackendDirPath}/${category}/${resourceName}`; - fs.ensureDirSync(apiDirPath); - const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); - const schemaFileExists = fs.existsSync(graphqlSchemaFilePath); - const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const schemaDirectoryPath = path.join(apiDirPath, 'schema'); - const schemaDirectoryExists = fs.existsSync(schemaDirectoryPath); - - if (schemaFileExists) { - const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - - if (currGraphQLSchemaDoc) { - typesToBeMerged.unshift(currGraphQLSchemaDoc); - } else { - context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); - context.print.info(''); - } - - const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged, { all: true }); - fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); - } else if (schemaDirectoryExists) { - const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); - fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); - } else { - throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); - } - - const resolversDir = `${projectBackendDirPath}/${category}/${resourceName}/resolvers`; - - /** - * Instantiate a new Relational Template Generator and create - * the template and relational resolvers - */ - const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); - context[rdsResourceName] = resourceName; - context[rdsDatasource] = datasource; - let template = templateGenerator.createTemplate(context); - template = templateGenerator.addRelationalResolvers( - template, - resolversDir, - FeatureFlags.getBoolean('graphqltransformer.improvePluralization'), - ); - const cfn = templateGenerator.printCloudformationTemplate(template); - - /** - * Add the generated the CFN to the appropriate nested stacks directory - */ - const stacksDir = `${projectBackendDirPath}/${category}/${resourceName}/stacks`; - const writeToPath = `${stacksDir}/${resourceName}-${databaseName}-rds.json`; - fs.writeFileSync(writeToPath, cfn, 'utf8'); - - return datasource; - }) - .then(datasourceName => { - context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); - return datasourceName; - }) - .then(datasourceName => { - const { print } = context; - print.success(`Successfully added the ${datasourceName} datasource locally`); - print.info(''); - print.success('Some next steps:'); - print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - print.info(''); - }) - .catch(err => { - context.print.info(err.stack); - context.print.error('There was an error adding the datasource'); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, - readSchema, -}; - -function datasourceSelectionPrompt(context, supportedDatasources) { - 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 datasources defined by configured providers for category: ${category}`; - context.print.error(errMessage); - context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(1); - } - - if (options.length === 1) { - // No need to ask questions - context.print.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 datasources', - type: 'list', - choices: options, - }, - ]; - - return inquirer.prompt(question).then(answer => answer.datasource); -} - -async function getAwsClient(context, action) { - const providerPlugins = context.amplify.getProviderPlugins(context); - const provider = require(providerPlugins[providerName]); - return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); -} - -function readSchema(graphqlSchemaFilePath) { - const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); - const graphqlSchemaIsEmpty = graphqlSchemaRaw.trim().length === 0; - if (graphqlSchemaIsEmpty) { - return null; - } - - let currGraphQLSchemaDoc; - try { - currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); - } catch (err) { - const relativePathToInput = path.relative(process.cwd(), graphqlSchemaRaw); - throw new Error(`Could not parse graphql schema \n${relativePathToInput}\n${err.message}`); - } - return currGraphQLSchemaDoc; -} 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 new file mode 100644 index 0000000000..d4bd9be8d8 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -0,0 +1,244 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as graphql from 'graphql'; +import _ from 'lodash'; +import inquirer from 'inquirer'; +import { + RelationalDBSchemaTransformer, + RelationalDBTemplateGenerator, + AuroraServerlessMySQLDatabaseReader, +} from 'graphql-relational-schema-transformer'; +import { mergeTypeDefs } from '@graphql-tools/merge'; +import { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick, $TSAny, $TSContext, stateManager, pathManager } from 'amplify-cli-core'; + +const subcommand = 'add-graphql-datasource'; +const categories = 'categories'; +const category = 'api'; +const providerName = 'awscloudformation'; + +module.exports = { + name: subcommand, + run: async (context: $TSContext) => { + try { + const servicesMetadata = (await import('../../provider-utils/supported-datasources')).supportedDatasources; + + const AWS = await getAwsClient(context, 'list'); + + const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); + + const providerController = await import(`../../provider-utils/${result.providerName}/index`); + + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + + const { datasource } = result; + const answers = await providerController.addDatasource(context, category, datasource); + + const { resourceName, databaseName } = answers; + + /** + * Write the new env specific datasource information into + * the team-provider-info file + */ + const currEnv = context.amplify.getEnvInfo().envName; + const teamProviderInfo = stateManager.getTeamProviderInfo(); + + _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { + rdsRegion: answers.region, + rdsClusterIdentifier: answers.dbClusterArn, + rdsSecretStoreArn: answers.secretStoreArn, + rdsDatabaseName: answers.databaseName, + }); + + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); + + 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 instrospection to get the GraphQL Schema and Template Context + */ + const improvePluralizationFlag = FeatureFlags.getBoolean('graphqltransformer.improvePluralization'); + const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName, improvePluralizationFlag); + const graphqlSchemaContext = await relationalSchemaTransformer.introspectDatabaseSchema(); + + if (graphqlSchemaContext === null) { + context.print.warning('No importable tables were found in the selected Database.'); + context.print.info(''); + return; + } + + /** + * Merge the GraphQL Schema with the existing schema.graphql in the projects stack + * + */ + const apiDirPath = path.join(pathManager.getBackendDirPath(), 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 currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + + if (currGraphQLSchemaDoc) { + typesToBeMerged.unshift(currGraphQLSchemaDoc); + } else { + context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); + context.print.info(''); + } + + const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); + + fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); + } else if (fs.existsSync(schemaDirectoryPath)) { + const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); + + fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); + } else { + throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${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'); + + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); + + context.print.success(`Successfully added the ${datasource} datasource locally`); + context.print.info(''); + context.print.success('Some next steps:'); + context.print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); + context.print.info( + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', + ); + context.print.info(''); + } catch (error) { + context.print.info(error.stack); + context.print.error('There was an error adding the datasource'); + + await context.usageData.emitError(error); + + process.exitCode = 1; + } + }, + readSchema, +}; + +async function datasourceSelectionPrompt(context, supportedDatasources) { + 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 datasources defined by configured providers for category: ${category}`; + + context.print.error(errMessage); + + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + + exitOnNextTick(1); + } + + if (options.length === 1) { + // No need to ask questions + context.print.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 datasources', + type: 'list', + choices: options, + }, + ]; + + return inquirer.prompt(question).then(answer => answer.datasource); +} + +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); +} + +function readSchema(graphqlSchemaFilePath) { + const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); + + if (graphqlSchemaRaw.trim().length === 0) { + return null; + } + + let currGraphQLSchemaDoc: graphql.DocumentNode; + + try { + currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); + } catch (err) { + const relativePathToInput = path.relative(process.cwd(), graphqlSchemaRaw); + + const error = new Error(`Could not parse graphql schema \n${relativePathToInput}\n${err.message}`); + + error.stack = undefined; + + throw error; + } + + return currGraphQLSchemaDoc; +} diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts similarity index 61% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts index 441450bb9b..1d0a92fb11 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts @@ -1,13 +1,14 @@ -const inquirer = require('inquirer'); -const ora = require('ora'); -const { DataApiParams } = require('graphql-relational-schema-transformer'); -const { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick } = require('amplify-cli-core'); +import inquirer from 'inquirer'; +import chalk from 'chalk'; +import ora from 'ora'; +import { DataApiParams } from 'graphql-relational-schema-transformer'; +import { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick, $TSContext, $TSObject } from 'amplify-cli-core'; const spinner = ora(''); const category = 'api'; const providerName = 'awscloudformation'; -async function serviceWalkthrough(context, defaultValuesFilename, datasourceMetadata) { +export async function serviceWalkthrough(context: $TSContext, defaultValuesFilename: string, datasourceMetadata: $TSObject) { const amplifyMeta = context.amplify.getProjectMeta(); // Verify that an API exists in the project before proceeding. @@ -20,7 +21,7 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta } // Loop through to find the AppSync API Resource Name - let appSyncApi; + let appSyncApi: string; const apis = Object.keys(amplifyMeta[category]); for (let i = 0; i < apis.length; i += 1) { @@ -73,20 +74,30 @@ async function serviceWalkthrough(context, defaultValuesFilename, datasourceMeta * * @param {*} inputs */ -async function selectCluster(context, inputs, AWS) { +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'); - for (let i = 0; i < rawClusters.length; i += 1) { - if (rawClusters[i].EngineMode === 'serverless') { - clusters.set(rawClusters[i].DBClusterIdentifier, rawClusters[i]); - } + if (serverlessClusters.length === 0) { + const errMessage = 'No properly configured Aurora Serverless clusters found.'; + + context.print.error(errMessage); + + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + + exitOnNextTick(0); } - if (clusters.size > 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); @@ -95,10 +106,16 @@ async function selectCluster(context, inputs, AWS) { clusterResourceId: selectedCluster.DbClusterResourceId, }; } - const errMessage = 'No properly configured Aurora Serverless clusters found.'; - context.print.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); + + // Pick first and only value + const firstCluster = Array.from(clusters.values())[0]; + + context.print.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); + + return { + selectedClusterArn: firstCluster.DBClusterArn, + clusterResourceId: firstCluster.DbClusterResourceId, + }; } /** @@ -106,7 +123,7 @@ async function selectCluster(context, inputs, AWS) { * @param {*} inputs * @param {*} clusterResourceId */ -async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { +async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, AWS) { const SecretsManager = new AWS.SecretsManager(); const NextToken = 'NextToken'; let rawSecrets = []; @@ -126,32 +143,33 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { } const secrets = new Map(); - let selectedSecretArn; + const secretsForCluster = rawSecrets.filter(secret => secret.Name.startsWith(`rds-db-credentials/${clusterResourceId}`)); - for (let i = 0; i < rawSecrets.length; i += 1) { - /** - * Attempt to auto-detect Secret Store that was created by Aurora Serverless - * as it follows a specfic format for the Secret Name - */ - if (rawSecrets[i].Name.startsWith(`rds-db-credentials/${clusterResourceId}`)) { - // Found the secret store - store the details and break out. - selectedSecretArn = rawSecrets[i].ARN; - break; - } - secrets.set(rawSecrets[i].Name, rawSecrets[i].ARN); + if (secretsForCluster.length === 0) { + const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; + + context.print.error(errMessage); + + await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); + + exitOnNextTick(0); } - if (!selectedSecretArn) { - if (secrets.size > 0) { - // Kick off questions flow - const selectedSecretName = await promptWalkthroughQuestion(inputs, 2, Array.from(secrets.keys())); - selectedSecretArn = secrets.get(selectedSecretName); - } else { - const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; - context.print.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]; + + context.print.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); } return selectedSecretArn; @@ -163,7 +181,7 @@ async function getSecretStoreArn(context, inputs, clusterResourceId, AWS) { * @param {*} clusterArn * @param {*} secretArn */ -async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { +async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn, AWS) { // Database Name Question const DataApi = new AWS.RDSDataService(); const params = new DataApiParams(); @@ -176,17 +194,9 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { try { const dataApiResult = await DataApi.executeStatement(params).promise(); + const excludedDatabases = ['information_schema', 'performance_schema', 'mysql', 'sys']; - // eslint-disable-next-line prefer-destructuring - const records = dataApiResult.records; - - for (const record of records) { - const recordValue = record[0].stringValue; - // ignore the three meta tables that the cluster creates - if (!['information_schema', 'performance_schema', 'mysql'].includes(recordValue)) { - databaseList.push(recordValue); - } - } + databaseList.push(...dataApiResult.records.map(record => record[0].stringValue).filter(name => !excludedDatabases.includes(name))); spinner.succeed('Fetched Aurora Serverless cluster.'); } catch (err) { @@ -200,14 +210,23 @@ async function selectDatabase(context, inputs, clusterArn, secretArn, AWS) { } } - if (databaseList.length > 0) { + if (databaseList.length === 0) { + const errMessage = 'No database found in the selected cluster.'; + + context.print.error(errMessage); + + await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); + + exitOnNextTick(0); + } + + if (databaseList.length > 1) { return await promptWalkthroughQuestion(inputs, 3, databaseList); } - const errMessage = 'No properly configured databases found.'; - context.print.error(errMessage); - await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); - exitOnNextTick(0); + context.print.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); + + return databaseList[0]; } /** @@ -230,12 +249,8 @@ async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) { return answer[inputs[questionNumber].key]; } -async function getAwsClient(context, action) { +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); } - -module.exports = { - serviceWalkthrough, -}; From 1b8d630d5679bae092f7416350bf02491d4adc35 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 23 Sep 2021 11:51:46 -0700 Subject: [PATCH 458/587] chore: bump aws-cdk to ~1.124.0 (#8252) * chore: bump aws-cdk to ~1.124.0 * chore: update jsonServer deps --- packages/amplify-category-api/package.json | 88 +++++++++++----------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 6c42be1830..04d8cdc196 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,50 +17,50 @@ "test": "jest" }, "dependencies": { - "@aws-cdk/assets": "~1.119.0", - "@aws-cdk/aws-apigateway": "~1.119.0", - "@aws-cdk/aws-apigatewayv2": "~1.119.0", - "@aws-cdk/aws-applicationautoscaling": "~1.119.0", - "@aws-cdk/aws-autoscaling": "~1.119.0", - "@aws-cdk/aws-autoscaling-common": "~1.119.0", - "@aws-cdk/aws-autoscaling-hooktargets": "~1.119.0", - "@aws-cdk/aws-certificatemanager": "~1.119.0", - "@aws-cdk/aws-cloudformation": "~1.119.0", - "@aws-cdk/aws-cloudfront": "~1.119.0", - "@aws-cdk/aws-cloudwatch": "~1.119.0", - "@aws-cdk/aws-codebuild": "~1.119.0", - "@aws-cdk/aws-codeguruprofiler": "~1.119.0", - "@aws-cdk/aws-codepipeline": "~1.119.0", - "@aws-cdk/aws-codepipeline-actions": "~1.119.0", - "@aws-cdk/aws-cognito": "~1.119.0", - "@aws-cdk/aws-ec2": "~1.119.0", - "@aws-cdk/aws-ecr": "~1.119.0", - "@aws-cdk/aws-ecr-assets": "~1.119.0", - "@aws-cdk/aws-ecs": "~1.119.0", - "@aws-cdk/aws-efs": "~1.119.0", - "@aws-cdk/aws-elasticloadbalancing": "~1.119.0", - "@aws-cdk/aws-elasticloadbalancingv2": "~1.119.0", - "@aws-cdk/aws-events": "~1.119.0", - "@aws-cdk/aws-iam": "~1.119.0", - "@aws-cdk/aws-kms": "~1.119.0", - "@aws-cdk/aws-lambda": "~1.119.0", - "@aws-cdk/aws-logs": "~1.119.0", - "@aws-cdk/aws-route53": "~1.119.0", - "@aws-cdk/aws-route53-targets": "~1.119.0", - "@aws-cdk/aws-s3": "~1.119.0", - "@aws-cdk/aws-s3-assets": "~1.119.0", - "@aws-cdk/aws-sam": "~1.119.0", - "@aws-cdk/aws-secretsmanager": "~1.119.0", - "@aws-cdk/aws-servicediscovery": "~1.119.0", - "@aws-cdk/aws-sns": "~1.119.0", - "@aws-cdk/aws-sns-subscriptions": "~1.119.0", - "@aws-cdk/aws-sqs": "~1.119.0", - "@aws-cdk/aws-ssm": "~1.119.0", - "@aws-cdk/cloud-assembly-schema": "~1.119.0", - "@aws-cdk/core": "~1.119.0", - "@aws-cdk/custom-resources": "~1.119.0", - "@aws-cdk/cx-api": "~1.119.0", - "@aws-cdk/region-info": "~1.119.0", + "@aws-cdk/assets": "~1.124.0", + "@aws-cdk/aws-apigateway": "~1.124.0", + "@aws-cdk/aws-apigatewayv2": "~1.124.0", + "@aws-cdk/aws-applicationautoscaling": "~1.124.0", + "@aws-cdk/aws-autoscaling": "~1.124.0", + "@aws-cdk/aws-autoscaling-common": "~1.124.0", + "@aws-cdk/aws-autoscaling-hooktargets": "~1.124.0", + "@aws-cdk/aws-certificatemanager": "~1.124.0", + "@aws-cdk/aws-cloudformation": "~1.124.0", + "@aws-cdk/aws-cloudfront": "~1.124.0", + "@aws-cdk/aws-cloudwatch": "~1.124.0", + "@aws-cdk/aws-codebuild": "~1.124.0", + "@aws-cdk/aws-codeguruprofiler": "~1.124.0", + "@aws-cdk/aws-codepipeline": "~1.124.0", + "@aws-cdk/aws-codepipeline-actions": "~1.124.0", + "@aws-cdk/aws-cognito": "~1.124.0", + "@aws-cdk/aws-ec2": "~1.124.0", + "@aws-cdk/aws-ecr": "~1.124.0", + "@aws-cdk/aws-ecr-assets": "~1.124.0", + "@aws-cdk/aws-ecs": "~1.124.0", + "@aws-cdk/aws-efs": "~1.124.0", + "@aws-cdk/aws-elasticloadbalancing": "~1.124.0", + "@aws-cdk/aws-elasticloadbalancingv2": "~1.124.0", + "@aws-cdk/aws-events": "~1.124.0", + "@aws-cdk/aws-iam": "~1.124.0", + "@aws-cdk/aws-kms": "~1.124.0", + "@aws-cdk/aws-lambda": "~1.124.0", + "@aws-cdk/aws-logs": "~1.124.0", + "@aws-cdk/aws-route53": "~1.124.0", + "@aws-cdk/aws-route53-targets": "~1.124.0", + "@aws-cdk/aws-s3": "~1.124.0", + "@aws-cdk/aws-s3-assets": "~1.124.0", + "@aws-cdk/aws-sam": "~1.124.0", + "@aws-cdk/aws-secretsmanager": "~1.124.0", + "@aws-cdk/aws-servicediscovery": "~1.124.0", + "@aws-cdk/aws-sns": "~1.124.0", + "@aws-cdk/aws-sns-subscriptions": "~1.124.0", + "@aws-cdk/aws-sqs": "~1.124.0", + "@aws-cdk/aws-ssm": "~1.124.0", + "@aws-cdk/cloud-assembly-schema": "~1.124.0", + "@aws-cdk/core": "~1.124.0", + "@aws-cdk/custom-resources": "~1.124.0", + "@aws-cdk/cx-api": "~1.124.0", + "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.29.0", From a8c22524d7bbb7bcb3854549ac0b45cac956ce3e Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 24 Sep 2021 09:34:57 -0700 Subject: [PATCH 459/587] feat: Flag to allow schema changes that require table replacement (#8144) * chore: dumping table changes * chore: drop table POC * feat: plumb destructive-updates flag * feat: plumb rebuild * chore: fix rebuild prompts * test: adding unit and e2e tests * feat: sweet jesus it works * fix: iterative push lambda with updates * chore: organize code better * test: add unit and e2e tests * chore: fit and finish * chore: didn't save all the files * test: fix some tests and add a couple more * chore: address PR comments --- .../amplify-category-api/amplify-plugin.json | 25 +++----- packages/amplify-category-api/package.json | 1 + .../__tests__/commands/api/rebuild.test.ts | 64 +++++++++++++++++++ .../amplify-category-api/src/commands/api.js | 5 ++ .../src/commands/api/rebuild.ts | 40 ++++++++++++ packages/amplify-category-api/tsconfig.json | 2 + 6 files changed, 120 insertions(+), 17 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts create mode 100644 packages/amplify-category-api/src/commands/api/rebuild.ts diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 8cf4ad9d46..8bd97a6a3c 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -1,18 +1,9 @@ { - "name": "api", - "type": "category", - "commands": [ - "add-graphql-datasource", - "add", - "console", - "gql-compile", - "push", - "remove", - "update", - "help" - ], - "commandAliases":{ - "configure": "update" - }, - "eventHandlers": [] -} \ No newline at end of file + "name": "api", + "type": "category", + "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "push", "rebuild", "remove", "update", "help"], + "commandAliases": { + "configure": "update" + }, + "eventHandlers": [] +} diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 04d8cdc196..31940a9ea6 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -65,6 +65,7 @@ "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.29.0", "amplify-headless-interface": "1.10.0", + "amplify-prompts": "1.1.2", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", "constructs": "^3.3.125", 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 new file mode 100644 index 0000000000..ce28470ecd --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts @@ -0,0 +1,64 @@ +import { $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import { mocked } from 'ts-jest/utils'; +import { run } from '../../../commands/api/rebuild'; + +jest.mock('amplify-cli-core'); +jest.mock('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/commands/api.js b/packages/amplify-category-api/src/commands/api.js index 948dc4ae4a..e8c261e00d 100644 --- a/packages/amplify-category-api/src/commands/api.js +++ b/packages/amplify-category-api/src/commands/api.js @@ -41,6 +41,11 @@ module.exports = { name: 'console', description: 'Opens the web console for the selected api service', }, + { + 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', + }, ]; context.amplify.showHelp(header, commands); diff --git a/packages/amplify-category-api/src/commands/api/rebuild.ts b/packages/amplify-category-api/src/commands/api/rebuild.ts new file mode 100644 index 0000000000..2173ba77c4 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/rebuild.ts @@ -0,0 +1,40 @@ +import { $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { printer, prompter, exact } from 'amplify-prompts'; + +const subcommand = 'rebuild'; +const category = 'api'; + +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(([_, meta]) => (meta 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, category, resourceName, undefined, rebuild); +}; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index dd332b004a..31c85559bb 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -14,7 +14,9 @@ "src/__tests__" ], "references": [ + {"path": "../amplify-cli-core"}, {"path": "../amplify-headless-interface"}, + {"path": "../amplify-prompts"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, ] From 5770353e088ff0cad3fbc7721463b3ea0af22287 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Fri, 24 Sep 2021 12:15:17 -0700 Subject: [PATCH 460/587] Revert "feat: Flag to allow schema changes that require table replacement (#8144)" (#8268) This reverts commit a8c22524d7bbb7bcb3854549ac0b45cac956ce3e. --- .../amplify-category-api/amplify-plugin.json | 25 +++++--- packages/amplify-category-api/package.json | 1 - .../__tests__/commands/api/rebuild.test.ts | 64 ------------------- .../amplify-category-api/src/commands/api.js | 5 -- .../src/commands/api/rebuild.ts | 40 ------------ packages/amplify-category-api/tsconfig.json | 2 - 6 files changed, 17 insertions(+), 120 deletions(-) delete mode 100644 packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts delete mode 100644 packages/amplify-category-api/src/commands/api/rebuild.ts diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 8bd97a6a3c..8cf4ad9d46 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -1,9 +1,18 @@ { - "name": "api", - "type": "category", - "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "push", "rebuild", "remove", "update", "help"], - "commandAliases": { - "configure": "update" - }, - "eventHandlers": [] -} + "name": "api", + "type": "category", + "commands": [ + "add-graphql-datasource", + "add", + "console", + "gql-compile", + "push", + "remove", + "update", + "help" + ], + "commandAliases":{ + "configure": "update" + }, + "eventHandlers": [] +} \ No newline at end of file diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 31940a9ea6..04d8cdc196 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -65,7 +65,6 @@ "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.29.0", "amplify-headless-interface": "1.10.0", - "amplify-prompts": "1.1.2", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", "constructs": "^3.3.125", 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 ce28470ecd..0000000000 --- a/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; -import { mocked } from 'ts-jest/utils'; -import { run } from '../../../commands/api/rebuild'; - -jest.mock('amplify-cli-core'); -jest.mock('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/commands/api.js b/packages/amplify-category-api/src/commands/api.js index e8c261e00d..948dc4ae4a 100644 --- a/packages/amplify-category-api/src/commands/api.js +++ b/packages/amplify-category-api/src/commands/api.js @@ -41,11 +41,6 @@ module.exports = { name: 'console', description: 'Opens the web console for the selected api service', }, - { - 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', - }, ]; context.amplify.showHelp(header, commands); 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 2173ba77c4..0000000000 --- a/packages/amplify-category-api/src/commands/api/rebuild.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; -import { printer, prompter, exact } from 'amplify-prompts'; - -const subcommand = 'rebuild'; -const category = 'api'; - -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(([_, meta]) => (meta 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, category, resourceName, undefined, rebuild); -}; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 31c85559bb..dd332b004a 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -14,9 +14,7 @@ "src/__tests__" ], "references": [ - {"path": "../amplify-cli-core"}, {"path": "../amplify-headless-interface"}, - {"path": "../amplify-prompts"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, ] From fc76c7e23dfd31e031655d5c4d5a653af4d43de8 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 27 Sep 2021 18:50:31 +0000 Subject: [PATCH 461/587] chore(release): Publish [ci skip] - amplify-app@3.0.13 - amplify-category-analytics@2.21.22 - amplify-category-api@2.32.0 - amplify-category-auth@2.38.2 - amplify-category-function@2.35.0 - amplify-category-geo@1.0.1 - amplify-category-hosting@2.7.22 - amplify-category-interactions@2.6.6 - amplify-category-predictions@2.9.13 - amplify-category-storage@2.12.10 - amplify-category-xr@2.8.22 - amplify-cli-core@1.30.0 - @aws-amplify/cli@6.1.0 - amplify-console-hosting@1.9.13 - amplify-console-integration-tests@1.8.10 - amplify-container-hosting@1.3.24 - amplify-dotnet-function-template-provider@1.5.22 - amplify-dynamodb-simulator@1.19.13 - amplify-e2e-core@1.27.0 - amplify-e2e-tests@2.51.0 - amplify-frontend-ios@2.20.15 - amplify-frontend-javascript@2.24.2 - amplify-go-function-runtime-provider@1.9.5 - @aws-amplify/graphql-function-transformer@0.4.4 - @aws-amplify/graphql-http-transformer@0.5.4 - @aws-amplify/graphql-index-transformer@0.3.3 - @aws-amplify/graphql-model-transformer@0.6.3 - @aws-amplify/graphql-predictions-transformer@0.3.4 - @aws-amplify/graphql-relational-transformer@0.3.0 - @aws-amplify/graphql-searchable-transformer@0.6.1 - @aws-amplify/graphql-transformer-core@0.9.1 - @aws-amplify/graphql-transformer-interfaces@1.9.1 - amplify-java-function-runtime-provider@1.8.15 - amplify-migration-tests@3.1.10 - amplify-nodejs-function-runtime-provider@1.6.12 - amplify-nodejs-function-template-provider@1.6.22 - amplify-prompts@1.2.0 - amplify-provider-awscloudformation@4.61.0 - amplify-python-function-runtime-provider@1.9.12 - amplify-util-import@1.5.13 - amplify-util-mock@3.34.6 - graphql-auth-transformer@6.24.23 - graphql-connection-transformer@4.21.23 - graphql-dynamodb-transformer@6.22.23 - graphql-elasticsearch-transformer@4.12.2 - graphql-function-transformer@2.5.22 - graphql-http-transformer@4.18.10 - graphql-key-transformer@2.23.23 - graphql-predictions-transformer@2.5.22 - graphql-relational-schema-transformer@2.18.7 - graphql-transformer-common@4.19.10 - graphql-transformer-core@6.30.0 - graphql-transformers-e2e-tests@6.27.0 - graphql-versioned-transformer@4.17.23 --- packages/amplify-category-api/CHANGELOG.md | 21 +++++++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 25ae29ee68..a1cb9883ec 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,27 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 04d8cdc196..ad67328585 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.31.23", + "version": "2.32.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,15 +63,15 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.29.0", + "amplify-cli-core": "1.30.0", "amplify-headless-interface": "1.10.0", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.6", - "graphql-transformer-core": "6.29.7", + "graphql-relational-schema-transformer": "2.18.7", + "graphql-transformer-core": "6.30.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 692a94775055666ca5b901066c3ace7d001dfa3f Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Mon, 4 Oct 2021 16:47:50 -0700 Subject: [PATCH 462/587] feat: Custom policies IAM Policies for Lambda and Containers (#8068) * Custom policy implementation * feat: add custom policies file to function and API container add custom policies file to function and API container, merge the custom policies to CFN template, validation for regex of resources and actions in the custom policies file * feat: changes for first PR * feat: Some changes according to the PR comments 1. Add Json Schema to validate the customers input 2. some minor changes related to format issue 3. error handle * feat: replace env to current env in the resource when checkout and add env, and push * feat: e2e test and replacing env * feat: Minor changes for env replacement * feat: remove changing env between env * feat: Add cloudform type for type safety, move validation to provider-cloudformation, validation * feat: remove some unused function and import, change regex for resource * feat: Some changes according to the PR comment * feat: changes according to PR comments * feat: remove unused import * feat: remove previous unused code * feat: Changes according to PR comments * feat: some changes according to PR comments * feat: work on PR comments * feat: rebase for conflict * feat: rebase for failure of hooksmanager test failed * feat: unit test * feat: fix fail test * feat: change default template of custom policies * feat: fix failed test * feat: PR comments * feat: pr comments * feat: fix failed test * feat: PR comments from ED Co-authored-by: Lu Han --- .../provider-utils/awscloudformation/containers-handler.ts | 6 ++++++ 1 file changed, 6 insertions(+) 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 index d117d74517..0a402bd123 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts @@ -6,6 +6,7 @@ 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'; +import { createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; export const addResource = async ( serviceWalkthroughPromise: Promise, @@ -96,6 +97,10 @@ export const addResource = async ( } + createDefaultCustomPoliciesFile(category, resourceName); + + const customPoliciesPath = pathManager.getCustomPoliciesPath(category, resourceName); + context.print.success(`Successfully added resource ${resourceName} locally.`); context.print.info(''); context.print.success('Next steps:'); @@ -111,6 +116,7 @@ export const addResource = async ( context.print.info( `- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers`, ); + context.print.info(`- To access AWS resources outside of this Amplify app, edit the ${customPoliciesPath}`); context.print.info('- Run "amplify push" to build and deploy your image'); return resourceName; From 8949c37b445f44271374acc8b6298a2d6c4f90f3 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 6 Oct 2021 17:16:43 +0000 Subject: [PATCH 463/587] chore(release): Publish [ci skip] - amplify-app@3.0.14 - amplify-category-analytics@2.21.23 - amplify-category-api@2.33.0 - amplify-category-auth@2.38.3 - amplify-category-function@2.36.0 - amplify-category-geo@1.0.2 - amplify-category-hosting@2.7.23 - amplify-category-interactions@2.6.7 - amplify-category-predictions@2.9.14 - amplify-category-storage@2.12.11 - amplify-category-xr@2.8.23 - amplify-cli-core@1.31.0 - @aws-amplify/cli@6.2.0 - amplify-console-hosting@1.9.14 - amplify-console-integration-tests@1.8.12 - amplify-container-hosting@1.3.25 - amplify-dotnet-function-template-provider@1.5.23 - amplify-dynamodb-simulator@1.19.14 - amplify-e2e-core@1.28.0 - amplify-e2e-tests@2.52.0 - amplify-frontend-ios@2.20.16 - amplify-frontend-javascript@2.24.3 - amplify-go-function-runtime-provider@1.9.6 - amplify-java-function-runtime-provider@1.8.16 - amplify-migration-tests@3.1.12 - amplify-nodejs-function-runtime-provider@1.6.13 - amplify-nodejs-function-template-provider@1.6.23 - amplify-provider-awscloudformation@4.62.0 - amplify-python-function-runtime-provider@1.9.13 - amplify-util-import@1.5.14 - amplify-util-mock@3.34.8 - graphql-auth-transformer@6.24.25 - graphql-connection-transformer@4.21.24 - graphql-dynamodb-transformer@6.22.24 - graphql-elasticsearch-transformer@4.12.4 - graphql-function-transformer@2.5.23 - graphql-http-transformer@4.18.11 - graphql-key-transformer@2.23.24 - graphql-predictions-transformer@2.5.23 - graphql-transformer-core@6.30.1 - graphql-transformers-e2e-tests@6.27.2 - graphql-versioned-transformer@4.17.24 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index a1cb9883ec..2e43ff11d2 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ad67328585..a0f6f61ea1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.32.0", + "version": "2.33.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,7 +63,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.30.0", + "amplify-cli-core": "1.31.0", "amplify-headless-interface": "1.10.0", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", @@ -71,7 +71,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.7", - "graphql-transformer-core": "6.30.0", + "graphql-transformer-core": "6.30.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 61488351e72ebd83c75443a1952e47a013e9a32c Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Fri, 8 Oct 2021 12:03:51 -0700 Subject: [PATCH 464/587] fix(amplify-category-api): fixed api to reference stack name and deployment bucket (#8145) * fix(amplify-category-api): fixed api to reference stack name and deployment bucket * fix: addressed pr comments --- .../awscloudformation/base-api-stack.ts | 67 ++++-- .../awscloudformation/ecs-alb-stack.ts | 201 +++++++++--------- .../awscloudformation/ecs-apigw-stack.ts | 22 +- .../utils/containers-artifacts.ts | 5 +- 4 files changed, 160 insertions(+), 135 deletions(-) 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 index f495cbff5c..6f886524e5 100644 --- 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 @@ -2,6 +2,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; import * as ecr from '@aws-cdk/aws-ecr'; import * as ecs from '@aws-cdk/aws-ecs'; import * as iam from '@aws-cdk/aws-iam'; +import { CfnFunction } from '@aws-cdk/aws-lambda'; import * as logs from '@aws-cdk/aws-logs'; import * as s3 from '@aws-cdk/aws-s3'; import * as ssm from '@aws-cdk/aws-secretsmanager'; @@ -31,10 +32,8 @@ export enum DEPLOYMENT_MECHANISM { export type ContainersStackProps = Readonly<{ skipWait?: boolean; - envName: string; categoryName: string; apiName: string; - deploymentBucketName: string; dependsOn: ReadonlyArray<{ category: string; resourceName: string; @@ -70,6 +69,9 @@ export abstract class ContainersStack extends cdk.Stack { 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: cdk.Construct, id: string, private readonly props: ContainersStackProps) { super(scope, id); @@ -86,6 +88,9 @@ export abstract class ContainersStack extends cdk.Stack { isAuthCondition, appClientId, userPoolId, + envName, + deploymentBucketName, + awaiterS3Key, } = this.init(); this.parameters = parameters; @@ -100,7 +105,9 @@ export abstract class ContainersStack extends cdk.Stack { 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; @@ -192,6 +199,17 @@ export abstract class ContainersStack extends cdk.Stack { ), }); + 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, @@ -204,12 +222,14 @@ export abstract class ContainersStack extends cdk.Stack { isAuthCondition, userPoolId: paramUserPoolId && paramUserPoolId.valueAsString, appClientId: paramAppClientIdWeb && paramAppClientIdWeb.valueAsString, + envName: stackNameParameter.valueAsString, + deploymentBucketName: deploymentBucketName.valueAsString, + awaiterS3Key: awaiterS3Key.valueAsString, }; } private ecs() { const { - envName, categoryName, apiName, policies, @@ -245,7 +265,7 @@ export abstract class ContainersStack extends cdk.Stack { compatibility: ecs.Compatibility.FARGATE, memoryMiB: '1024', cpu: '512', - family: `${envName}-${apiName}`, + family: `${this.envName}-${apiName}`, }); (task.node.defaultChild as ecs.CfnTaskDefinition).overrideLogicalId('TaskDefinition'); policies.forEach(policy => { @@ -274,7 +294,7 @@ export abstract class ContainersStack extends cdk.Stack { secrets: containerSecrets, }) => { const logGroup = new logs.LogGroup(this, `${name}ContainerLogGroup`, { - logGroupName: `/ecs/${envName}-${apiName}-${name}`, + logGroupName: `/ecs/${this.envName}-${apiName}-${name}`, retention: logs.RetentionDays.ONE_MONTH, removalPolicy: cdk.RemovalPolicy.DESTROY, }); @@ -293,13 +313,13 @@ export abstract class ContainersStack extends cdk.Stack { if (build) { const logicalId = `${name}Repository`; - const repositoryName = `${envName}-${categoryName}-${apiName}-${name}`; + const repositoryName = `${this.envName}-${categoryName}-${apiName}-${name}`; if (this.props.existingEcrRepositories.has(repositoryName)) { repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); } else { repository = new ecr.Repository(this, logicalId, { - repositoryName: `${envName}-${categoryName}-${apiName}-${name}`, + repositoryName: `${this.envName}-${categoryName}-${apiName}-${name}`, removalPolicy: cdk.RemovalPolicy.RETAIN, lifecycleRules: [ { @@ -446,15 +466,15 @@ export abstract class ContainersStack extends cdk.Stack { }[]; gitHubSourceActionInfo?: GitHubSourceActionInfo; }) { - const { envName, deploymentBucketName, deploymentMechanism, desiredCount } = this.props; + const { deploymentMechanism, desiredCount } = this.props; const s3SourceActionKey = this.zipPath; - const bucket = s3.Bucket.fromBucketName(this, 'Bucket', deploymentBucketName); + const bucket = s3.Bucket.fromBucketName(this, 'Bucket', this.deploymentBucketName); const pipelineWithAwaiter = new PipelineWithAwaiter(this, 'ApiPipeline', { skipWait, - envName, + envName: this.envName, containersInfo, service, bucket, @@ -477,26 +497,29 @@ export abstract class ContainersStack extends cdk.Stack { const pipelineName = this.getPipelineName(); return `https://${region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${pipelineName}/view`; } - 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, + }; + } + }); + prepareApp(this); const cfn = this._toCloudFormation(); Object.keys(cfn.Parameters).forEach(k => { if (k.startsWith('AssetParameters')) { - let value = ''; - - if (k.includes('Bucket')) { - value = this.props.deploymentBucketName; - } else if (k.includes('VersionKey')) { - value = `${PIPELINE_AWAITER_ZIP}||`; - } - - cfn.Parameters[k].Default = value; + delete cfn.Parameters[k]; } }); - return cfn; } } 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 index acf1b119fe..c66f371960 100644 --- 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 @@ -7,14 +7,15 @@ import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; import * as route53targets from '@aws-cdk/aws-route53-targets'; import * as cdk from '@aws-cdk/core'; -import { ContainersStack, ContainersStackProps } from "./base-api-stack"; -import { v4 as uuid } from "uuid"; +import { ContainersStack, ContainersStackProps } from './base-api-stack'; +import { v4 as uuid } from 'uuid'; -type EcsStackProps = ContainersStackProps & Readonly<{ - domainName: string; - hostedZoneId?: string; - authName: string; -}>; +type EcsStackProps = ContainersStackProps & + Readonly<{ + domainName: string; + hostedZoneId?: string; + authName: string; + }>; export class EcsAlbStack extends ContainersStack { private readonly userPoolDomain: string; @@ -40,13 +41,9 @@ export class EcsAlbStack extends ContainersStack { private alb() { const { - envName, domainName, hostedZoneId, - exposedContainer: { - name: containerName, - port - }, + exposedContainer: { name: containerName, port }, restrictAccess, } = this.ecsProps; @@ -70,39 +67,37 @@ export class EcsAlbStack extends ContainersStack { ]); const [distributionDomainName, , domainNameSuffix] = domainName.match(/([^\.]+)\.(.*)/); - const lbPrefix = `lb-${envName}`; + 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, - }] + 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 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(), @@ -119,38 +114,44 @@ export class EcsAlbStack extends ContainersStack { 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, - }] + 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, + securityGroups: [albSecurityGroup.attrGroupId], + loadBalancerAttributes: [ + { + key: 'deletion_protection.enabled', + value: 'false', + }, ], - loadBalancerAttributes: [{ - key: 'deletion_protection.enabled', - value: 'false', - }], scheme: 'internet-facing', subnets, }); - (this.ecsService.loadBalancers) = [{ - containerName, - containerPort: port, - targetGroupArn: targetGroup.ref, - }]; + (this.ecsService.loadBalancers) = [ + { + containerName, + containerPort: port, + targetGroupArn: targetGroup.ref, + }, + ]; (this.ecsServiceSecurityGroup.securityGroupIngress).push({ ipProtocol: ec2.Protocol.TCP, fromPort: port, @@ -159,16 +160,18 @@ export class EcsAlbStack extends ContainersStack { }); const listener = new elb2.CfnListener(this, 'AlbListener', { - defaultActions: [{ - fixedResponseConfig: { - statusCode: '403', + defaultActions: [ + { + fixedResponseConfig: { + statusCode: '403', + }, + type: 'fixed-response', }, - type: 'fixed-response', - }], + ], loadBalancerArn: loadBalancer.ref, port: 443, protocol: elb2.Protocol.HTTPS, - certificates: [{ certificateArn: wildcardCertificate.ref }] + certificates: [{ certificateArn: wildcardCertificate.ref }], }); this.ecsService.addDependsOn(listener); @@ -178,20 +181,22 @@ export class EcsAlbStack extends ContainersStack { priority: 1, listenerArn: listener.ref, actions: [].concat( - restrictAccess ? { - order: actionsOrderCounter++, - type: 'authenticate-cognito', - authenticateCognitoConfig: { - userPoolArn, - userPoolClientId: userPoolClient.ref, - userPoolDomain, - } - } : undefined, + restrictAccess + ? { + order: actionsOrderCounter++, + type: 'authenticate-cognito', + authenticateCognitoConfig: { + userPoolArn, + userPoolClientId: userPoolClient.ref, + userPoolDomain, + }, + } + : undefined, { order: actionsOrderCounter++, type: 'forward', targetGroupArn: targetGroup.ref, - } + }, ), conditions: [ { @@ -205,8 +210,8 @@ export class EcsAlbStack extends ContainersStack { httpHeaderConfig: { httpHeaderName: sharedSecretHeaderName, values: [sharedSecretHeader], - } - } + }, + }, ], }); @@ -227,25 +232,29 @@ export class EcsAlbStack extends ContainersStack { queryString: true, }, targetOriginId: originId, - viewerProtocolPolicy: 'redirect-to-https' + viewerProtocolPolicy: 'redirect-to-https', }, - origins: [{ - customOriginConfig: { - originProtocolPolicy: 'https-only', + origins: [ + { + customOriginConfig: { + originProtocolPolicy: 'https-only', + }, + domainName: albDomainName, + id: originId, + originCustomHeaders: [ + { + headerName: sharedSecretHeaderName, + headerValue: sharedSecretHeader, + }, + ], }, - domainName: albDomainName, - id: originId, - originCustomHeaders: [{ - headerName: sharedSecretHeaderName, - headerValue: sharedSecretHeader, - }] - }], + ], viewerCertificate: { acmCertificateArn: wildcardCertificate.ref, minimumProtocolVersion: 'TLSv1.2_2019', sslSupportMethod: 'sni-only', }, - } + }, }); if (hostedZoneId) { @@ -257,7 +266,7 @@ export class EcsAlbStack extends ContainersStack { type: route53.RecordType.A, aliasTarget: { hostedZoneId: loadBalancer.attrCanonicalHostedZoneId, - dnsName: loadBalancer.attrDnsName + dnsName: loadBalancer.attrDnsName, }, }, { @@ -265,10 +274,10 @@ export class EcsAlbStack extends ContainersStack { type: route53.RecordType.A, aliasTarget: { hostedZoneId: route53targets.CloudFrontTarget.CLOUDFRONT_ZONE_ID, - dnsName: distribution.attrDomainName + dnsName: distribution.attrDomainName, }, - } - ] + }, + ], }); } @@ -278,8 +287,8 @@ export class EcsAlbStack extends ContainersStack { cdk.Aws.REGION, '.console.aws.amazon.com/codesuite/codepipeline/pipelines/', this.getPipelineName(), - '/view' - ]) + '/view', + ]), }); new cdk.CfnOutput(this, 'LoadBalancerAliasDomainName', { value: loadBalancer.attrDnsName }); 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 index 3925b5835b..4d740dd29d 100644 --- 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 @@ -1,13 +1,14 @@ import * as apigw2 from '@aws-cdk/aws-apigatewayv2'; import * as cdk from '@aws-cdk/core'; -import { ContainersStack, ContainersStackProps } from "./base-api-stack"; +import { ContainersStack, ContainersStackProps } from './base-api-stack'; import { API_TYPE } from './service-walkthroughs/containers-walkthrough'; -type EcsStackProps = Readonly; +type EcsStackProps = Readonly< + ContainersStackProps & { + apiType: API_TYPE; + } +>; export class EcsStack extends ContainersStack { - constructor(scope: cdk.Construct, id: string, private readonly ecsProps: EcsStackProps) { super(scope, id, { ...ecsProps, @@ -33,10 +34,10 @@ export class EcsStack extends ContainersStack { } private apiGateway() { - const { envName, apiName } = this.ecsProps + const { apiName } = this.ecsProps; const api = new apigw2.CfnApi(this, 'Api', { - name: `${envName}-${apiName}`, + name: `${this.envName}-${apiName}`, protocolType: 'HTTP', corsConfiguration: { allowHeaders: ['*'], @@ -67,12 +68,7 @@ export class EcsStack extends ContainersStack { authorizerType: 'JWT', jwtConfiguration: { audience: [this.appClientId], - issuer: cdk.Fn.join('', [ - 'https://cognito-idp.', - cdk.Aws.REGION, - '.amazonaws.com/', - this.userPoolId, - ]), + issuer: cdk.Fn.join('', ['https://cognito-idp.', cdk.Aws.REGION, '.amazonaws.com/', this.userPoolId]), }, identitySource: ['$request.header.Authorization'], }); 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 index c1745a4fb9..7ed760fa8f 100644 --- 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 @@ -54,7 +54,7 @@ export async function generateContainersArtifacts( providers: { [cloudformationProviderName]: provider }, } = context.amplify.getProjectMeta(); - const { StackName: envName, DeploymentBucketName: deploymentBucketName } = provider; + const { StackName: envName } = provider; const { category: categoryName, @@ -78,7 +78,6 @@ export async function generateContainersArtifacts( srcPath, askForExposedContainer, ); - const repositories = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'describeEcrRepositories'); const existingEcrRepositories: Set = new Set( @@ -88,7 +87,6 @@ export async function generateContainersArtifacts( ); const stack = new EcsStack(undefined, 'ContainersStack', { - envName, categoryName, apiName: resourceName, taskPorts: containersPorts, @@ -97,7 +95,6 @@ export async function generateContainersArtifacts( taskEnvironmentVariables: environmentMap, gitHubSourceActionInfo: gitHubInfo, deploymentMechanism, - deploymentBucketName, containers, isInitialDeploy, desiredCount, From b5d326ca902b0fc0b0a3b69d1ca44cbd81f80f44 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 10 Oct 2021 01:06:24 +0000 Subject: [PATCH 465/587] chore(release): Publish [ci skip] - amplify-app@3.0.15 - amplify-category-analytics@2.21.24 - amplify-category-api@2.33.1 - amplify-category-auth@2.38.4 - amplify-category-function@2.36.1 - amplify-category-geo@1.0.3 - amplify-category-hosting@2.7.24 - amplify-category-interactions@2.6.8 - amplify-category-predictions@2.9.15 - amplify-category-storage@2.12.12 - amplify-category-xr@2.8.24 - amplify-cli-core@1.31.1 - @aws-amplify/cli@6.3.0 - amplify-console-hosting@1.9.15 - amplify-console-integration-tests@1.8.13 - amplify-container-hosting@1.3.26 - amplify-dotnet-function-template-provider@1.5.24 - amplify-dynamodb-simulator@1.19.15 - amplify-e2e-core@1.29.0 - amplify-e2e-tests@2.53.0 - amplify-frontend-ios@2.20.17 - amplify-frontend-javascript@2.24.4 - amplify-go-function-runtime-provider@1.9.7 - @aws-amplify/graphql-default-value-transformer@0.2.0 - @aws-amplify/graphql-function-transformer@0.4.5 - @aws-amplify/graphql-http-transformer@0.5.5 - @aws-amplify/graphql-index-transformer@0.4.0 - @aws-amplify/graphql-model-transformer@0.6.4 - @aws-amplify/graphql-predictions-transformer@0.3.5 - @aws-amplify/graphql-relational-transformer@0.3.1 - @aws-amplify/graphql-searchable-transformer@0.6.3 - @aws-amplify/graphql-transformer-core@0.9.2 - @aws-amplify/graphql-transformer-interfaces@1.10.0 - amplify-java-function-runtime-provider@1.8.17 - amplify-migration-tests@3.1.13 - amplify-nodejs-function-runtime-provider@1.6.14 - amplify-nodejs-function-template-provider@1.6.24 - amplify-provider-awscloudformation@4.63.0 - amplify-python-function-runtime-provider@1.9.14 - amplify-util-import@1.5.15 - amplify-util-mock@3.34.10 - graphql-auth-transformer@6.24.26 - graphql-connection-transformer@4.21.25 - graphql-dynamodb-transformer@6.22.25 - graphql-elasticsearch-transformer@4.12.5 - graphql-function-transformer@2.5.24 - graphql-http-transformer@4.18.12 - graphql-key-transformer@2.23.25 - graphql-predictions-transformer@2.5.24 - graphql-transformer-core@6.30.2 - graphql-transformers-e2e-tests@6.28.0 - graphql-versioned-transformer@4.17.25 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 2e43ff11d2..bb0d42ef11 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a0f6f61ea1..017a3a46c9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.33.0", + "version": "2.33.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -63,7 +63,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.31.0", + "amplify-cli-core": "1.31.1", "amplify-headless-interface": "1.10.0", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", @@ -71,7 +71,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.7", - "graphql-transformer-core": "6.30.1", + "graphql-transformer-core": "6.30.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 086c02130a037c2f36667cb0c69db47f2a25c71a Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Tue, 12 Oct 2021 12:53:08 -0700 Subject: [PATCH 466/587] fix: api containers on repushing does not fail (#8416) * fix: api containers on repushing does not fail --- .../src/provider-utils/awscloudformation/base-api-stack.ts | 4 +++- .../awscloudformation/utils/containers-artifacts.ts | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) 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 index 6f886524e5..7eecf409af 100644 --- 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 @@ -52,6 +52,7 @@ export type ContainersStackProps = Readonly<{ createCloudMapService?: boolean; gitHubSourceActionInfo?: GitHubSourceActionInfo; existingEcrRepositories: Set; + currentStackName: string; }>; export abstract class ContainersStack extends cdk.Stack { protected readonly vpcId: string; @@ -240,6 +241,7 @@ export abstract class ContainersStack extends cdk.Stack { taskPorts, isInitialDeploy, desiredCount, + currentStackName, createCloudMapService, } = this.props; @@ -313,7 +315,7 @@ export abstract class ContainersStack extends cdk.Stack { if (build) { const logicalId = `${name}Repository`; - const repositoryName = `${this.envName}-${categoryName}-${apiName}-${name}`; + const repositoryName = `${currentStackName}-${categoryName}-${apiName}-${name}`; if (this.props.existingEcrRepositories.has(repositoryName)) { repository = ecr.Repository.fromRepositoryName(this, logicalId, repositoryName); 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 index 7ed760fa8f..51da9da2da 100644 --- 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 @@ -99,6 +99,7 @@ export async function generateContainersArtifacts( isInitialDeploy, desiredCount, restrictAccess, + currentStackName: envName, apiType, exposedContainer, secretsArns, From 43c4c3d86f863686b5e3ff8432d4a0b17b5168a4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 13 Oct 2021 03:45:11 +0000 Subject: [PATCH 467/587] chore(release): Publish [ci skip] - amplify-app@3.0.16 - amplify-category-api@2.33.2 - amplify-category-geo@1.1.0 - @aws-amplify/cli@6.3.1 - amplify-console-integration-tests@1.8.14 - amplify-container-hosting@1.3.27 - amplify-e2e-core@1.30.0 - amplify-e2e-tests@2.54.0 - amplify-frontend-javascript@2.25.0 - amplify-migration-tests@3.1.14 - amplify-provider-awscloudformation@4.64.0 - amplify-util-mock@3.34.11 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index bb0d42ef11..be752508e9 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 017a3a46c9..e5fe23c82d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.33.1", + "version": "2.33.2", "description": "amplify-cli api plugin", "repository": { "type": "git", From ad98f181034c118bd5966e6bf982b0d9b6d4bfda Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Thu, 14 Oct 2021 14:51:04 -0400 Subject: [PATCH 468/587] Merge GraphQL v-next to master (#8287) * feat(cli-api): improve add and update api * Delete sam.schema.json * Delete cloudformation.schema.json * remove auto apply authmode code from update api workflow * remove unused import * fix lint issues * relative import * fix dependencies * fix lint comments * remove unused code * updated v2 templates * remove unused import * change to use executeProviderUtils * fixed formatting * several minor tweaks to add and update api workflow * update conflict detection label * remove app not deployed message * auto apply auth mode * auto apply authmode for v2 tranformer * add type amplify_global to v2 schemas * Update many-relationship-schema-v2.graphql * Update single-object-auth-schema-v2.graphql * Update single-object-schema-v2.graphql * feat: add @auth (#1) * feat: add @auth base package with Access Control * feat: graphql auth v2 add schemaChanges, iam policy generation, and query/read resolvers * feat: graphql auth v2 add auth on mutation and subscription resolvers * feat(amplify-category-api): add global sandbox mode directive on schema generation (#8074) * feat(amplify-category-api): add global sandbox mode directive on schema generation * test(amplify-e2e-tests): add e2e tests for sandbox mode * test(amplify-category-api): add unit test for generating sandbox mode directive; rm unused method * feat(cli): add sandbox mode warning to amplify status (#8078) * feat(amplify-category-api): prompt api key creation on amplify push (#8124) * feat(amplify-category-api): prompt api key create when invalid with sandbox mode * test(amplify-category-api): add unit tests for provider utils * test(amplify-category-api): fix test for adding api key prompt * refactor(cli): refactor api key prompt * refactor(amplify-category-api): add api key with gql compiled * feat: @model conflict resolution * auth directive support for index, searchable, predictions, functions, and relational directives (#8146) * feat: add support for index and updated unit and e2e tests * feat: directive suport for functions, predictions, searchable, and relational * test: updated unit tests for updated auth on directives * @auth support for datastore and add has auth flag (#8168) * feat: @auth v2 on datastore and updated unit tests * feat: add hasAuthFlag * feat(graphql-model-transformer): set up transformer for sandbox mode directive (#8138) * feat(graphql-model-transformer): add sandbox mode support to model transformer * refactor(graphql-transformer-core): do not persist sandbox mode meta data * fix: add command to show access control and field auth evaluation in access control (#8174) * fix: admin ui app state check and auth transformer index resolver name (#8175) * fix: has auth typo and qref on field conditions for private rule (#8180) * fix(graphql-model-transformer): use hasAuth flag when sandbox mode is disabled (#8179) * fix: update hasMany to use join table name, sync config warning, updated unit test * fix: add empty payload for sandbox mode * fix: snapshot test for @searchable * fix: udpated snapshot for index and relation directives * fix: use same none datasource name as resolver manager * fix: iam resolver check and relational payload (#8234) * fix: add datastore query in config for auth (#8246) * fix: auth filter expression (#8248) * fix: update iam auth to include roles in before template (#8259) * chore: rebase and update auth dependencies * fix(graphql-model-transformer): iam role name does not exceed 64 characters * fix: add base e2e tests with auth fixes Co-authored-by: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Co-authored-by: lazpavel <85319655+lazpavel@users.noreply.github.com> * fix: update dependency versions * feat(amplify-provider-awscloudformation): match env directive field for sandbox mode (#3) * fix(amplify-provider-awscloudformation): invoke api function from invoker plugin (#8274) * fix(amplify-provider-awscloudformation): invoke api function from invoker plugin * fix(graphql-index-transformer): update snapshots for tests * test(amplify-provider-awscloudformation): fix tests for sandbox helpers * fix(amplify-provider-awscloudformation): remove sandbox mode directive from schema before transform (#8272) * chore(graphql-auth-transformer): update deps for auth transformer and api category * fix(graphql-model-transformer): revert code to master version * test(graphql-model-transformer): update the snapshot for the amplify/graphql-model-transformer test * chore: remove showacm as that was for testing purposes only * test(amplify-e2e-tests): update to use correct helpers * test(graphql-transformers-e2e-tests): enable sandbox mode on v2 transforms * test(amplify-e2e-tests): replace updateAPIResolution imports with new methods * fix: get item query for @model and relational directives * auto apply auth fix * auto apply auth modes v2 fix (#4) * test(amplify-e2e-tests): rm sandbox e2e test * fix(amplify-provider-awscloudformation): fix api key creation when sandbox mode enable * test(amplify-e2e-tests): create random app name generator for broken tests * fix api e2e workflow * test(amplify-e2e-core): add random app name generator, update snapshots and imports * chore(graphql-auth-transformer): upgrade deps in auth transformer * update e2e test to use new api workflow (#5) * feat(graphql-model-transformer): fix default value e2e test (#6) * test(amplify-e2e-tests): add missing helper * e2e fix for auth tests using new api workflow (#7) * update e2e test to use new api workflow * fix(test): update auth tests with new api workflow * test(amplify-e2e-tests): add missing helper and fix broken test Co-authored-by: Christopher Sundersingh Co-authored-by: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Co-authored-by: Josue Ruiz <7465495+SwaySway@users.noreply.github.com> Co-authored-by: lazpavel <85319655+lazpavel@users.noreply.github.com> Co-authored-by: Colin Ihrig --- packages/amplify-category-api/package.json | 2 + .../graphql-schemas/blank-schema.graphql | 0 .../many-relationship-schema-v2.graphql | 18 + .../single-object-auth-schema-v2.graphql | 15 + .../single-object-schema-v2.graphql | 5 + .../cfn-api-artifact-handler.test.ts.snap | 1 + .../cfn-api-artifact-handler.test.ts | 2 +- .../prompt-to-add-api-key.test.ts | 44 ++ .../appSync-walkthrough.test.ts | 2 +- ...p-sync-auth-type-bi-di-mapper.test.ts.snap | 2 + .../utils/global-sandbox-mode.test.ts | 21 + packages/amplify-category-api/src/index.ts | 33 + .../provider-utils/api-artifact-handler.ts | 6 +- .../cfn-api-artifact-handler.ts | 17 +- .../prompt-to-add-api-key.ts | 27 + .../appSync-walkthrough.ts | 627 ++++++++++++------ ...nfig-to-app-sync-auth-type-bi-di-mapper.ts | 2 + .../utils/edit-schema-flow.ts | 2 +- .../utils/global-sandbox-mode.ts | 10 + .../src/provider-utils/supported-services.ts | 4 + 20 files changed, 618 insertions(+), 222 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/blank-schema.graphql create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e5fe23c82d..fa76cb5945 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -65,6 +65,8 @@ "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.31.1", "amplify-headless-interface": "1.10.0", + "amplify-prompts": "1.2.0", + "amplify-provider-awscloudformation": "4.61.1", "amplify-util-headless-input": "1.5.4", "chalk": "^4.1.1", "constructs": "^3.3.125", 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 new file mode 100644 index 0000000000..e69de29bb2 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 new file mode 100644 index 0000000000..2619b18729 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/many-relationship-schema-v2.graphql @@ -0,0 +1,18 @@ +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/single-object-auth-schema-v2.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql new file mode 100644 index 0000000000..0faf0997d4 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-auth-schema-v2.graphql @@ -0,0 +1,15 @@ +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-schema-v2.graphql b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql new file mode 100644 index 0000000000..74b097ceae --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-schemas/single-object-schema-v2.graphql @@ -0,0 +1,5 @@ +type Todo @model { + id: ID! + name: String! + description: String +} 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 index 36f39965a9..3b9aa6928f 100644 --- 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 @@ -18,6 +18,7 @@ Object { }, Object { "apiKeyConfig": Object { + "apiKeyExpirationDate": undefined, "apiKeyExpirationDays": undefined, "description": undefined, }, 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 index 28e2aec71d..e8dfa51770 100644 --- 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 @@ -30,7 +30,7 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', jest.mock('amplify-cli-core'); -const fs_mock = (fs as unknown) as jest.Mocked; +const fs_mock = fs as unknown as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; 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 new file mode 100644 index 0000000000..871b8c8f1e --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/prompt-to-add-api-key.test.ts @@ -0,0 +1,44 @@ +import { $TSContext } from 'amplify-cli-core'; +import * as prompts from '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('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/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts index a664b0b469..1d7ed55cdf 100644 --- 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 @@ -3,7 +3,7 @@ import { askAdditionalAuthQuestions, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { FeatureFlags, CLIEnvironmentProvider, FeatureFlagRegistration } from 'amplify-cli-core'; +import { FeatureFlags } from 'amplify-cli-core'; jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), 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 index 73049e4ca9..3c18c0fa24 100644 --- 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 @@ -12,6 +12,7 @@ Object { exports[`AppSyncAuthType to authConfig maps API_KEY correctly 1`] = ` Object { "apiKeyConfig": Object { + "apiKeyExpirationDate": undefined, "apiKeyExpirationDays": 120, "description": undefined, }, @@ -47,6 +48,7 @@ Object { exports[`authConfig to AppSyncAuthType maps API_KEY auth correctly 1`] = ` Object { + "apiKeyExpirationDate": undefined, "expirationTime": 120, "keyDescription": "api key description", "mode": "API_KEY", 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 new file mode 100644 index 0000000000..a895da7f66 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/global-sandbox-mode.test.ts @@ -0,0 +1,21 @@ +import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudformation/utils/global-sandbox-mode'; +import { $TSContext } from 'amplify-cli-core'; + +describe('global sandbox mode GraphQL directive', () => { + it('returns AMPLIFY_DIRECTIVE type with code comment, directive, and env name', () => { + const envName = 'envone'; + const ctx = <$TSContext>{ + amplify: { + getEnvInfo() { + return { envName }; + }, + }, + }; + + expect(defineGlobalSandboxMode(ctx)) + .toBe(`# This allows public create, read, update, and delete access for a limited time to all models via API Key. +# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth +type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n +`); + }); +}); diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index af7f162501..3593ba6b97 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -3,6 +3,9 @@ import fs from 'fs-extra'; import path from 'path'; import { run } from './commands/api/console'; import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn-api-artifact-handler'; +import { askAuthQuestions } from './provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; +import { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; +import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; export { NETWORK_STACK_LOGICAL_ID } from './category-constants'; export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack'; @@ -15,6 +18,7 @@ export { processDockerConfig, } from './provider-utils/awscloudformation/utils/containers-artifacts'; export { getContainers } from './provider-utils/awscloudformation/docker-compose'; +export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; const category = 'api'; @@ -217,3 +221,32 @@ export async function handleAmplifyEvent(context, args) { context.print.info(`${category} handleAmplifyEvent to be implemented`); context.print.info(`Received event args ${args}`); } + +export async function addGraphQLAuthorizationMode(context, args) { + const { authType, printLeadText, authSettings } = args; + const apiName = getAppSyncResourceName(context.amplify.getProjectMeta()); + if (!apiName) { + return; + } + + const authConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + 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; +} \ No newline at end of file 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 index a3b7de27c5..7dbab41d77 100644 --- a/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/api-artifact-handler.ts @@ -1,6 +1,10 @@ import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; +export interface ApiArtifactHandlerOptions { + skipCompile?: boolean; +} + export interface ApiArtifactHandler { createArtifacts(request: AddApiRequest): Promise; - updateArtifacts(request: UpdateApiRequest): Promise; + updateArtifacts(request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise; } 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 index cc421715b5..f06fc27941 100644 --- 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 @@ -12,7 +12,7 @@ import _ from 'lodash'; import * as path from 'path'; import uuid from 'uuid'; import { category } from '../../category-constants'; -import { ApiArtifactHandler } from '../api-artifact-handler'; +import { ApiArtifactHandler, ApiArtifactHandlerOptions } from '../api-artifact-handler'; import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants'; import { authConfigHasApiKey, checkIfAuthExists, getAppSyncAuthConfig, getAppSyncResourceName } from './utils/amplify-meta-utils'; import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; @@ -96,7 +96,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { // 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): Promise => { + updateArtifacts = async (request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise => { const updates = request.serviceModification; const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); if (!apiName) { @@ -118,11 +118,14 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { if (updates.additionalAuthTypes) { authConfig.additionalAuthenticationProviders = updates.additionalAuthTypes.map(appSyncAuthTypeToAuthConfig); } - await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { - resourceDir, - parameters: this.getCfnParameters(apiName, authConfig, resourceDir), - authConfig, - }); + + if (!opts?.skipCompile) { + await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { + resourceDir, + parameters: this.getCfnParameters(apiName, authConfig, resourceDir), + authConfig, + }); + } this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); 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 new file mode 100644 index 0000000000..4e3a92b5ea --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/prompt-to-add-api-key.ts @@ -0,0 +1,27 @@ +import { $TSContext } from 'amplify-cli-core'; +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'; +import { prompter } from 'amplify-prompts'; + +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-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index f2878dbb50..c8561d30e0 100644 --- 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 @@ -4,12 +4,13 @@ import inquirer from 'inquirer'; import fs from 'fs-extra'; import path from 'path'; import { rootAssetDir } from '../aws-constants'; -import { collectDirectivesByTypeNames, readProjectConfiguration, ConflictHandlerType } from 'graphql-transformer-core'; +import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; import { category } from '../../../category-constants'; import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; +import chalk from 'chalk'; import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; import { ResourceAlreadyExistsError, @@ -21,6 +22,8 @@ import { $TSContext, open, } from 'amplify-cli-core'; +import { Duration, Expiration } from '@aws-cdk/core'; +import { defineGlobalSandboxMode } from '../utils/global-sandbox-mode'; const serviceName = 'AppSync'; const elasticContainerServiceName = 'ElasticContainer'; @@ -46,6 +49,63 @@ const authProviderChoices = [ }, ]; +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 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: 'blank-schema.graphql', + }, +]; + +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: 'blank-schema.graphql', + }, +]; + export const openConsole = async (context: $TSContext) => { const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; @@ -136,90 +196,129 @@ export const openConsole = async (context: $TSContext) => { } }; -export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { - const resourceName = resourceAlreadyExists(context); +const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { + let continuePrompt = false; let authConfig; let defaultAuthType; let resolverConfig; - - 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.'; - context.print.warning(errMessage); - await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); - exitOnNextTick(0); - } - const { amplify } = context; const { inputs } = serviceMetadata; const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - 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; + 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: [], + }; - // API name question + // + // 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 resourceAnswers = await inquirer.prompt(resourceQuestions); - resourceAnswers[inputs[0].key] = resourceAnswers[inputs[1].key]; + const getAdditionalAuthModeChoices = async () => { + let additionalAuthModesText = ''; + authConfig.additionalAuthenticationProviders.map(async authMode => { + additionalAuthModesText += `, ${authProviderChoices.find(choice => choice.value === authMode.authenticationType).name}`; + }); + return additionalAuthModesText; + }; + + const basicInfoQuestionChoices = []; - // Ask additonal questions + basicInfoQuestionChoices.push({ + name: chalk`{bold Name:} ${resourceAnswers[inputs[1].key]}`, + value: 'API_NAME', + }); - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); - ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, authConfig, defaultAuthType)); + basicInfoQuestionChoices.push({ + name: chalk`{bold Authorization modes:} ${await getAuthModeChoice()}${await getAdditionalAuthModeChoices()}`, + value: 'API_AUTH_MODE', + }); - // Ask schema file question + basicInfoQuestionChoices.push({ + name: chalk`{bold Conflict detection (required for DataStore):} ${resolverConfig?.project ? 'Enabled' : 'Disabled'}`, + value: 'CONFLICT_DETECTION', + }); - const schemaFileQuestion = { - type: inputs[2].type, - name: inputs[2].key, - message: inputs[2].question, - validate: amplify.inputValidation(inputs[2]), - default: () => { - const defaultValue = allDefaultValues[inputs[2].key]; - return defaultValue; - }, - }; + if (resolverConfig?.project) { + basicInfoQuestionChoices.push({ + name: chalk`{bold Conflict resolution strategy:} ${ + conflictResolutionHanlderChoices.find(x => x.value === resolverConfig.project.ConflictHandler).name + }`, + value: 'CONFLICT_STRATEGY', + }); + } - const schemaFileAnswer = await inquirer.prompt(schemaFileQuestion); + basicInfoQuestionChoices.push({ + name: 'Continue', + value: 'CONTINUE', + }); - let schemaContent = ''; - let askToEdit = true; - if (schemaFileAnswer[inputs[2].key]) { - // User has an annotated schema file - const filePathQuestion = { - type: inputs[3].type, - name: inputs[3].key, - message: inputs[3].question, - validate: amplify.inputValidation(inputs[3]), - }; - const { schemaFilePath } = await inquirer.prompt(filePathQuestion); - schemaContent = fs.readFileSync(schemaFilePath, 'utf8'); - askToEdit = false; - } else { - // Schema template selection - const templateSelectionQuestion = { - type: inputs[4].type, - name: inputs[4].key, - message: inputs[4].question, - choices: inputs[4].options.filter(templateSchemaFilter(authConfig)), - validate: amplify.inputValidation(inputs[4]), + 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, }; - const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); - const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent = fs.readFileSync(schemaFilePath, 'utf8'); + 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]; + 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 { @@ -227,8 +326,99 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen output: { authConfig, }, - noCfnFile: true, resolverConfig, + }; +}; + +const updateApiInputWalkthrough = async (context, project, 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, defaultValuesFilename, serviceMetadata) => { + const resourceName = resourceAlreadyExists(context); + const useExperimentalPipelineTransformer = FeatureFlags.getBoolean('graphQLTransformer.useExperimentalPipelinedTransformer'); + + 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.'; + context.print.warning(errMessage); + await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); + exitOnNextTick(0); + } + + const { amplify } = context; + const { inputs } = serviceMetadata; + + const basicInfoAnswers = await serviceApiInputWalkthrough(context, defaultValuesFilename, serviceMetadata); + let schemaContent = ''; + let askToEdit = true; + + // Schema template selection + const schemaTemplateOptions = useExperimentalPipelineTransformer ? 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 += useExperimentalPipelineTransformer ? defineGlobalSandboxMode(context) : ''; + schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); + + return { + ...basicInfoAnswers, + noCfnFile: true, schemaContent, askToEdit, }; @@ -238,13 +428,13 @@ export const updateWalkthrough = async (context): Promise => { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; + let resource; let authConfig; - let defaultAuthType; const resources = allResources.filter(resource => resource.service === 'AppSync'); // There can only be one appsync resource if (resources.length > 0) { - const resource = resources[0]; + resource = resources[0]; if (resource.providerPlugin !== providerName) { // TODO: Move message string to seperate file throw new Error( @@ -265,6 +455,8 @@ export const updateWalkthrough = async (context): Promise => { 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 = []; @@ -276,45 +468,8 @@ export const updateWalkthrough = async (context): Promise => { } }); } - const updateChoices = [ - { - name: 'Walkthrough all configurations', - value: 'all', - }, - { - name: 'Update auth settings', - value: 'authUpdate', - }, - ]; - // check if DataStore is enabled for the entire API - if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - updateChoices.push({ name: 'Disable DataStore for entire API', value: 'disableDatastore' }); - } else { - updateChoices.push({ name: 'Enable DataStore for entire API', value: 'enableDatastore' }); - } - - const updateOptionQuestion = { - type: 'list', - name: 'updateOption', - message: 'Select from the options below', - choices: updateChoices, - }; - const { updateOption } = await inquirer.prompt([updateOptionQuestion]); - - if (updateOption === 'enableDatastore') { - resolverConfig = { - project: { ConflictHandler: ConflictHandlerType.AUTOMERGE, ConflictDetection: 'VERSION' }, - }; - } else if (updateOption === 'disableDatastore') { - resolverConfig = {}; - } else if (updateOption === 'authUpdate') { - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); - authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); - } else if (updateOption === 'all') { - ({ authConfig, defaultAuthType } = await askDefaultAuthQuestion(context)); - ({ authConfig, resolverConfig } = await askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes)); - } + ({ authConfig, resolverConfig } = await updateApiInputWalkthrough(context, project, resolverConfig, modelTypes)); return { version: 1, @@ -330,111 +485,130 @@ export const updateWalkthrough = async (context): Promise => { }; }; -async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { - let resolverConfig; +async function displayApiInformation(context, resource, project) { + 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)}`); + }); - const advancedSettingsQuestion = { - type: 'list', - name: 'advancedSettings', - message: 'Do you want to configure advanced settings for the GraphQL API', - choices: [ - { - name: 'No, I am done.', - value: false, - }, - { - name: 'Yes, I want to make some additional changes.', - value: true, - }, - ], - }; + context.print.info(''); - const advancedSettingsAnswer = await inquirer.prompt([advancedSettingsQuestion]); + context.print.success('General information'); + context.print.info('- Name: '.concat(resource.resourceName)); + if (resource?.output?.GraphQLAPIEndpointOutput) { + context.print.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); + } + context.print.info(''); - if (advancedSettingsAnswer.advancedSettings) { - authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); - resolverConfig = await askResolverConflictQuestion(context, modelTypes); + context.print.success('Authorization modes'); + authModes.forEach(authMode => context.print.info(authMode)); + context.print.info(''); + + context.print.success('Conflict detection (required for DataStore)'); + if (project.config && !_.isEmpty(project.config.ResolverConfig)) { + context.print.info( + `- Conflict resolution strategy: ${ + conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name + }`, + ); + } else { + context.print.info('- Disabled'); } - return { authConfig, resolverConfig }; + context.print.info(''); } -async function askResolverConflictQuestion(context, modelTypes?) { - let resolverConfig: any = {}; +async function displayAuthMode(context, resource, authMode) { + if (authMode == 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { + let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getAppSyncApiKeys', { + 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; +} - if (await context.prompt.confirm('Enable conflict detection?')) { - const askConflictResolutionStrategy = async msg => { - let conflictResolutionStrategy; - - do { - const conflictResolutionQuestion: ListQuestion = { - type: 'list', - name: 'conflictResolutionStrategy', - message: msg, - default: 'AUTOMERGE', - choices: [ - { - name: 'Auto Merge', - value: 'AUTOMERGE', - }, - { - name: 'Optimistic Concurrency', - value: 'OPTIMISTIC_CONCURRENCY', - }, - { - name: 'Custom Lambda', - value: 'LAMBDA', - }, - { - name: 'Learn More', - value: 'Learn More', - }, - ], - }; - if (conflictResolutionStrategy === 'Learn More') { - conflictResolutionQuestion.prefix = dataStoreLearnMore; - } - ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); - } while (conflictResolutionStrategy === 'Learn More'); +async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { + authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); + return { authConfig }; +} - let syncConfig: any = { - ConflictHandler: conflictResolutionStrategy, - ConflictDetection: 'VERSION', - }; +async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) { + let resolverConfigResponse: any = {}; + + if (await context.prompt.confirm('Enable conflict detection?', !resolverConfig?.project)) { + resolverConfigResponse = await askResolverConflictHandlerQuestion(context, modelTypes); + } + + return resolverConfigResponse; +} - if (conflictResolutionStrategy === 'LAMBDA') { - const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); - syncConfig.LambdaConflictHandler = { - name: lambdaFunctionName, - new: newFunction, - }; +async function askResolverConflictHandlerQuestion(context, modelTypes?) { + let resolverConfig: any = {}; + 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'); - return syncConfig; + let syncConfig: any = { + ConflictHandler: conflictResolutionStrategy, + ConflictDetection: 'VERSION', }; - resolverConfig.project = await askConflictResolutionStrategy('Select the default resolution strategy'); + if (conflictResolutionStrategy === 'LAMBDA') { + const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); + syncConfig.LambdaConflictHandler = { + name: lambdaFunctionName, + new: newFunction, + }; + } - // Ask for per-model resolver override setting + 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, - }; + 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]); + const { selectedModelTypes } = await inquirer.prompt([modelTypeQuestion]); - if (selectedModelTypes.length > 0) { - resolverConfig.models = {}; - for (let i = 0; i < selectedModelTypes.length; i += 1) { - resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( - `Select the resolution strategy for ${selectedModelTypes[i]} model`, - ); - } + if (selectedModelTypes.length > 0) { + resolverConfig.models = {}; + for (let i = 0; i < selectedModelTypes.length; i += 1) { + resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( + `Select the resolution strategy for ${selectedModelTypes[i]} model`, + ); } } } @@ -492,7 +666,7 @@ async function askDefaultAuthQuestion(context) { const { defaultAuthType } = await inquirer.prompt([defaultAuthTypeQuestion]); // Get default auth configured - const defaultAuth = await askAuthQuestions(defaultAuthType, context); + const defaultAuth = await askAuthQuestions(defaultAuthType, context, false, currentAuthConfig?.defaultAuthentication); return { authConfig: { @@ -508,9 +682,11 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut 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 currentAdditionalAuth = ( + (currentAuthConfig && currentAuthConfig.additionalAuthenticationProviders + ? currentAuthConfig.additionalAuthenticationProviders + : []) as any[] + ).map(authProvider => authProvider.authenticationType); const additionalProvidersQuestion: CheckboxQuestion = { type: 'checkbox', @@ -525,7 +701,12 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { const authProvider = additionalProvidersAnswer.authType[i]; - const config = await askAuthQuestions(authProvider, context, true); + const config = await askAuthQuestions( + authProvider, + context, + true, + currentAuthConfig?.additionalAuthenticationProviders?.find(authSetting => authSetting.authenticationType == authProvider), + ); authConfig.additionalAuthenticationProviders.push(config); } @@ -537,7 +718,7 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut return authConfig; } -async function askAuthQuestions(authType, context, printLeadText = false) { +export async function askAuthQuestions(authType, context, printLeadText = false, authSettings) { if (authType === 'AMAZON_COGNITO_USER_POOLS') { if (printLeadText) { context.print.info('Cognito UserPool configuration'); @@ -553,7 +734,7 @@ async function askAuthQuestions(authType, context, printLeadText = false) { context.print.info('API key configuration'); } - const apiKeyConfig = await askApiKeyQuestions(); + const apiKeyConfig = await askApiKeyQuestions(authSettings); return apiKeyConfig; } @@ -569,7 +750,7 @@ async function askAuthQuestions(authType, context, printLeadText = false) { context.print.info('OpenID Connect configuration'); } - const openIDConnectConfig = await askOpenIDConnectQuestions(); + const openIDConnectConfig = await askOpenIDConnectQuestions(authSettings); return openIDConnectConfig; } @@ -582,9 +763,8 @@ async function askAuthQuestions(authType, context, printLeadText = false) { async function askUserPoolQuestions(context) { let authResourceName = checkIfAuthExists(context); - if (!authResourceName) { - authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context]); + authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context, true]); } else { context.print.info('Use a Cognito user pool configured as a part of this project.'); } @@ -600,18 +780,25 @@ async function askUserPoolQuestions(context) { }; } -async function askApiKeyQuestions() { +export async function askApiKeyQuestions(authSettings = undefined) { + let defaultValues = { + apiKeyExpirationDays: 7, + description: undefined, + }; + 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: 7, + default: defaultValues.apiKeyExpirationDays, validate: validateDays, // adding filter to ensure parsing input as int -> https://github.com/SBoudrias/Inquirer.js/issues/866 filter: value => (isNaN(parseInt(value, 10)) ? value : parseInt(value, 10)), @@ -619,6 +806,8 @@ async function askApiKeyQuestions() { ]; const apiKeyConfig = await inquirer.prompt(apiKeyQuestions); + const apiKeyExpirationDaysNum = Number(apiKeyConfig.apiKeyExpirationDays); + apiKeyConfig.apiKeyExpirationDate = Expiration.after(Duration.days(apiKeyExpirationDaysNum)).date; return { authenticationType: 'API_KEY', @@ -626,35 +815,49 @@ async function askApiKeyQuestions() { }; } -async function askOpenIDConnectQuestions() { +async function askOpenIDConnectQuestions(authSettings) { + 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, }, ]; @@ -677,9 +880,10 @@ function validateDays(input) { } function validateIssuerUrl(input) { - const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( - input, - ); + 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.'; @@ -779,8 +983,8 @@ const buildPolicyResource = (resourceName: string, path: string | null) => { { Ref: `${category}${resourceName}GraphQLAPIIdOutput`, }, - ...(path ? [path] : []) - ] + ...(path ? [path] : []), + ], ], }; }; @@ -788,7 +992,8 @@ const buildPolicyResource = (resourceName: string, path: string | null) => { const templateSchemaFilter = authConfig => { const authIncludesCognito = getAuthTypes(authConfig).includes('AMAZON_COGNITO_USER_POOLS'); return (templateOption: ListChoiceOptions): boolean => - authIncludesCognito || templateOption.value !== 'single-object-auth-schema.graphql'; + authIncludesCognito || + templateOption.name !== 'Objects with fine-grained access control (e.g., a project management app with owner-based authorization)'; }; const getAuthTypes = authConfig => { 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 index d52094eae5..c1a8dde916 100644 --- 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 @@ -30,6 +30,7 @@ const authConfigToAppSyncAuthTypeMap: Record AppSyn API_KEY: authConfig => ({ mode: 'API_KEY', expirationTime: authConfig.apiKeyConfig.apiKeyExpirationDays, + apiKeyExpirationDate: authConfig.apiKeyConfig?.apiKeyExpirationDate, keyDescription: authConfig.apiKeyConfig.description, }), AWS_IAM: () => ({ @@ -54,6 +55,7 @@ const appSyncAuthTypeToAuthConfigMap: Record { type: 'confirm', name: 'editNow', message: 'Do you want to edit the schema now?', - default: false, + default: true, }; if (!(await inquirer.prompt(prompt)).editNow) return; 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 new file mode 100644 index 0000000000..27fc26f1f3 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/global-sandbox-mode.ts @@ -0,0 +1,10 @@ +import { $TSContext } from 'amplify-cli-core'; + +export function defineGlobalSandboxMode(context: $TSContext): string { + const envName = context.amplify.getEnvInfo().envName; + + return `# This allows public create, read, update, and delete access for a limited time to all models via API Key. +# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth +type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n +`; +} diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index 9bf9cbba01..d5fe5482aa 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -52,6 +52,10 @@ export const supportedServices = { 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, }, From b804c8497bc754ddb20a79227639c7ba73ea3fd5 Mon Sep 17 00:00:00 2001 From: Pavel Lazar <85319655+lazpavel@users.noreply.github.com> Date: Thu, 14 Oct 2021 16:37:21 -0400 Subject: [PATCH 469/587] fix(graphql-model-transformer): fixed schema template options check for transformer version (#8449) --- .../service-walkthroughs/appSync-walkthrough.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) 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 index c8561d30e0..379a66a4ee 100644 --- 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 @@ -384,7 +384,8 @@ const updateApiInputWalkthrough = async (context, project, resolverConfig, model export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); - const useExperimentalPipelineTransformer = FeatureFlags.getBoolean('graphQLTransformer.useExperimentalPipelinedTransformer'); + const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); + const transformerVersion = providerPlugin.getTransformerVersion(context); if (resourceName) { const errMessage = @@ -402,7 +403,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen let askToEdit = true; // Schema template selection - const schemaTemplateOptions = useExperimentalPipelineTransformer ? schemaTemplatesV2 : schemaTemplatesV1; + const schemaTemplateOptions = transformerVersion === 2 ? schemaTemplatesV2 : schemaTemplatesV1; const templateSelectionQuestion = { type: inputs[4].type, name: inputs[4].key, @@ -413,7 +414,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent += useExperimentalPipelineTransformer ? defineGlobalSandboxMode(context) : ''; + schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode(context) : ''; schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); return { From 6aa7b9f947d2495efcf431cc6a74d24181e170d2 Mon Sep 17 00:00:00 2001 From: John Corser Date: Mon, 18 Oct 2021 19:55:52 -0400 Subject: [PATCH 470/587] test: fix some Windows e2e tests (#8372) * fix: use proper singleselect for windows e2e tests * ci: prevent jest from hanging aftetr completion * ci: do not use node for pkg binary * ci: try running all windows to see which pass * ci: use multi-account retries on windows * ci: use correct env var * ci: pare down list of failing windows tests * chore: skip additional tests * chore: skip necessary windows tests * chore: fix test lint --- .../single-object-auth-schema-v2.graphql | 7 +++++-- .../appSync-walkthrough.test.ts | 13 ++++++------- packages/amplify-category-api/src/index.ts | 2 +- 3 files changed, 12 insertions(+), 10 deletions(-) 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 index 0faf0997d4..d1706a3bab 100644 --- 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 @@ -1,8 +1,11 @@ type Task @model - @auth(rules: [ + @auth( + rules: [ { allow: groups, groups: ["Managers"], operations: [create, update, read, delete] } - { allow: groups, groups: ["Employees"], operations: [read] } ]) { + { allow: groups, groups: ["Employees"], operations: [read] } + ] + ) { id: ID! title: String! description: String 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 index 1d7ed55cdf..6e6a75c8d8 100644 --- 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 @@ -25,16 +25,15 @@ const context_stub = (prompt: jest.Mock) => ({ }); type IAMArtifact = { - attributes: string[], - policy: any, + attributes: string[]; + policy: any; }; - describe('get IAM policies', () => { beforeEach(() => { jest.resetModules(); }); -it('does not include API key if none exists', async () => { + it('does not include API key if none exists', async () => { mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => false); const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); @@ -47,7 +46,7 @@ it('does not include API key if none exists', async () => { expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/types/Query/*'); }); -it('includes API key if it exists', async () => { + it('includes API key if it exists', async () => { mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => true); const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); @@ -61,7 +60,7 @@ it('includes API key if it exists', async () => { expect(iamArtifact.policy.Resource[0]['Fn::Join'][1][6]).toMatch('/types/Query/*'); }); -it('policy path includes the new format for graphql operations', async () => { + 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'], context_stub(confirmPromptFalse_mock)); @@ -85,7 +84,7 @@ it('policy path includes the new format for graphql operations', async () => { ] `); expect(iamArtifact.policy.Action).toHaveLength(4); - expect(iamArtifact.policy.Action).toEqual(["appsync:Create*", "appsync:StartSchemaCreation", "appsync:GraphQL", "appsync:Update*"]); + 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('/*'); }); diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 3593ba6b97..4ada1ab74d 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -249,4 +249,4 @@ export async function addGraphQLAuthorizationMode(context, args) { ); return addAuthConfig; -} \ No newline at end of file +} From d76c9cb9da5b1f200bce9751b4359d5451e3641c Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Thu, 21 Oct 2021 11:37:02 -0700 Subject: [PATCH 471/587] feat: flag to allow destructive schema changes (#8273) * chore: dumping table changes * chore: drop table POC * feat: plumb destructive-updates flag * feat: plumb rebuild * chore: fix rebuild prompts * test: adding unit and e2e tests * feat: sweet jesus it works * fix: iterative push lambda with updates * chore: organize code better * test: add unit and e2e tests * chore: fit and finish * chore: didn't save all the files * test: fix some tests and add a couple more * chore: address PR comments * test: fix e2e failures * chore: fix prompts dep version * test: exclude new api tests from windows * test: update test schema * chore: address PR comments * fix: messed up merge * test: fix e2e failures --- .../amplify-category-api/amplify-plugin.json | 25 +++----- .../__tests__/commands/api/rebuild.test.ts | 64 +++++++++++++++++++ .../amplify-category-api/src/commands/api.js | 5 ++ .../src/commands/api/rebuild.ts | 40 ++++++++++++ packages/amplify-category-api/tsconfig.json | 2 + 5 files changed, 119 insertions(+), 17 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts create mode 100644 packages/amplify-category-api/src/commands/api/rebuild.ts diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 8cf4ad9d46..8bd97a6a3c 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -1,18 +1,9 @@ { - "name": "api", - "type": "category", - "commands": [ - "add-graphql-datasource", - "add", - "console", - "gql-compile", - "push", - "remove", - "update", - "help" - ], - "commandAliases":{ - "configure": "update" - }, - "eventHandlers": [] -} \ No newline at end of file + "name": "api", + "type": "category", + "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "push", "rebuild", "remove", "update", "help"], + "commandAliases": { + "configure": "update" + }, + "eventHandlers": [] +} 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 new file mode 100644 index 0000000000..ce28470ecd --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/commands/api/rebuild.test.ts @@ -0,0 +1,64 @@ +import { $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import { mocked } from 'ts-jest/utils'; +import { run } from '../../../commands/api/rebuild'; + +jest.mock('amplify-cli-core'); +jest.mock('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/commands/api.js b/packages/amplify-category-api/src/commands/api.js index 948dc4ae4a..e8c261e00d 100644 --- a/packages/amplify-category-api/src/commands/api.js +++ b/packages/amplify-category-api/src/commands/api.js @@ -41,6 +41,11 @@ module.exports = { name: 'console', description: 'Opens the web console for the selected api service', }, + { + 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', + }, ]; context.amplify.showHelp(header, commands); diff --git a/packages/amplify-category-api/src/commands/api/rebuild.ts b/packages/amplify-category-api/src/commands/api/rebuild.ts new file mode 100644 index 0000000000..26b8ead364 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/rebuild.ts @@ -0,0 +1,40 @@ +import { $TSAny, $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { printer, prompter, exact } from 'amplify-prompts'; + +const subcommand = 'rebuild'; +const category = 'api'; + +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 $TSAny).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, category, resourceName, undefined, rebuild); +}; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index dd332b004a..31c85559bb 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -14,7 +14,9 @@ "src/__tests__" ], "references": [ + {"path": "../amplify-cli-core"}, {"path": "../amplify-headless-interface"}, + {"path": "../amplify-prompts"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, ] From 430e10c729c0e8fc00f22df66f3df98fdc4eefb6 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Wed, 27 Oct 2021 16:02:51 -0400 Subject: [PATCH 472/587] fix: expand region support for aurora serverless (#8577) This commit updates the list of regions where Aurora is supported to reflect the CLI's recent region expansion. Co-authored-by: Ihrig --- .../src/provider-utils/supported-datasources.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index f9eb118a09..65b5b01910 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -40,10 +40,15 @@ export const supportedDatasources = { 'ap-southeast-1', 'ap-southeast-2', 'ap-northeast-1', + 'ap-northeast-2', + 'ca-central-1', 'eu-central-1', + 'eu-north-1', 'eu-west-1', 'eu-west-2', 'eu-west-3', + 'me-south-1', + 'sa-east-1', ], }, }; From 382b027e38209b317c8aa83179a963ac7aa440aa Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Wed, 27 Oct 2021 14:38:21 -0700 Subject: [PATCH 473/587] lambda authorizer cli and transformer change (#8527) Add Lambda authorizer support for GraphQL Api --- .../graphql-lambda-authorizer-index.js | 25 +++ ...graphql-lambda-authorizer-package.json.ejs | 6 + ...raphql-lambda-authorizer-template.json.ejs | 208 ++++++++++++++++++ .../appSync-walkthrough.ts | 189 +++++++++++++++- ...nfig-to-app-sync-auth-type-bi-di-mapper.ts | 13 ++ packages/amplify-category-api/tsconfig.json | 1 + 6 files changed, 435 insertions(+), 7 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js new file mode 100644 index 0000000000..20f0971452 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js @@ -0,0 +1,25 @@ +// This is sample code. Please update this to suite your schema + +exports.handler = async (event) => { + console.log(`event >`, JSON.stringify(event, null, 2)); + const { + authorizationToken, + requestContext: { apiId, accountId }, + } = event; + const response = { + isAuthorized: authorizationToken === 'custom-authorized', + resolverContext: { + userid: 'user-id', + info: 'contextual information A', + more_info: 'contextual information B', + }, + deniedFields: [ + `arn:aws:appsync:${process.env.AWS_REGION}:${accountId}:apis/${apiId}/types/Event/fields/comments`, + `Mutation.createEvent`, + ], + ttlOverride: 300, + }; + console.log(`response >`, JSON.stringify(response, null, 2)); + return response; +}; + diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs new file mode 100644 index 0000000000..e2f9e8b41d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs @@ -0,0 +1,6 @@ +{ + "name": "<%= props.functionName %>", + "version": "1.0.0", + "description": "Lambda function generated by Amplify for AppSync Lambda authorizer", + "main": "index.js" +} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs new file mode 100644 index 0000000000..acd908246d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs @@ -0,0 +1,208 @@ +{ + "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": "nodejs14.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/*" + ] + ] + } + <% } %> + ] + } + <% } %> + ] + } + } + } + ,"PermissionForAppSyncToInvokeLambda": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "LambdaFunction" + }, + "Action": "lambda:InvokeFunction", + "Principal": "appsync.amazonaws.com" + } + } + <% 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/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 379a66a4ee..2178083776 100644 --- 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 @@ -3,7 +3,7 @@ import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; import inquirer from 'inquirer'; import fs from 'fs-extra'; import path from 'path'; -import { rootAssetDir } from '../aws-constants'; +import { rootAssetDir, provider } from '../aws-constants'; import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; import { category } from '../../../category-constants'; import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; @@ -11,6 +11,7 @@ import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-au import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; import _ from 'lodash'; import chalk from 'chalk'; +import uuid from 'uuid'; import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; import { ResourceAlreadyExistsError, @@ -30,6 +31,9 @@ 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', @@ -68,6 +72,7 @@ const conflictResolutionHanlderChoices = [ }, ]; +const blankSchemaFile = 'blank-schema.graphql'; const schemaTemplatesV1 = [ { name: 'Single object with fields (e.g., “Todo” with ID, name, description)', @@ -83,7 +88,7 @@ const schemaTemplatesV1 = [ }, { name: 'Blank Schema', - value: 'blank-schema.graphql', + value: blankSchemaFile, }, ]; @@ -102,7 +107,7 @@ const schemaTemplatesV2 = [ }, { name: 'Blank Schema', - value: 'blank-schema.graphql', + value: blankSchemaFile, }, ]; @@ -146,7 +151,7 @@ export const openConsole = async (context: $TSContext) => { url = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); if (isAdminApp) { if (region !== Region) { @@ -384,9 +389,9 @@ const updateApiInputWalkthrough = async (context, project, resolverConfig, model export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { const resourceName = resourceAlreadyExists(context); - const providerPlugin = await import(context.amplify.getProviderPlugins(context).awscloudformation); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); const transformerVersion = providerPlugin.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.'; @@ -414,7 +419,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode(context) : ''; + schemaContent += transformerVersion === 2 && templateSelection !== blankSchemaFile ? defineGlobalSandboxMode(context) : ''; schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); return { @@ -432,6 +437,7 @@ export const updateWalkthrough = async (context): Promise => { 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) { @@ -652,10 +658,24 @@ async function askSyncFunctionQuestion(context) { return { newFunction, lambdaFunctionName }; } + +async function addLambdaAuthorizerChoice(context) { + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); + const transformerVersion = providerPlugin.getTransformerVersion(context); + if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { + authProviderChoices.push({ + name: 'Lambda', + value: 'AWS_LAMBDA', + }); + } +} + async function askDefaultAuthQuestion(context) { + await addLambdaAuthorizerChoice(context); const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); const currentDefaultAuth = currentAuthConfig && currentAuthConfig.defaultAuthentication ? currentAuthConfig.defaultAuthentication.authenticationType : undefined; + const defaultAuthTypeQuestion = { type: 'list', name: 'defaultAuthType', @@ -756,6 +776,16 @@ export async function askAuthQuestions(authType, context, printLeadText = false, 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}`; context.print.error(errMessage); await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); @@ -1006,3 +1036,148 @@ const getAuthTypes = authConfig => { 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 source', + 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 targetDir = context.amplify.pathManager.getBackendDirPath(); + const assetDir = path.normalize(path.join(rootAssetDir, 'graphql-lambda-authorizer')); + const [shortId] = uuid().split('-'); + + const functionName = `graphQlLambdaAuthorizer${shortId}`; + + const functionProps = { + functionName: `${functionName}`, + roleName: `${functionName}LambdaRole`, + }; + + const copyJobs = [ + { + dir: assetDir, + template: 'graphql-lambda-authorizer-index.js', + target: `${targetDir}/function/${functionName}/src/index.js`, + }, + { + dir: assetDir, + template: 'graphql-lambda-authorizer-package.json.ejs', + target: `${targetDir}/function/${functionName}/src/package.json`, + }, + { + dir: assetDir, + template: 'graphql-lambda-authorizer-template.json.ejs', + target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + await context.amplify.copyBatch(context, copyJobs, functionProps, true); + + const backendConfigs = { + service: FunctionServiceNameLambdaFunction, + providerPlugin: provider, + build: true, + }; + + await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); + context.print.success(`Successfully added ${functionName} function locally`); + + return functionName; +}; \ No newline at end of file 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 index c1a8dde916..948b72a495 100644 --- 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 @@ -3,6 +3,7 @@ import { AppSyncAPIKeyAuthType, AppSyncCognitoUserPoolsAuthType, AppSyncOpenIDConnectAuthType, + AppSyncLambdaAuthType, } from 'amplify-headless-interface'; import _ from 'lodash'; @@ -48,6 +49,11 @@ const authConfigToAppSyncAuthTypeMap: Record AppSyn 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> = { @@ -78,4 +84,11 @@ const appSyncAuthTypeToAuthConfigMap: Record ({ + authenticationType: 'AWS_LAMBDA', + lambdaAuthorizerConfig: { + lambdaFunction: authType.lambdaFunction, + ttlSeconds: authType.ttlSeconds, + }, + }), }; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 31c85559bb..0fc8b8735c 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -11,6 +11,7 @@ "lib", "resources/awscloudformation/lambdas", "resources/awscloudformation/container-templates", + "resources/awscloudformation/graphql-lambda-authorizer", "src/__tests__" ], "references": [ From fe5cd3a08f277853d6efb4da1f1ae7e92b417739 Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Sun, 31 Oct 2021 13:10:43 -0400 Subject: [PATCH 474/587] feat(amplify-provider-awscloudformation): change sandbox mode syntax in schema (#8592) --- .../utils/global-sandbox-mode.test.ts | 19 ++++--------------- .../appSync-walkthrough.ts | 14 ++++++-------- .../utils/global-sandbox-mode.ts | 12 ++++-------- 3 files changed, 14 insertions(+), 31 deletions(-) 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 index a895da7f66..315084e96b 100644 --- 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 @@ -1,21 +1,10 @@ import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudformation/utils/global-sandbox-mode'; -import { $TSContext } from 'amplify-cli-core'; describe('global sandbox mode GraphQL directive', () => { - it('returns AMPLIFY_DIRECTIVE type with code comment, directive, and env name', () => { - const envName = 'envone'; - const ctx = <$TSContext>{ - amplify: { - getEnvInfo() { - return { envName }; - }, - }, - }; - - expect(defineGlobalSandboxMode(ctx)) - .toBe(`# This allows public create, read, update, and delete access for a limited time to all models via API Key. -# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth -type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n + it('returns input AMPLIFY with code comment', () => { + expect(defineGlobalSandboxMode()).toEqual(`# 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-transformer/auth +input AMPLIFY { global_auth_rule: AuthorizationRule = { allow: public } } # FOR TESTING ONLY!\n `); }); }); 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 index 2178083776..204aaba2c6 100644 --- 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 @@ -419,7 +419,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent += transformerVersion === 2 && templateSelection !== blankSchemaFile ? defineGlobalSandboxMode(context) : ''; + schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode() : ''; schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); return { @@ -664,8 +664,8 @@ async function addLambdaAuthorizerChoice(context) { const transformerVersion = providerPlugin.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ - name: 'Lambda', - value: 'AWS_LAMBDA', + name: 'Lambda', + value: 'AWS_LAMBDA', }); } } @@ -1073,7 +1073,7 @@ async function askLambdaQuestion(context) { const lambdaAuthorizerConfig = { lambdaFunction, ttlSeconds, - } + }; return { authenticationType: 'AWS_LAMBDA', @@ -1130,9 +1130,7 @@ async function askLambdaFromProject(context: $TSContext) { default: lambdaFunctions[0], }); - await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [ - answer.lambdaFunction, - ]); + await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [answer.lambdaFunction]); return { lambdaFunction: answer.lambdaFunction }; } @@ -1180,4 +1178,4 @@ async function createLambdaAuthorizerFunction(context: $TSContext) { context.print.success(`Successfully added ${functionName} function locally`); return functionName; -}; \ No newline at end of file +} 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 index 27fc26f1f3..e0a703267c 100644 --- 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 @@ -1,10 +1,6 @@ -import { $TSContext } from 'amplify-cli-core'; - -export function defineGlobalSandboxMode(context: $TSContext): string { - const envName = context.amplify.getEnvInfo().envName; - - return `# This allows public create, read, update, and delete access for a limited time to all models via API Key. -# To configure PRODUCTION-READY authorization rules, review: https://docs.amplify.aws/cli/graphql-transformer/auth -type AMPLIFY_GLOBAL @allow_public_data_access_with_api_key(in: \"${envName}\") # FOR TESTING ONLY!\n +export function defineGlobalSandboxMode(): 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: https://docs.amplify.aws/cli/graphql-transformer/auth +input AMPLIFY { global_auth_rule: AuthorizationRule = { allow: public } } # FOR TESTING ONLY!\n `; } From 21d2078fbbe1b017a7b7fba57b942570f9302363 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Sun, 31 Oct 2021 10:13:12 -0700 Subject: [PATCH 475/587] fix(graphql): minor api prompt fixes (#8603) minor api prompt fixes --- .../service-walkthroughs/appSync-walkthrough.ts | 13 ++++++++++--- .../src/provider-utils/supported-services.ts | 4 ++-- 2 files changed, 12 insertions(+), 5 deletions(-) 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 index 204aaba2c6..fd4a0033cc 100644 --- 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 @@ -308,6 +308,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile // 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 @@ -832,7 +833,13 @@ export async function askApiKeyQuestions(authSettings = undefined) { default: defaultValues.apiKeyExpirationDays, validate: validateDays, // adding filter to ensure parsing input as int -> https://github.com/SBoudrias/Inquirer.js/issues/866 - filter: value => (isNaN(parseInt(value, 10)) ? value : parseInt(value, 10)), + filter: value => { + const val = parseInt(value, 10); + if (isNaN(val) || val <= 0 || val > 365) { + return value; + } + return val; + }, }, ]; @@ -900,8 +907,8 @@ async function askOpenIDConnectQuestions(authSettings) { }; } -function validateDays(input) { - const isValid = /^\d+$/.test(input); +async function validateDays(input) { + 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.'; diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index d5fe5482aa..99cc2e128b 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -18,8 +18,8 @@ export const supportedServices = { question: 'Provide API name:', validation: { operator: 'regex', - value: '^[a-zA-Z0-9]+$', - onErrorMsg: 'You can use the following characters: a-z A-Z 0-9', + 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, }, From 70891148dcc3952257549254301ac66443c2ed06 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Tue, 2 Nov 2021 16:02:39 -0700 Subject: [PATCH 476/587] fix(graphql): lambda auth label fix (#8623) --- .../service-walkthroughs/appSync-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index fd4a0033cc..933134e813 100644 --- 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 @@ -1063,7 +1063,7 @@ async function askLambdaQuestion(context) { const lambdaAnswer = await inquirer.prompt({ name: 'functionType', type: 'list', - message: 'Choose a Lambda source', + message: 'Choose a Lambda authorization function', choices, default: defaultFunctionType, }); From e1fc46a250c8d54c59f2beb42d188bc60b3e0dae Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Wed, 3 Nov 2021 13:42:53 -0400 Subject: [PATCH 477/587] fix(amplify-category-api): change auth directive type and fix codegen bug (#8639) --- .../awscloudformation/utils/global-sandbox-mode.test.ts | 2 +- .../awscloudformation/utils/global-sandbox-mode.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 index 315084e96b..fb6175701d 100644 --- 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 @@ -4,7 +4,7 @@ describe('global sandbox mode GraphQL directive', () => { it('returns input AMPLIFY with code comment', () => { expect(defineGlobalSandboxMode()).toEqual(`# 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-transformer/auth -input AMPLIFY { global_auth_rule: AuthorizationRule = { allow: public } } # FOR TESTING ONLY!\n +input AMPLIFY { global_auth_rule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n `); }); }); 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 index e0a703267c..7c7da39818 100644 --- 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 @@ -1,6 +1,6 @@ export function defineGlobalSandboxMode(): 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: https://docs.amplify.aws/cli/graphql-transformer/auth -input AMPLIFY { global_auth_rule: AuthorizationRule = { allow: public } } # FOR TESTING ONLY!\n +input AMPLIFY { global_auth_rule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n `; } From 772ae5a8fc8bfc063c347ac9e07233570b3a8630 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Thu, 4 Nov 2021 12:16:32 -0700 Subject: [PATCH 478/587] fix: remove duplicate error messages (#8651) --- packages/amplify-category-api/src/commands/api/update.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/update.js b/packages/amplify-category-api/src/commands/api/update.js index 03dbb328f1..f55ec76e9f 100644 --- a/packages/amplify-category-api/src/commands/api/update.js +++ b/packages/amplify-category-api/src/commands/api/update.js @@ -1,3 +1,5 @@ +const { printer } = require('amplify-prompts'); + const subcommand = 'update'; const category = 'api'; @@ -13,15 +15,14 @@ module.exports = { .then(result => { const providerController = require(`../../provider-utils/${result.providerName}/index`); if (!providerController) { - context.print.error('Provider not configured for this category'); + printer.error('Provider not configured for this category'); return; } return providerController.updateResource(context, category, result.service); }) - .then(() => context.print.success('Successfully updated resource')) + .then(() => printer.success('Successfully updated resource')) .catch(err => { - context.print.error(err.message); - console.log(err.stack); + printer.error(err.message || err); context.usageData.emitError(err); process.exitCode = 1; }); From 1f5d061c6db581236ef9ff977561883fb257e7b8 Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Fri, 5 Nov 2021 14:45:09 -0400 Subject: [PATCH 479/587] feat(amplify-provider-awscloudformation): change global_auth_rule to globalAuthRule for global auth (#8674) --- .../awscloudformation/utils/global-sandbox-mode.test.ts | 2 +- .../awscloudformation/utils/global-sandbox-mode.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 index fb6175701d..5603957515 100644 --- 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 @@ -4,7 +4,7 @@ describe('global sandbox mode GraphQL directive', () => { it('returns input AMPLIFY with code comment', () => { expect(defineGlobalSandboxMode()).toEqual(`# 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-transformer/auth -input AMPLIFY { global_auth_rule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n +input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n `); }); }); 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 index 7c7da39818..6c3d8db0cc 100644 --- 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 @@ -1,6 +1,6 @@ export function defineGlobalSandboxMode(): 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: https://docs.amplify.aws/cli/graphql-transformer/auth -input AMPLIFY { global_auth_rule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n +input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n `; } From 60bf68c1031875ee96dac17b59222a83ac951c39 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Mon, 8 Nov 2021 14:37:09 -0800 Subject: [PATCH 480/587] fix: schema migrator utility as separate command (#8720) --- .../amplify-category-api/amplify-plugin.json | 2 +- packages/amplify-category-api/package.json | 1 + .../amplify-category-api/src/commands/api.js | 4 +++ .../src/commands/api/migrate.ts | 36 +++++++++++++++++++ packages/amplify-category-api/tsconfig.json | 1 + 5 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 packages/amplify-category-api/src/commands/api/migrate.ts diff --git a/packages/amplify-category-api/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 8bd97a6a3c..21548e0f39 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -1,7 +1,7 @@ { "name": "api", "type": "category", - "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "push", "rebuild", "remove", "update", "help"], + "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "migrate", "push", "rebuild", "remove", "update", "help"], "commandAliases": { "configure": "update" }, diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index fa76cb5945..a9f73c754e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -17,6 +17,7 @@ "test": "jest" }, "dependencies": { + "@aws-amplify/graphql-transformer-migrator": "0.1.0", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", diff --git a/packages/amplify-category-api/src/commands/api.js b/packages/amplify-category-api/src/commands/api.js index e8c261e00d..2ea6c65e5a 100644 --- a/packages/amplify-category-api/src/commands/api.js +++ b/packages/amplify-category-api/src/commands/api.js @@ -41,6 +41,10 @@ module.exports = { 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: diff --git a/packages/amplify-category-api/src/commands/api/migrate.ts b/packages/amplify-category-api/src/commands/api/migrate.ts new file mode 100644 index 0000000000..f5ea2857a1 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/migrate.ts @@ -0,0 +1,36 @@ +import { $TSAny, $TSContext, pathManager, stateManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import { attemptV2TransformerMigration, revertV2Migration } from '@aws-amplify/graphql-transformer-migrator'; +import * as path from 'path'; +import { category } from '../../category-constants'; + +const subcommand = 'migrate'; + +export const name = subcommand; + +export const run = async (context: $TSContext) => { + const apiNames = Object.entries(stateManager.getMeta()?.api || {}) + .filter(([_, apiResource]) => (apiResource as $TSAny).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(), category, apiName); + + if (context.parameters?.options?.revert) { + await revertV2Migration(apiResourceDir, stateManager.getCurrentEnvName()); + return; + } + await attemptV2TransformerMigration(apiResourceDir, apiName, stateManager.getCurrentEnvName()); +}; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 0fc8b8735c..5a69dbb23d 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -20,5 +20,6 @@ {"path": "../amplify-prompts"}, {"path": "../graphql-transformer-core"}, {"path": "../amplify-util-headless-input"}, + {"path": "../amplify-graphql-transformer-migrator"}, ] } From c2d1177575de360983ec12bb430f06c9d8381af9 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Mon, 8 Nov 2021 17:07:42 -0800 Subject: [PATCH 481/587] Lambda auth minor fixes (#8741) fix(graphql): lambda auth minor changes --- .../graphql-lambda-authorizer-index.js | 25 --- ...graphql-lambda-authorizer-package.json.ejs | 6 - ...raphql-lambda-authorizer-template.json.ejs | 208 ------------------ .../appSync-walkthrough.ts | 53 ++--- 4 files changed, 16 insertions(+), 276 deletions(-) delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js deleted file mode 100644 index 20f0971452..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js +++ /dev/null @@ -1,25 +0,0 @@ -// This is sample code. Please update this to suite your schema - -exports.handler = async (event) => { - console.log(`event >`, JSON.stringify(event, null, 2)); - const { - authorizationToken, - requestContext: { apiId, accountId }, - } = event; - const response = { - isAuthorized: authorizationToken === 'custom-authorized', - resolverContext: { - userid: 'user-id', - info: 'contextual information A', - more_info: 'contextual information B', - }, - deniedFields: [ - `arn:aws:appsync:${process.env.AWS_REGION}:${accountId}:apis/${apiId}/types/Event/fields/comments`, - `Mutation.createEvent`, - ], - ttlOverride: 300, - }; - console.log(`response >`, JSON.stringify(response, null, 2)); - return response; -}; - diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs deleted file mode 100644 index e2f9e8b41d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "<%= props.functionName %>", - "version": "1.0.0", - "description": "Lambda function generated by Amplify for AppSync Lambda authorizer", - "main": "index.js" -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs deleted file mode 100644 index acd908246d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs +++ /dev/null @@ -1,208 +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": "nodejs14.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/*" - ] - ] - } - <% } %> - ] - } - <% } %> - ] - } - } - } - ,"PermissionForAppSyncToInvokeLambda": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "FunctionName": { - "Ref": "LambdaFunction" - }, - "Action": "lambda:InvokeFunction", - "Principal": "appsync.amazonaws.com" - } - } - <% 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/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 933134e813..52de5b0701 100644 --- 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 @@ -1143,46 +1143,25 @@ async function askLambdaFromProject(context: $TSContext) { } async function createLambdaAuthorizerFunction(context: $TSContext) { - const targetDir = context.amplify.pathManager.getBackendDirPath(); - const assetDir = path.normalize(path.join(rootAssetDir, 'graphql-lambda-authorizer')); const [shortId] = uuid().split('-'); - const functionName = `graphQlLambdaAuthorizer${shortId}`; - - const functionProps = { - functionName: `${functionName}`, - roleName: `${functionName}LambdaRole`, - }; - - const copyJobs = [ - { - dir: assetDir, - template: 'graphql-lambda-authorizer-index.js', - target: `${targetDir}/function/${functionName}/src/index.js`, - }, - { - dir: assetDir, - template: 'graphql-lambda-authorizer-package.json.ejs', - target: `${targetDir}/function/${functionName}/src/package.json`, - }, + const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ + context, + 'awscloudformation', + FunctionServiceNameLambdaFunction, { - dir: assetDir, - template: 'graphql-lambda-authorizer-template.json.ejs', - target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + functionName, + defaultRuntime: 'nodejs', + providerContext: { + provider: 'awscloudformation', + }, + template: 'lambda-auth', + skipAdvancedSection: true, + skipNextSteps: true, }, - ]; + ]); - // copy over the files - await context.amplify.copyBatch(context, copyJobs, functionProps, true); - - const backendConfigs = { - service: FunctionServiceNameLambdaFunction, - providerPlugin: provider, - build: true, - }; - - await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - context.print.success(`Successfully added ${functionName} function locally`); - - return functionName; + context.print.success(`Successfully added ${resourceName} function locally`); + await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [resourceName]); + return resourceName; } From 6af4b5e60c0848d8a0a71f90c5c29b0115a3b0e3 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 8 Nov 2021 18:59:47 -0800 Subject: [PATCH 482/587] chore: update aws-sdk, cdk, typescript dependency, regen yarn.lock (#8739) * chore: update aws-sdk, cdk, typescript dependency, regen yarn.lock * chore: address feedback, newer packages * test: fix failing tests --- packages/amplify-category-api/package.json | 88 +++++++++---------- .../express/package.json | 2 +- .../dockerfile-rest-express/package.json | 4 +- .../graphql-express/package.json | 2 +- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a9f73c754e..2978603dee 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -18,50 +18,50 @@ }, "dependencies": { "@aws-amplify/graphql-transformer-migrator": "0.1.0", - "@aws-cdk/assets": "~1.124.0", - "@aws-cdk/aws-apigateway": "~1.124.0", - "@aws-cdk/aws-apigatewayv2": "~1.124.0", - "@aws-cdk/aws-applicationautoscaling": "~1.124.0", - "@aws-cdk/aws-autoscaling": "~1.124.0", - "@aws-cdk/aws-autoscaling-common": "~1.124.0", - "@aws-cdk/aws-autoscaling-hooktargets": "~1.124.0", - "@aws-cdk/aws-certificatemanager": "~1.124.0", - "@aws-cdk/aws-cloudformation": "~1.124.0", - "@aws-cdk/aws-cloudfront": "~1.124.0", - "@aws-cdk/aws-cloudwatch": "~1.124.0", - "@aws-cdk/aws-codebuild": "~1.124.0", - "@aws-cdk/aws-codeguruprofiler": "~1.124.0", - "@aws-cdk/aws-codepipeline": "~1.124.0", - "@aws-cdk/aws-codepipeline-actions": "~1.124.0", - "@aws-cdk/aws-cognito": "~1.124.0", - "@aws-cdk/aws-ec2": "~1.124.0", - "@aws-cdk/aws-ecr": "~1.124.0", - "@aws-cdk/aws-ecr-assets": "~1.124.0", - "@aws-cdk/aws-ecs": "~1.124.0", - "@aws-cdk/aws-efs": "~1.124.0", - "@aws-cdk/aws-elasticloadbalancing": "~1.124.0", - "@aws-cdk/aws-elasticloadbalancingv2": "~1.124.0", - "@aws-cdk/aws-events": "~1.124.0", - "@aws-cdk/aws-iam": "~1.124.0", - "@aws-cdk/aws-kms": "~1.124.0", - "@aws-cdk/aws-lambda": "~1.124.0", - "@aws-cdk/aws-logs": "~1.124.0", - "@aws-cdk/aws-route53": "~1.124.0", - "@aws-cdk/aws-route53-targets": "~1.124.0", - "@aws-cdk/aws-s3": "~1.124.0", - "@aws-cdk/aws-s3-assets": "~1.124.0", - "@aws-cdk/aws-sam": "~1.124.0", - "@aws-cdk/aws-secretsmanager": "~1.124.0", - "@aws-cdk/aws-servicediscovery": "~1.124.0", - "@aws-cdk/aws-sns": "~1.124.0", - "@aws-cdk/aws-sns-subscriptions": "~1.124.0", - "@aws-cdk/aws-sqs": "~1.124.0", - "@aws-cdk/aws-ssm": "~1.124.0", - "@aws-cdk/cloud-assembly-schema": "~1.124.0", - "@aws-cdk/core": "~1.124.0", - "@aws-cdk/custom-resources": "~1.124.0", - "@aws-cdk/cx-api": "~1.124.0", - "@aws-cdk/region-info": "~1.124.0", + "@aws-cdk/assets": "~1.131.0", + "@aws-cdk/aws-apigateway": "~1.131.0", + "@aws-cdk/aws-apigatewayv2": "~1.131.0", + "@aws-cdk/aws-applicationautoscaling": "~1.131.0", + "@aws-cdk/aws-autoscaling": "~1.131.0", + "@aws-cdk/aws-autoscaling-common": "~1.131.0", + "@aws-cdk/aws-autoscaling-hooktargets": "~1.131.0", + "@aws-cdk/aws-certificatemanager": "~1.131.0", + "@aws-cdk/aws-cloudformation": "~1.131.0", + "@aws-cdk/aws-cloudfront": "~1.131.0", + "@aws-cdk/aws-cloudwatch": "~1.131.0", + "@aws-cdk/aws-codebuild": "~1.131.0", + "@aws-cdk/aws-codeguruprofiler": "~1.131.0", + "@aws-cdk/aws-codepipeline": "~1.131.0", + "@aws-cdk/aws-codepipeline-actions": "~1.131.0", + "@aws-cdk/aws-cognito": "~1.131.0", + "@aws-cdk/aws-ec2": "~1.131.0", + "@aws-cdk/aws-ecr": "~1.131.0", + "@aws-cdk/aws-ecr-assets": "~1.131.0", + "@aws-cdk/aws-ecs": "~1.131.0", + "@aws-cdk/aws-efs": "~1.131.0", + "@aws-cdk/aws-elasticloadbalancing": "~1.131.0", + "@aws-cdk/aws-elasticloadbalancingv2": "~1.131.0", + "@aws-cdk/aws-events": "~1.131.0", + "@aws-cdk/aws-iam": "~1.131.0", + "@aws-cdk/aws-kms": "~1.131.0", + "@aws-cdk/aws-lambda": "~1.131.0", + "@aws-cdk/aws-logs": "~1.131.0", + "@aws-cdk/aws-route53": "~1.131.0", + "@aws-cdk/aws-route53-targets": "~1.131.0", + "@aws-cdk/aws-s3": "~1.131.0", + "@aws-cdk/aws-s3-assets": "~1.131.0", + "@aws-cdk/aws-sam": "~1.131.0", + "@aws-cdk/aws-secretsmanager": "~1.131.0", + "@aws-cdk/aws-servicediscovery": "~1.131.0", + "@aws-cdk/aws-sns": "~1.131.0", + "@aws-cdk/aws-sns-subscriptions": "~1.131.0", + "@aws-cdk/aws-sqs": "~1.131.0", + "@aws-cdk/aws-ssm": "~1.131.0", + "@aws-cdk/cloud-assembly-schema": "~1.131.0", + "@aws-cdk/core": "~1.131.0", + "@aws-cdk/custom-resources": "~1.131.0", + "@aws-cdk/cx-api": "~1.131.0", + "@aws-cdk/region-info": "~1.131.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.31.1", 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 index 98a3659067..c46a6881fb 100644 --- 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 @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1024.0", "axios": "^0.21.4", "body-parser": "^1.19.0", "express": "^4.17.1", 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 index 9c72bb598f..b7e6db8d44 100644 --- 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 @@ -9,8 +9,8 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1024.0", "body-parser": "^1.19.0", "express": "^4.17.1" } - } \ No newline at end of file + } 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 index ee61e94075..fb264e3a23 100644 --- 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 @@ -7,7 +7,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1024.0", "express": "^4.17.1", "express-graphql": "^0.11.0", "graphql": "^15.4.0" From 3d3c05a8b7f4c770ac38d254e8b69e63f863e784 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Tue, 9 Nov 2021 15:51:48 -0800 Subject: [PATCH 483/587] Revert/last green (#8759) * Revert "fix(amplify-category-auth): added username attributes to configure sms (#8624)" This reverts commit adb70b1de1d84faf72e82aaf992813d52b50e3b8. * Revert "Model vnext unit test update (#8749)" This reverts commit 8a308a8b0431172e0df389e8306a32175844b83c. * Revert "Revert "feat: version blocking for CLI (#8737)" (#8747)" This reverts commit 2d5110c22412a56027417bc691030aa1ea18121e. * Revert "chore: update aws-sdk, cdk, typescript dependency, regen yarn.lock (#8739)" This reverts commit 6af4b5e60c0848d8a0a71f90c5c29b0115a3b0e3. * Revert "feat: version blocking for CLI (#8737)" This reverts commit b92cd32afc3afb75b3fd7ddcc93a5d510b4fac2e. * Revert "Remove pipelineFunction references in favor of resolvers (#8729)" This reverts commit a0295aa940dd735b29f54be989f2b11dac47aacc. * Revert "fix: move @model params to root stack and fix ds logical id (#8736)" This reverts commit df4408c4080949ddd638778df9ae20e763dd5824. * Revert "fix(amplify-provider-awscloudformation): use amplify prompts for warnings (#8731)" This reverts commit 98840ec1b61e2e424c9884f055227d11c5463c26. --- packages/amplify-category-api/package.json | 88 +++++++++---------- .../express/package.json | 2 +- .../dockerfile-rest-express/package.json | 4 +- .../graphql-express/package.json | 2 +- 4 files changed, 48 insertions(+), 48 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 2978603dee..a9f73c754e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -18,50 +18,50 @@ }, "dependencies": { "@aws-amplify/graphql-transformer-migrator": "0.1.0", - "@aws-cdk/assets": "~1.131.0", - "@aws-cdk/aws-apigateway": "~1.131.0", - "@aws-cdk/aws-apigatewayv2": "~1.131.0", - "@aws-cdk/aws-applicationautoscaling": "~1.131.0", - "@aws-cdk/aws-autoscaling": "~1.131.0", - "@aws-cdk/aws-autoscaling-common": "~1.131.0", - "@aws-cdk/aws-autoscaling-hooktargets": "~1.131.0", - "@aws-cdk/aws-certificatemanager": "~1.131.0", - "@aws-cdk/aws-cloudformation": "~1.131.0", - "@aws-cdk/aws-cloudfront": "~1.131.0", - "@aws-cdk/aws-cloudwatch": "~1.131.0", - "@aws-cdk/aws-codebuild": "~1.131.0", - "@aws-cdk/aws-codeguruprofiler": "~1.131.0", - "@aws-cdk/aws-codepipeline": "~1.131.0", - "@aws-cdk/aws-codepipeline-actions": "~1.131.0", - "@aws-cdk/aws-cognito": "~1.131.0", - "@aws-cdk/aws-ec2": "~1.131.0", - "@aws-cdk/aws-ecr": "~1.131.0", - "@aws-cdk/aws-ecr-assets": "~1.131.0", - "@aws-cdk/aws-ecs": "~1.131.0", - "@aws-cdk/aws-efs": "~1.131.0", - "@aws-cdk/aws-elasticloadbalancing": "~1.131.0", - "@aws-cdk/aws-elasticloadbalancingv2": "~1.131.0", - "@aws-cdk/aws-events": "~1.131.0", - "@aws-cdk/aws-iam": "~1.131.0", - "@aws-cdk/aws-kms": "~1.131.0", - "@aws-cdk/aws-lambda": "~1.131.0", - "@aws-cdk/aws-logs": "~1.131.0", - "@aws-cdk/aws-route53": "~1.131.0", - "@aws-cdk/aws-route53-targets": "~1.131.0", - "@aws-cdk/aws-s3": "~1.131.0", - "@aws-cdk/aws-s3-assets": "~1.131.0", - "@aws-cdk/aws-sam": "~1.131.0", - "@aws-cdk/aws-secretsmanager": "~1.131.0", - "@aws-cdk/aws-servicediscovery": "~1.131.0", - "@aws-cdk/aws-sns": "~1.131.0", - "@aws-cdk/aws-sns-subscriptions": "~1.131.0", - "@aws-cdk/aws-sqs": "~1.131.0", - "@aws-cdk/aws-ssm": "~1.131.0", - "@aws-cdk/cloud-assembly-schema": "~1.131.0", - "@aws-cdk/core": "~1.131.0", - "@aws-cdk/custom-resources": "~1.131.0", - "@aws-cdk/cx-api": "~1.131.0", - "@aws-cdk/region-info": "~1.131.0", + "@aws-cdk/assets": "~1.124.0", + "@aws-cdk/aws-apigateway": "~1.124.0", + "@aws-cdk/aws-apigatewayv2": "~1.124.0", + "@aws-cdk/aws-applicationautoscaling": "~1.124.0", + "@aws-cdk/aws-autoscaling": "~1.124.0", + "@aws-cdk/aws-autoscaling-common": "~1.124.0", + "@aws-cdk/aws-autoscaling-hooktargets": "~1.124.0", + "@aws-cdk/aws-certificatemanager": "~1.124.0", + "@aws-cdk/aws-cloudformation": "~1.124.0", + "@aws-cdk/aws-cloudfront": "~1.124.0", + "@aws-cdk/aws-cloudwatch": "~1.124.0", + "@aws-cdk/aws-codebuild": "~1.124.0", + "@aws-cdk/aws-codeguruprofiler": "~1.124.0", + "@aws-cdk/aws-codepipeline": "~1.124.0", + "@aws-cdk/aws-codepipeline-actions": "~1.124.0", + "@aws-cdk/aws-cognito": "~1.124.0", + "@aws-cdk/aws-ec2": "~1.124.0", + "@aws-cdk/aws-ecr": "~1.124.0", + "@aws-cdk/aws-ecr-assets": "~1.124.0", + "@aws-cdk/aws-ecs": "~1.124.0", + "@aws-cdk/aws-efs": "~1.124.0", + "@aws-cdk/aws-elasticloadbalancing": "~1.124.0", + "@aws-cdk/aws-elasticloadbalancingv2": "~1.124.0", + "@aws-cdk/aws-events": "~1.124.0", + "@aws-cdk/aws-iam": "~1.124.0", + "@aws-cdk/aws-kms": "~1.124.0", + "@aws-cdk/aws-lambda": "~1.124.0", + "@aws-cdk/aws-logs": "~1.124.0", + "@aws-cdk/aws-route53": "~1.124.0", + "@aws-cdk/aws-route53-targets": "~1.124.0", + "@aws-cdk/aws-s3": "~1.124.0", + "@aws-cdk/aws-s3-assets": "~1.124.0", + "@aws-cdk/aws-sam": "~1.124.0", + "@aws-cdk/aws-secretsmanager": "~1.124.0", + "@aws-cdk/aws-servicediscovery": "~1.124.0", + "@aws-cdk/aws-sns": "~1.124.0", + "@aws-cdk/aws-sns-subscriptions": "~1.124.0", + "@aws-cdk/aws-sqs": "~1.124.0", + "@aws-cdk/aws-ssm": "~1.124.0", + "@aws-cdk/cloud-assembly-schema": "~1.124.0", + "@aws-cdk/core": "~1.124.0", + "@aws-cdk/custom-resources": "~1.124.0", + "@aws-cdk/cx-api": "~1.124.0", + "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", "amplify-cli-core": "1.31.1", 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 index c46a6881fb..98a3659067 100644 --- 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 @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1024.0", + "aws-sdk": "^2.845.0", "axios": "^0.21.4", "body-parser": "^1.19.0", "express": "^4.17.1", 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 index b7e6db8d44..9c72bb598f 100644 --- 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 @@ -9,8 +9,8 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1024.0", + "aws-sdk": "^2.845.0", "body-parser": "^1.19.0", "express": "^4.17.1" } - } + } \ No newline at end of file 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 index fb264e3a23..ee61e94075 100644 --- 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 @@ -7,7 +7,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1024.0", + "aws-sdk": "^2.845.0", "express": "^4.17.1", "express-graphql": "^0.11.0", "graphql": "^15.4.0" From 28301285376b9c22891d299789dbab78f661e997 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Tue, 9 Nov 2021 16:38:59 -0800 Subject: [PATCH 484/587] Revert "Lambda auth minor fixes (#8741)" (#8762) This reverts commit c2d1177575de360983ec12bb430f06c9d8381af9. --- .../graphql-lambda-authorizer-index.js | 25 +++ ...graphql-lambda-authorizer-package.json.ejs | 6 + ...raphql-lambda-authorizer-template.json.ejs | 208 ++++++++++++++++++ .../appSync-walkthrough.ts | 53 +++-- 4 files changed, 276 insertions(+), 16 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs create mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js new file mode 100644 index 0000000000..20f0971452 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js @@ -0,0 +1,25 @@ +// This is sample code. Please update this to suite your schema + +exports.handler = async (event) => { + console.log(`event >`, JSON.stringify(event, null, 2)); + const { + authorizationToken, + requestContext: { apiId, accountId }, + } = event; + const response = { + isAuthorized: authorizationToken === 'custom-authorized', + resolverContext: { + userid: 'user-id', + info: 'contextual information A', + more_info: 'contextual information B', + }, + deniedFields: [ + `arn:aws:appsync:${process.env.AWS_REGION}:${accountId}:apis/${apiId}/types/Event/fields/comments`, + `Mutation.createEvent`, + ], + ttlOverride: 300, + }; + console.log(`response >`, JSON.stringify(response, null, 2)); + return response; +}; + diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs new file mode 100644 index 0000000000..e2f9e8b41d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs @@ -0,0 +1,6 @@ +{ + "name": "<%= props.functionName %>", + "version": "1.0.0", + "description": "Lambda function generated by Amplify for AppSync Lambda authorizer", + "main": "index.js" +} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs new file mode 100644 index 0000000000..acd908246d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs @@ -0,0 +1,208 @@ +{ + "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": "nodejs14.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/*" + ] + ] + } + <% } %> + ] + } + <% } %> + ] + } + } + } + ,"PermissionForAppSyncToInvokeLambda": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": { + "Ref": "LambdaFunction" + }, + "Action": "lambda:InvokeFunction", + "Principal": "appsync.amazonaws.com" + } + } + <% 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/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 52de5b0701..933134e813 100644 --- 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 @@ -1143,25 +1143,46 @@ async function askLambdaFromProject(context: $TSContext) { } async function createLambdaAuthorizerFunction(context: $TSContext) { + const targetDir = context.amplify.pathManager.getBackendDirPath(); + const assetDir = path.normalize(path.join(rootAssetDir, 'graphql-lambda-authorizer')); const [shortId] = uuid().split('-'); + const functionName = `graphQlLambdaAuthorizer${shortId}`; - const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ - context, - 'awscloudformation', - FunctionServiceNameLambdaFunction, + + const functionProps = { + functionName: `${functionName}`, + roleName: `${functionName}LambdaRole`, + }; + + const copyJobs = [ { - functionName, - defaultRuntime: 'nodejs', - providerContext: { - provider: 'awscloudformation', - }, - template: 'lambda-auth', - skipAdvancedSection: true, - skipNextSteps: true, + dir: assetDir, + template: 'graphql-lambda-authorizer-index.js', + target: `${targetDir}/function/${functionName}/src/index.js`, + }, + { + dir: assetDir, + template: 'graphql-lambda-authorizer-package.json.ejs', + target: `${targetDir}/function/${functionName}/src/package.json`, }, - ]); + { + dir: assetDir, + template: 'graphql-lambda-authorizer-template.json.ejs', + target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + }, + ]; - context.print.success(`Successfully added ${resourceName} function locally`); - await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [resourceName]); - return resourceName; + // copy over the files + await context.amplify.copyBatch(context, copyJobs, functionProps, true); + + const backendConfigs = { + service: FunctionServiceNameLambdaFunction, + providerPlugin: provider, + build: true, + }; + + await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); + context.print.success(`Successfully added ${functionName} function locally`); + + return functionName; } From 5e8d617cffddcbfcb14ffd3b1c403e7942a087e4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 11 Nov 2021 00:23:35 +0000 Subject: [PATCH 485/587] chore(release): Publish [ci skip] - amplify-app@3.0.17 - amplify-appsync-simulator@1.27.8 - amplify-category-analytics@2.21.25 - amplify-category-api@2.34.0 - amplify-category-auth@2.38.5 - amplify-category-function@2.37.0 - amplify-category-geo@1.2.0 - amplify-category-hosting@2.7.25 - amplify-category-interactions@2.6.9 - amplify-category-predictions@2.9.16 - amplify-category-storage@2.13.0 - amplify-category-xr@2.8.25 - amplify-cli-core@1.32.0 - @aws-amplify/cli@6.4.0 - amplify-codegen-appsync-model-plugin@1.22.5 - amplify-console-hosting@1.9.16 - amplify-console-integration-tests@1.8.15 - amplify-container-hosting@1.3.28 - amplify-dotnet-function-template-provider@1.5.25 - amplify-dynamodb-simulator@1.19.16 - amplify-e2e-core@1.31.0 - amplify-e2e-tests@2.55.0 - amplify-frontend-ios@2.20.18 - amplify-frontend-javascript@2.25.1 - amplify-go-function-runtime-provider@1.9.8 - @aws-amplify/graphql-auth-transformer@0.2.0 - @aws-amplify/graphql-default-value-transformer@0.3.0 - @aws-amplify/graphql-function-transformer@0.4.6 - @aws-amplify/graphql-http-transformer@0.5.6 - @aws-amplify/graphql-index-transformer@0.5.0 - amplify-graphql-migration-tests@1.0.1 - @aws-amplify/graphql-model-transformer@0.7.0 - @aws-amplify/graphql-predictions-transformer@0.3.6 - @aws-amplify/graphql-relational-transformer@0.4.0 - @aws-amplify/graphql-searchable-transformer@0.7.0 - @aws-amplify/graphql-transformer-core@0.10.0 - @aws-amplify/graphql-transformer-interfaces@1.10.1 - @aws-amplify/graphql-transformer-migrator@0.2.0 - amplify-headless-interface@1.11.0 - amplify-java-function-runtime-provider@1.8.18 - amplify-migration-tests@3.1.15 - amplify-nodejs-function-runtime-provider@1.6.15 - amplify-nodejs-function-template-provider@1.6.25 - amplify-prompts@1.3.0 - amplify-provider-awscloudformation@4.65.0 - amplify-python-function-runtime-provider@1.9.15 - amplify-util-headless-input@1.6.0 - amplify-util-import@1.5.16 - amplify-util-mock@3.34.12 - graphql-auth-transformer@6.25.0 - graphql-connection-transformer@4.22.0 - graphql-dynamodb-transformer@6.23.0 - graphql-elasticsearch-transformer@4.13.0 - graphql-function-transformer@2.5.25 - graphql-http-transformer@4.18.13 - graphql-key-transformer@2.23.26 - graphql-mapping-template@4.18.4 - graphql-predictions-transformer@2.5.25 - graphql-relational-schema-transformer@2.18.8 - graphql-transformer-common@4.20.0 - graphql-transformer-core@6.31.0 - graphql-transformers-e2e-tests@6.29.0 - graphql-versioned-transformer@4.17.26 --- packages/amplify-category-api/CHANGELOG.md | 33 ++++++++++++++++++++++ packages/amplify-category-api/package.json | 16 +++++------ 2 files changed, 41 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index be752508e9..4985ac44f1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,39 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a9f73c754e..387368e519 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.33.2", + "version": "2.34.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "0.1.0", + "@aws-amplify/graphql-transformer-migrator": "0.2.0", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,17 +64,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.31.1", - "amplify-headless-interface": "1.10.0", - "amplify-prompts": "1.2.0", + "amplify-cli-core": "1.32.0", + "amplify-headless-interface": "1.11.0", + "amplify-prompts": "1.3.0", "amplify-provider-awscloudformation": "4.61.1", - "amplify-util-headless-input": "1.5.4", + "amplify-util-headless-input": "1.6.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.7", - "graphql-transformer-core": "6.30.2", + "graphql-relational-schema-transformer": "2.18.8", + "graphql-transformer-core": "6.31.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From e6bd4c8389f88cc1e06d3e4de154d148e03efcdf Mon Sep 17 00:00:00 2001 From: John Hockett Date: Wed, 3 Nov 2021 14:53:43 -0700 Subject: [PATCH 486/587] feat: extensibility for REST APIs (#8598) --- packages/amplify-category-api/.npmignore | 1 + packages/amplify-category-api/package.json | 9 +- ...w-cloudformation-template-default.json.ejs | 512 -------------- .../overrides-resource/APIGW/override.ts | 8 + .../overrides-resource/APIGW/package.json | 17 + .../overrides-resource/APIGW/tsconfig.json | 11 + .../APIGW/tsconfig.resource.json | 13 + .../APIGatewayCLIInputs.schema.json | 68 ++ .../scripts/generateApiSchemas.ts | 14 + ...test.js => add-graphql-datasource.test.ts} | 4 +- .../cfn-api-artifact-handler.test.ts | 48 +- .../legacy-add-resource.test.ts | 19 +- .../legacy-update-resource.test.ts | 15 +- .../appSync-walkthrough.test.ts | 40 +- .../utils/rest-api-path-utils.test.ts | 8 +- .../amplify-category-api/src/commands/api.ts | 60 ++ .../commands/api/add-graphql-datasource.ts | 256 ++++--- .../src/commands/api/add.js | 75 -- .../src/commands/api/add.ts | 64 ++ .../src/commands/api/console.js | 25 - .../src/commands/api/console.ts | 24 + .../src/commands/api/gql-compile.js | 20 - .../src/commands/api/gql-compile.ts | 22 + .../src/commands/api/override.ts | 70 ++ .../src/commands/api/push.js | 17 - .../src/commands/api/push.ts | 17 + .../src/commands/api/rebuild.ts | 5 +- .../src/commands/api/remove.js | 31 - .../src/commands/api/remove.ts | 32 + .../src/commands/api/update.js | 30 - .../src/commands/api/update.ts | 30 + packages/amplify-category-api/src/index.ts | 128 ++-- .../awscloudformation/apigw-input-state.ts | 250 +++++++ .../awscloudformation/aws-constants.ts | 4 +- .../cdk-stack-builder/apigw-stack-builder.ts | 402 +++++++++++ .../apigw-stack-transform.ts | 197 ++++++ .../cdk-stack-builder/index.ts | 3 + .../cdk-stack-builder/types.ts | 53 ++ .../cfn-api-artifact-handler.ts | 40 +- .../awscloudformation/containers-handler.ts | 45 +- .../{apigw-defaults.js => apigw-defaults.ts} | 8 +- ...ppSync-defaults.js => appSync-defaults.ts} | 9 +- .../default-values/containers-defaults.ts | 8 +- .../awscloudformation/docker-compose/index.ts | 4 +- .../awscloudformation/ecs-alb-stack.ts | 2 +- .../provider-utils/awscloudformation/index.ts | 178 ++--- .../awscloudformation/legacy-add-resource.ts | 20 +- .../legacy-update-resource.ts | 19 +- .../aPIGateway-user-input-types.ts | 37 + .../service-walkthrough-types/apigw-types.ts | 28 + .../service-walkthroughs/apigw-walkthrough.ts | 650 +++++++----------- .../appSync-rds-walkthrough.ts | 33 +- .../appSync-walkthrough.ts | 197 +++--- .../containers-walkthrough.ts | 27 +- .../utils/amplify-meta-utils.ts | 24 +- .../utils/containers-artifacts.ts | 21 +- .../utils/dynamic-imports.ts | 14 +- .../utils/edit-schema-flow.ts | 20 +- .../utils/print-api-key-warnings.ts | 14 +- .../utils/rest-api-path-utils.ts | 4 +- .../provider-utils/supported-datasources.ts | 1 - .../src/provider-utils/supported-services.ts | 3 - packages/amplify-category-api/tsconfig.json | 4 +- 63 files changed, 2306 insertions(+), 1706 deletions(-) delete mode 100644 packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json create mode 100644 packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json create mode 100644 packages/amplify-category-api/scripts/generateApiSchemas.ts rename packages/amplify-category-api/src/__tests__/commands/api/{add-graphql-datasource.test.js => add-graphql-datasource.test.ts} (87%) create mode 100644 packages/amplify-category-api/src/commands/api.ts delete mode 100644 packages/amplify-category-api/src/commands/api/add.js create mode 100644 packages/amplify-category-api/src/commands/api/add.ts delete mode 100644 packages/amplify-category-api/src/commands/api/console.js create mode 100644 packages/amplify-category-api/src/commands/api/console.ts delete mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.js create mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.ts create mode 100644 packages/amplify-category-api/src/commands/api/override.ts delete mode 100644 packages/amplify-category-api/src/commands/api/push.js create mode 100644 packages/amplify-category-api/src/commands/api/push.ts delete mode 100644 packages/amplify-category-api/src/commands/api/remove.js create mode 100644 packages/amplify-category-api/src/commands/api/remove.ts delete mode 100644 packages/amplify-category-api/src/commands/api/update.js create mode 100644 packages/amplify-category-api/src/commands/api/update.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{apigw-defaults.js => apigw-defaults.ts} (68%) rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{appSync-defaults.js => appSync-defaults.ts} (71%) create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore index 89eeb1ee92..3af03e1d7c 100644 --- a/packages/amplify-category-api/.npmignore +++ b/packages/amplify-category-api/.npmignore @@ -1,5 +1,6 @@ **/__mocks__/** **/__tests__/** ./src +!resources/overrides-resource/tsconfig.json tsconfig.json tsconfig.tsbuildinfo diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 387368e519..4d0cc890b1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { - "name": "amplify-category-api", - "version": "2.34.0", + "name": "@aws-amplify/amplify-category-api", + "version": "1.0.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -14,7 +14,8 @@ "build": "tsc", "watch": "tsc -w", "clean": "rimraf lib tsconfig.tsbuildinfo", - "test": "jest" + "test": "jest", + "generateSchemas": "ts-node ./scripts/generateApiSchemas.ts" }, "dependencies": { "@aws-amplify/graphql-transformer-migrator": "0.2.0", @@ -79,7 +80,7 @@ "js-yaml": "^4.0.0", "lodash": "^4.17.21", "ora": "^4.0.3", - "uuid": "^3.4.0" + "uuid": "^8.3.2" }, "devDependencies": { "@types/js-yaml": "^4.0.0" diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs deleted file mode 100644 index 959fb43c00..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ /dev/null @@ -1,512 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "API Gateway resource stack creation using Amplify CLI", - <% if (props.dependsOn) { %> - "Parameters": { - "env": { - "Type": "String" - }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> - <% 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": { - <% for(var i=0; i < props.paths.length; i++) { %> - <%if (props.paths[i].privacy && props.paths[i].privacy.userPoolGroups) { %> - <% let selectedUserPoolGroupList = Object.keys(props.paths[i].privacy.userPoolGroups); %> - <% for(var j=0; j < selectedUserPoolGroupList.length; j++) { %> - "<%=selectedUserPoolGroupList[j]%>Group<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>Policy": { - "DependsOn": [ - "<%= props.apiName %>" - ], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "<%= props.apiName %>-<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>-<%=selectedUserPoolGroupList[j]%>-group-policy", - "Roles": [ - { - "Fn::Join": [ - "", - [ - { - "Ref": "auth<%= props.authResourceName%>UserPoolId" - }, - "-<%=selectedUserPoolGroupList[j]%>GroupRole" - ] - ] - } - ], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "execute-api:Invoke" - ], - "Resource": [ - - <% for(var x=0; x < props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length; x++) { %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].policyResourceName %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].policyResourceName %>" - ] - ] - } - <% if (x !== props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length - 1) { %> - , - <% } %> - <% } %> - ] - } - ] - } - } - }, - <% } %> - <% } %> - <% } %> - "<%= props.apiName %>": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "Description": "", - "Name": "<%= props.apiName %>", - "Body": { - "swagger": "2.0", - "info": { - "version": "2018-05-24T17:52:00Z", - "title": "<%= props.apiName %>" - }, - "host": { - "Fn::Join": [ - "", - [ - "apigateway.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" - ] - ] - }, - "basePath": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "/Prod", - { - "Fn::Join": [ - "", - [ - "/", - { - "Ref": "env" - } - ] - ] - } - ] - }, - "schemes": [ - "https" - ], - "paths": { - <% for(var i=0; i < props.paths.length; i++) { %> - "<%= props.paths[i].name %>": { - "options": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "200 response", - "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,X-Amz-User-Agent'", - "method.response.header.Access-Control-Allow-Origin": "'*'" - } - } - }, - "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" - } - } - }, - <%if (!props.paths[i].privacy.open) { %> - "security": [ - { - "sigv4": [] - } - ], - <% } %> - "x-amazon-apigateway-integration": { - "responses": { - "default": { - "statusCode": "200" - } - }, - "uri": { - "Fn::Join": [ - "", - [ - "arn:aws:apigateway:", - { - "Ref": "AWS::Region" - }, - ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn ) { %> - "<%= props.paths[i].lambdaArn %>", - <% } else { %> - { - - "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" - }, - <% } %> - "/invocations" - ] - ] - }, - "passthroughBehavior": "when_no_match", - "httpMethod": "POST", - "type": "aws_proxy" - } - } - }, - "<%= props.paths[i].name %>/{proxy+}": { - "options": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "200 response", - "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,X-Amz-User-Agent'", - "method.response.header.Access-Control-Allow-Origin": "'*'" - } - } - }, - "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" - } - } - }, - <%if (!props.paths[i].privacy.open) { %> - "security": [ - { - "sigv4": [] - } - ], - <% } %> - "x-amazon-apigateway-integration": { - "responses": { - "default": { - "statusCode": "200" - } - }, - "uri": { - "Fn::Join": [ - "", - [ - "arn:aws:apigateway:", - { - "Ref": "AWS::Region" - }, - ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn) { %> - "<%= props.paths[i].lambdaArn %>", - <% } else { %> - { - - "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" - }, - <% } %> - "/invocations" - ] - ] - }, - "passthroughBehavior": "when_no_match", - "httpMethod": "POST", - "type": "aws_proxy" - } - } - }<% if (i !== props.paths.length - 1) { %>,<% } %> - <% } %> - }, - "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" - } - } - }, - "FailOnWarnings": true - } - }, - - <%if (props.functionArns) { %> - <% for (var i=0; i < props.functionArns.length; i++) { %> - - "function<%= props.functionArns[i].lambdaFunction.replace(/[^0-9a-zA-Z]/gi, '') %>Permission<%= props.apiName %>": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "FunctionName": <% if (props.functionArns[i].lambdaArn) {%> "<%= props.functionArns[i].lambdaArn %>", <% } else { %> - { - "Ref": "function<%= props.functionArns[i].lambdaFunction %>Name" - }, - <% } %> - "Action": "lambda:InvokeFunction", - "Principal": "apigateway.amazonaws.com", - "SourceArn": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/*/*/*" - ] - ] - } - } - }, - <% } %> - <% } %> - - "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "Description": "The Development stage deployment of your API.", - "StageName": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "RestApiId": { - "Ref": "<%= props.apiName %>" - } - } - } - }, - "Outputs": { - "RootUrl": { - "Description": "Root URL of the API gateway", - "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} - }, - "ApiName": { - "Description": "API Friendly name", - "Value": "<%= props.resourceName %>" - }, - "ApiId": { - "Description": "API ID (prefix of API URL)", - "Value": {"Ref": "<%= props.apiName %>"} - } - } - } diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts new file mode 100644 index 0000000000..ac3781476a --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts @@ -0,0 +1,8 @@ +// This file is used to override the REST API resource configuration +// import { AmplifyApigwResourceTemplate } from '@aws-amplify/cli-overrides-helper'; + +/* TODO: Need to change props to Root-Stack specific props when props are ready */ +export function overrideProps(props: any) { + /* Override props (AmplifyApigwResourceTemplate) with new parameters */ + return props; +} 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 new file mode 100644 index 0000000000..61f6fd48bc --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json @@ -0,0 +1,17 @@ +{ + "name": "overrides-for-root-stack", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "tsc", + "watch": "tsc -w", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "fs-extra": "^9.1.0" + }, + "devDependencies": { + "@types/fs-extra": "^9.0.11", + "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 new file mode 100644 index 0000000000..c6f1a33b4d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json @@ -0,0 +1,11 @@ +{ + "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 new file mode 100644 index 0000000000..6504da8028 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "strict": false, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./", + "rootDir": "../" + }, + "include": ["../**/*"] +} diff --git a/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json new file mode 100644 index 0000000000..a0b2cbe39b --- /dev/null +++ b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json @@ -0,0 +1,68 @@ +{ + "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": "array", + "items": { + "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#" +} diff --git a/packages/amplify-category-api/scripts/generateApiSchemas.ts b/packages/amplify-category-api/scripts/generateApiSchemas.ts new file mode 100644 index 0000000000..e611a1a84b --- /dev/null +++ b/packages/amplify-category-api/scripts/generateApiSchemas.ts @@ -0,0 +1,14 @@ +import * as SchemaGenerator from 'amplify-cli-core'; + +type TypeDef = SchemaGenerator.TypeDef; + +const ApigwTypeDef: TypeDef = { + typeName: 'APIGatewayCLIInputs', + service: 'API Gateway', +}; + +// Defines the type names and the paths to the TS files that define them +const apigwCategoryTypeDefs: TypeDef[] = [ApigwTypeDef]; + +const schemaGenerator = new SchemaGenerator.CLIInputSchemaGenerator(apigwCategoryTypeDefs); +schemaGenerator.generateJSONSchemas(); // convert CLI input data into json schemas. diff --git a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts similarity index 87% rename from packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js rename to packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts index 701aadaa8c..b0acae414d 100644 --- a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js +++ b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts @@ -1,5 +1,5 @@ -const { readSchema } = require('../../../commands/api/add-graphql-datasource'); -const path = require('path'); +import { readSchema } from '../../../commands/api/add-graphql-datasource'; +import * as path from 'path'; describe('read schema', () => { it('Valid schema present in folder', async () => { 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 index e8dfa51770..1d3cbeefbf 100644 --- 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 @@ -1,19 +1,23 @@ -import path from 'path'; -import fs from 'fs-extra'; -import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; -import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; +import { $TSContext, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; -import { category } from '../../../category-constants'; +import { printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; import { writeTransformerConfiguration } from 'graphql-transformer-core'; +import _ from 'lodash'; +import * as path from 'path'; +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 { - getAppSyncResourceName, - getAppSyncAuthConfig, authConfigHasApiKey, + getAppSyncAuthConfig, + getAppSyncResourceName, } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import _ from 'lodash'; jest.mock('fs-extra'); +const printer_mock = printer as jest.Mocked; +printer_mock.warn = jest.fn(); jest.mock('graphql-transformer-core', () => ({ readTransformerConfiguration: jest.fn(async () => ({})), @@ -30,32 +34,26 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', jest.mock('amplify-cli-core'); +const backendDirPathStub = 'backendDirPath'; +const testApiName = 'testApiName'; + +const pathManager_mock = pathManager as jest.Mocked; +pathManager_mock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); +const stateManager_mock = stateManager as jest.Mocked; + const fs_mock = fs as unknown as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; -const backendDirPathStub = 'backendDirPath'; - -const testApiName = 'testApiName'; - const context_stub = { - print: { - success: jest.fn(), - warning: jest.fn(), - }, amplify: { updateamplifyMetaAfterResourceAdd: jest.fn(), updateamplifyMetaAfterResourceUpdate: jest.fn(), updateBackendConfigAfterResourceUpdate: jest.fn(), executeProviderUtils: jest.fn(), copyBatch: jest.fn(), - getProjectMeta: jest.fn(), - readJsonFile: jest.fn(), - pathManager: { - getBackendDirPath: jest.fn(() => backendDirPathStub), - }, }, }; @@ -80,7 +78,7 @@ describe('create artifacts', () => { }); beforeEach(() => { jest.clearAllMocks(); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); }); it('does not create a second API if one already exists', async () => { @@ -180,7 +178,7 @@ describe('update artifacts', () => { beforeEach(() => { jest.clearAllMocks(); updateRequestStub = _.cloneDeep(updateRequestStubBase); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); }); it('throws error if no GQL API in project', () => { @@ -236,12 +234,12 @@ describe('update artifacts', () => { it('prints warning when adding API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.print.warning.mock.calls.length).toBe(2); + expect(printer_mock.warn.mock.calls.length).toBe(2); }); it('prints warning when removing API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.print.warning.mock.calls.length).toBe(3); + expect(printer_mock.warn.mock.calls.length).toBe(3); }); }); 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 index 4dc7ed152f..ada52d192c 100644 --- 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 @@ -1,22 +1,29 @@ import { legacyAddResource } from '../../../provider-utils/awscloudformation/legacy-add-resource'; import { category } from '../../../category-constants'; +import { $TSAny, $TSContext } from 'amplify-cli-core'; jest.mock('fs-extra'); -jest.mock('amplify-cli-core'); +jest.mock('amplify-cli-core', () => ({ + 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: { - pathManager: { - getBackendDirPath: jest.fn(_ => 'mock/backend/path'), - }, updateamplifyMetaAfterResourceAdd: jest.fn(), copyBatch: jest.fn(), }, }; it('sets policy resource name in paths object before copying template', async () => { - const stubWalkthroughPromise: Promise = Promise.resolve({ + const stubWalkthroughPromise: Promise<$TSAny> = Promise.resolve({ answers: { resourceName: 'mockResourceName', paths: [ @@ -29,7 +36,7 @@ describe('legacy add resource', () => { ], }, }); - await legacyAddResource(stubWalkthroughPromise, contextStub, category, 'API Gateway', {}); + 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 index 135f62250f..cf6e04f21f 100644 --- 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 @@ -1,14 +1,21 @@ +import { $TSContext } from 'amplify-cli-core'; import { legacyUpdateResource } from '../../../provider-utils/awscloudformation/legacy-update-resource'; import { category } from '../../../category-constants'; jest.mock('fs-extra'); +jest.mock('amplify-cli-core', () => ({ + JSONUtilities: { + readJson: jest.fn(), + writeJson: jest.fn(), + }, + pathManager: { + getResourceDirectoryPath: jest.fn(_ => 'mock/backend/path'), + }, +})); describe('legacy update resource', () => { const contextStub = { amplify: { - pathManager: { - getBackendDirPath: jest.fn(_ => 'mock/backend/path'), - }, updateamplifyMetaAfterResourceUpdate: jest.fn(), copyBatch: jest.fn(), }, @@ -28,7 +35,7 @@ describe('legacy update resource', () => { ], }, }); - await legacyUpdateResource(stubWalkthroughPromise, contextStub, category, 'API Gateway'); + 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/service-walkthroughs/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts index 6e6a75c8d8..9b2db83f7b 100644 --- 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 @@ -1,42 +1,51 @@ +import { $TSAny, $TSContext, FeatureFlags, pathManager, stateManager } from 'amplify-cli-core'; import { - getIAMPolicies, askAdditionalAuthQuestions, + getIAMPolicies, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { FeatureFlags } from 'amplify-cli-core'; + jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), })); jest.mock('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(), - }, -}); +const context_stub = (prompt: jest.Mock) => + ({ + prompt: { + confirm: prompt, + }, + amplify: { + getProjectMeta: jest.fn(), + }, + } as unknown as $TSContext); type IAMArtifact = { attributes: string[]; - policy: any; + policy: $TSAny; }; 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -49,7 +58,7 @@ describe('get IAM policies', () => { it('includes API key if it exists', async () => { mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -63,7 +72,7 @@ describe('get IAM policies', () => { 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query', 'Mutate']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -73,10 +82,11 @@ describe('get IAM policies', () => { 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['create', 'update']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", 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 index 7c82402f42..6facce6d56 100644 --- 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 @@ -4,7 +4,7 @@ import { formatCFNPathParamsForExpressJs, } from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; -const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }, { name: '/path/{with}/{params}' }]; +const stubOtherPaths = ['/other/path', '/sub/path', '/path/{with}/{params}']; test('validatePathName_validPath', () => { expect(validatePathName('/some/path')).toBe(true); @@ -56,9 +56,9 @@ test('checkForPathOverlap_subPathParamsNoMatch', () => { }); test('checkForPathOverlap_pathMatch', () => { - expect(checkForPathOverlap(stubOtherPaths[0].name, stubOtherPaths)).toEqual({ - higherOrderPath: stubOtherPaths[0].name, - lowerOrderPath: stubOtherPaths[0].name, + expect(checkForPathOverlap(stubOtherPaths[0], stubOtherPaths)).toEqual({ + higherOrderPath: stubOtherPaths[0], + lowerOrderPath: stubOtherPaths[0], }); }); diff --git a/packages/amplify-category-api/src/commands/api.ts b/packages/amplify-category-api/src/commands/api.ts new file mode 100644 index 0000000000..d9741de9a9 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api.ts @@ -0,0 +1,60 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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: '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', + }, + ]; + + 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 index d4bd9be8d8..b9a235b802 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -1,171 +1,169 @@ +import { mergeTypeDefs } from '@graphql-tools/merge'; +import { $TSAny, $TSContext, exitOnNextTick, FeatureFlags, pathManager, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; -import * as path from 'path'; import * as graphql from 'graphql'; -import _ from 'lodash'; -import inquirer from 'inquirer'; import { + AuroraServerlessMySQLDatabaseReader, RelationalDBSchemaTransformer, RelationalDBTemplateGenerator, - AuroraServerlessMySQLDatabaseReader, } from 'graphql-relational-schema-transformer'; -import { mergeTypeDefs } from '@graphql-tools/merge'; -import { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick, $TSAny, $TSContext, stateManager, pathManager } from 'amplify-cli-core'; +import inquirer from 'inquirer'; +import _ from 'lodash'; +import * as path from 'path'; const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; const providerName = 'awscloudformation'; -module.exports = { - name: subcommand, - run: async (context: $TSContext) => { - try { - const servicesMetadata = (await import('../../provider-utils/supported-datasources')).supportedDatasources; +export const name = subcommand; - const AWS = await getAwsClient(context, 'list'); +export const run = async (context: $TSContext) => { + try { + const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; + const AWS = await getAwsClient(context, 'list'); - const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); + const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); - const providerController = await import(`../../provider-utils/${result.providerName}/index`); + const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - if (!providerController) { - context.print.error('Provider not configured for this category'); - return; - } + 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; - - /** - * Write the new env specific datasource information into - * the team-provider-info file - */ - const currEnv = context.amplify.getEnvInfo().envName; - const teamProviderInfo = stateManager.getTeamProviderInfo(); - - _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { - rdsRegion: answers.region, - rdsClusterIdentifier: answers.dbClusterArn, - rdsSecretStoreArn: answers.secretStoreArn, - rdsDatabaseName: answers.databaseName, - }); - - stateManager.setTeamProviderInfo(undefined, teamProviderInfo); - - 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 instrospection to get the GraphQL Schema and Template Context - */ - const improvePluralizationFlag = FeatureFlags.getBoolean('graphqltransformer.improvePluralization'); - const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName, improvePluralizationFlag); - const graphqlSchemaContext = await relationalSchemaTransformer.introspectDatabaseSchema(); - - if (graphqlSchemaContext === null) { - context.print.warning('No importable tables were found in the selected Database.'); - context.print.info(''); - return; - } + const { datasource } = result; + const answers = await providerController.addDatasource(context, category, datasource); + + const { resourceName, databaseName } = answers; - /** - * Merge the GraphQL Schema with the existing schema.graphql in the projects stack - * - */ - const apiDirPath = path.join(pathManager.getBackendDirPath(), category, resourceName); + /** + * Write the new env specific datasource information into + * the team-provider-info file + */ + const currEnv = context.amplify.getEnvInfo().envName; + const teamProviderInfo = stateManager.getTeamProviderInfo(); - fs.ensureDirSync(apiDirPath); + _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { + rdsRegion: answers.region, + rdsClusterIdentifier: answers.dbClusterArn, + rdsSecretStoreArn: answers.secretStoreArn, + rdsDatabaseName: answers.databaseName, + }); - const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); - const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const schemaDirectoryPath = path.join(apiDirPath, 'schema'); + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); + + 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 instrospection to get the GraphQL Schema and Template Context + */ + 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.info(''); + return; + } - if (fs.existsSync(graphqlSchemaFilePath)) { - const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + /** + * Merge the GraphQL Schema with the existing schema.graphql in the projects stack + * + */ + const apiDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); - if (currGraphQLSchemaDoc) { - typesToBeMerged.unshift(currGraphQLSchemaDoc); - } else { - context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); - context.print.info(''); - } + fs.ensureDirSync(apiDirPath); - const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); + const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); + const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; + const schemaDirectoryPath = path.join(apiDirPath, 'schema'); - fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); - } else if (fs.existsSync(schemaDirectoryPath)) { - const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); + if (fs.existsSync(graphqlSchemaFilePath)) { + const typesToBeMerged = [rdsGraphQLSchemaDoc]; + const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); + if (currGraphQLSchemaDoc) { + typesToBeMerged.unshift(currGraphQLSchemaDoc); } else { - throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); + printer.warn(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); + printer.info(''); } - const resolversDir = path.join(apiDirPath, 'resolvers'); + const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); - /** - * Instantiate a new Relational Template Generator and create - * the template and relational resolvers - */ + fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); + } else if (fs.existsSync(schemaDirectoryPath)) { + const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); - const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); + fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); + } else { + throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); + } - let template = templateGenerator.createTemplate(context); + const resolversDir = path.join(apiDirPath, 'resolvers'); - template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); + /** + * Instantiate a new Relational Template Generator and create + * the template and relational resolvers + */ - const cfn = templateGenerator.printCloudformationTemplate(template); + const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); - /** - * Add the generated the CFN to the appropriate nested stacks directory - */ + let template = templateGenerator.createTemplate(context); - const stacksDir = path.join(apiDirPath, 'stacks'); - const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); + template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); - fs.writeFileSync(writeToPath, cfn, 'utf8'); + const cfn = templateGenerator.printCloudformationTemplate(template); - context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); + /** + * Add the generated the CFN to the appropriate nested stacks directory + */ - context.print.success(`Successfully added the ${datasource} datasource locally`); - context.print.info(''); - context.print.success('Some next steps:'); - context.print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - context.print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - context.print.info(''); - } catch (error) { - context.print.info(error.stack); - context.print.error('There was an error adding the datasource'); + const stacksDir = path.join(apiDirPath, 'stacks'); + const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); - await context.usageData.emitError(error); + fs.writeFileSync(writeToPath, cfn, 'utf8'); - process.exitCode = 1; - } - }, - readSchema, + 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.info(error.stack); + printer.error('There was an error adding the datasource'); + + await context.usageData.emitError(error); + + process.exitCode = 1; + } }; -async function datasourceSelectionPrompt(context, supportedDatasources) { +async function datasourceSelectionPrompt(context: $TSContext, supportedDatasources) { const options = []; Object.keys(supportedDatasources).forEach(datasource => { const optionName = @@ -184,7 +182,7 @@ async function datasourceSelectionPrompt(context, supportedDatasources) { if (options.length === 0) { const errMessage = `No datasources defined by configured providers for category: ${category}`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -193,7 +191,7 @@ async function datasourceSelectionPrompt(context, supportedDatasources) { if (options.length === 1) { // No need to ask questions - context.print.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); + printer.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); return new Promise(resolve => { resolve(options[0].value); @@ -219,7 +217,7 @@ async function getAwsClient(context: $TSContext, action: string) { return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); } -function readSchema(graphqlSchemaFilePath) { +export function readSchema(graphqlSchemaFilePath: string) { const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); if (graphqlSchemaRaw.trim().length === 0) { diff --git a/packages/amplify-category-api/src/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js deleted file mode 100644 index d883208b45..0000000000 --- a/packages/amplify-category-api/src/commands/api/add.js +++ /dev/null @@ -1,75 +0,0 @@ -const inquirer = require('inquirer'); -const subcommand = 'add'; -const category = 'api'; -const apiGatewayService = 'API Gateway'; - -let options; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(async result => { - options = { - service: result.service, - providerPlugin: result.providerName, - }; - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - context.print.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, category, result.service, options); - }) - .then(resourceName => { - const { print } = context; - print.success(`Successfully added resource ${resourceName} locally`); - print.info(''); - print.success('Some next steps:'); - print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - print.info(''); - }) - .catch(err => { - context.print.info(err.stack); - context.print.error('There was an error adding the API resource'); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; - -async function shouldUpdateExistingRestApi(context, selectedService) { - if (selectedService !== apiGatewayService) { - return false; - } - - const { allResources } = await context.amplify.getResourceStatus(); - const hasRestApis = allResources.some(resource => resource.service === apiGatewayService && resource.mobileHubMigrated !== true); - - if (!hasRestApis) { - return false; - } - - const question = [ - { - name: 'update', - message: 'Would you like to add a new path to an existing REST API:', - type: 'confirm', - default: true, - }, - ]; - const answer = await inquirer.prompt(question); - - return answer.update; -} diff --git a/packages/amplify-category-api/src/commands/api/add.ts b/packages/amplify-category-api/src/commands/api/add.ts new file mode 100644 index 0000000000..bf2f64e8c2 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/add.ts @@ -0,0 +1,64 @@ +import { $TSContext, $TSObject, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as path from 'path'; + +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.info(err.stack); + printer.error('There was an error adding the API resource'); + await context.usageData.emitError(err); + process.exitCode = 1; + }); +}; + +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: $TSObject) => 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.js b/packages/amplify-category-api/src/commands/api/console.js deleted file mode 100644 index a8bc4d57bc..0000000000 --- a/packages/amplify-category-api/src/commands/api/console.js +++ /dev/null @@ -1,25 +0,0 @@ -const subcommand = 'console'; -const category = 'api'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(async result => { - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - throw new Error(`Provider "${result.providerName}" is not configured for this category`); - } - return await providerController.console(context, result.service); - }) - .catch(err => { - context.print.error('Error opening console.'); - context.print.info(err.message); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/console.ts b/packages/amplify-category-api/src/commands/api/console.ts new file mode 100644 index 0000000000..2e2430047b --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/console.ts @@ -0,0 +1,24 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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.'); + printer.info(err.message); + await context.usageData.emitError(err); + process.exitCode = 1; + } +}; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.js b/packages/amplify-category-api/src/commands/api/gql-compile.js deleted file mode 100644 index a53e64d0fe..0000000000 --- a/packages/amplify-category-api/src/commands/api/gql-compile.js +++ /dev/null @@ -1,20 +0,0 @@ -const subcommand = 'gql-compile'; - -module.exports = { - name: subcommand, - run: async context => { - try { - const { - parameters: { options }, - } = context; - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - forceCompile: true, - minify: options['minify'], - }); - } catch (err) { - context.print.error(err.toString()); - context.usageData.emitError(err); - process.exitCode = 1; - } - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.ts b/packages/amplify-category-api/src/commands/api/gql-compile.ts new file mode 100644 index 0000000000..bcbbfba4f8 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/gql-compile.ts @@ -0,0 +1,22 @@ +import { $TSContext } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; + +const subcommand = 'gql-compile'; + +export const name = subcommand; + +export const run = async (context: $TSContext) => { + try { + const { + parameters: { options }, + } = context; + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + forceCompile: true, + minify: options['minify'], + }); + } catch (err) { + printer.error(err.toString()); + await context.usageData.emitError(err); + process.exitCode = 1; + } +}; diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts new file mode 100644 index 0000000000..a7d1047636 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/override.ts @@ -0,0 +1,70 @@ +import { + $TSContext, + AmplifyCategories, + AmplifySupportedService, + generateOverrideSkeleton, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as path from 'path'; +import { ApigwInputState } from '../../provider-utils/awscloudformation/apigw-input-state'; +import { ApigwStackTransform } from '../../provider-utils/awscloudformation/cdk-stack-builder'; + +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) { + throw 'To be implemented'; + } else if (service === AmplifySupportedService.APIGW) { + // Migration logic goes in here + const apigwInputState = ApigwInputState.getInstance(context, selectedResourceName); + if (!apigwInputState.cliInputsFileExists()) { + if (await prompter.yesOrNo('File migration required to continue. Do you want to continue?', true)) { + await apigwInputState.migrateApigwResource(selectedResourceName); + const stackGenerator = new ApigwStackTransform(context, selectedResourceName); + stackGenerator.transform(); + } else { + return; + } + } + } + + await generateOverrideSkeleton(context, srcPath, destPath); +}; diff --git a/packages/amplify-category-api/src/commands/api/push.js b/packages/amplify-category-api/src/commands/api/push.js deleted file mode 100644 index 8a0da0bb5a..0000000000 --- a/packages/amplify-category-api/src/commands/api/push.js +++ /dev/null @@ -1,17 +0,0 @@ -const subcommand = 'push'; -const category = 'api'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify, parameters } = context; - const resourceName = parameters.first; - context.amplify.constructExeInfo(context); - return amplify.pushResources(context, category, resourceName).catch(err => { - context.print.error('There was an error pushing the API resource'); - context.print.error(err.toString()); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/push.ts b/packages/amplify-category-api/src/commands/api/push.ts new file mode 100644 index 0000000000..ce32110c1c --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/push.ts @@ -0,0 +1,17 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; + +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).catch(async err => { + printer.error('There was an error pushing the API resource'); + printer.error(err.toString()); + await context.usageData.emitError(err); + process.exitCode = 1; + }); +}; diff --git a/packages/amplify-category-api/src/commands/api/rebuild.ts b/packages/amplify-category-api/src/commands/api/rebuild.ts index 26b8ead364..55c269da95 100644 --- a/packages/amplify-category-api/src/commands/api/rebuild.ts +++ b/packages/amplify-category-api/src/commands/api/rebuild.ts @@ -1,8 +1,7 @@ -import { $TSAny, $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, AmplifyCategories, FeatureFlags, stateManager } from 'amplify-cli-core'; import { printer, prompter, exact } from 'amplify-prompts'; const subcommand = 'rebuild'; -const category = 'api'; export const name = subcommand; @@ -36,5 +35,5 @@ export const run = async (context: $TSContext) => { const { amplify, parameters } = context; const resourceName = parameters.first; amplify.constructExeInfo(context); - return amplify.pushResources(context, category, resourceName, undefined, rebuild); + return amplify.pushResources(context, AmplifyCategories.API, resourceName, undefined, rebuild); }; diff --git a/packages/amplify-category-api/src/commands/api/remove.js b/packages/amplify-category-api/src/commands/api/remove.js deleted file mode 100644 index 8c334611a5..0000000000 --- a/packages/amplify-category-api/src/commands/api/remove.js +++ /dev/null @@ -1,31 +0,0 @@ -const path = require('path'); - -const subcommand = 'remove'; -const category = 'api'; -const gqlConfigFilename = '.graphqlconfig.yml'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify, parameters } = context; - const resourceName = parameters.first; - - return amplify - .removeResource(context, category, resourceName) - .then(resourceValues => { - if (!resourceValues) return; // indicates that the customer selected "no" at the confirmation prompt - if (resourceValues.service === 'AppSync') { - const { projectPath } = amplify.getEnvInfo(); - - const gqlConfigFile = path.normalize(path.join(projectPath, gqlConfigFilename)); - context.filesystem.remove(gqlConfigFile); - } - }) - .catch(err => { - context.print.info(err.stack); - context.print.error('There was an error removing the api resource'); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/remove.ts b/packages/amplify-category-api/src/commands/api/remove.ts new file mode 100644 index 0000000000..ac67429d87 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/remove.ts @@ -0,0 +1,32 @@ +import { $TSContext, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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.info(err.stack); + printer.error('There was an error removing the api resource'); + await context.usageData.emitError(err); + process.exitCode = 1; + } +}; diff --git a/packages/amplify-category-api/src/commands/api/update.js b/packages/amplify-category-api/src/commands/api/update.js deleted file mode 100644 index f55ec76e9f..0000000000 --- a/packages/amplify-category-api/src/commands/api/update.js +++ /dev/null @@ -1,30 +0,0 @@ -const { printer } = require('amplify-prompts'); - -const subcommand = 'update'; -const category = 'api'; - -module.exports = { - name: subcommand, - alias: ['configure'], - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(result => { - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - printer.error('Provider not configured for this category'); - return; - } - return providerController.updateResource(context, category, result.service); - }) - .then(() => printer.success('Successfully updated resource')) - .catch(err => { - printer.error(err.message || err); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/update.ts b/packages/amplify-category-api/src/commands/api/update.ts new file mode 100644 index 0000000000..8813a045be --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/update.ts @@ -0,0 +1,30 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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')) + .catch(async err => { + printer.error(err.message); + printer.info(err.stack); + await context.usageData.emitError(err); + process.exitCode = 1; + }); +}; diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 4ada1ab74d..f556148476 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -1,42 +1,57 @@ +import { + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + buildOverrideDir, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; -import fs from 'fs-extra'; -import path from 'path'; +import * as fs from 'fs-extra'; +import * as path from 'path'; import { run } from './commands/api/console'; +import { getAppSyncAuthConfig, getAppSyncResourceName } 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 { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; 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'; -export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; +export { getContainers } from './provider-utils/awscloudformation/docker-compose'; export { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; -export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; +export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; +export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; export { - generateContainersArtifacts, ApiResource, + generateContainersArtifacts, processDockerConfig, } from './provider-utils/awscloudformation/utils/containers-artifacts'; -export { getContainers } from './provider-utils/awscloudformation/docker-compose'; -export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; - -const category = 'api'; +export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; +const category = AmplifyCategories.API; const categories = 'categories'; -export async function console(context) { +export async function console(context: $TSContext) { await run(context); } -export async function migrate(context, serviceName) { - const { projectPath, amplifyMeta } = context.migrationInfo; +export async function migrate(context: $TSContext, serviceName?: string) { + const { projectPath } = context.migrationInfo; + const amplifyMeta = stateManager.getMeta(); const migrateResourcePromises = []; - Object.keys(amplifyMeta).forEach(categoryName => { + for (const categoryName of Object.keys(amplifyMeta)) { if (categoryName === category) { - Object.keys(amplifyMeta[category]).forEach(resourceName => { + for (const resourceName of Object.keys(amplifyMeta[category])) { try { if (amplifyMeta[category][resourceName].providerPlugin) { - const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + const providerController = await import( + path.join('.', 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') + ); if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( @@ -45,20 +60,20 @@ export async function migrate(context, serviceName) { } } } else { - context.print.error(`Provider not configured for ${category}: ${resourceName}`); + printer.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - context.print.warning(`Could not run migration for ${category}: ${resourceName}`); + printer.warn(`Could not run migration for ${category}: ${resourceName}`); throw e; } - }); + } } - }); + } await Promise.all(migrateResourcePromises); } -export async function initEnv(context) { +export async function initEnv(context: $TSContext) { const datasource = 'Aurora Serverless'; const service = 'service'; const rdsInit = 'rdsInit'; @@ -73,7 +88,7 @@ export async function initEnv(context) { * Check if we need to do the walkthrough, by looking to see if previous environments have * configured an RDS datasource */ - const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); + const backendConfigFilePath = pathManager.getBackendConfigFilePath(); // If this is a mobile hub migrated project without locally added resources then there is no // backend config exists yet. @@ -81,7 +96,7 @@ export async function initEnv(context) { return; } - const backendConfig = amplify.readJsonFile(backendConfigFilePath); + const backendConfig = stateManager.getBackendConfig(); if (!backendConfig[category]) { return; @@ -89,9 +104,9 @@ export async function initEnv(context) { let resourceName; const apis = Object.keys(backendConfig[category]); - for (let i = 0; i < apis.length; i += 1) { - if (backendConfig[category][apis[i]][service] === 'AppSync') { - resourceName = apis[i]; + for (const api of apis) { + if (backendConfig[category][api][service] === AmplifySupportedService.APPSYNC) { + resourceName = api; break; } } @@ -106,10 +121,10 @@ export async function initEnv(context) { return; } - const providerController = require('./provider-utils/awscloudformation/index'); + const providerController = await import(path.join('.', 'provider-utils', provider, 'index')); if (!providerController) { - context.print.error('Provider not configured for this category'); + printer.error('Provider not configured for this category'); return; } @@ -117,8 +132,7 @@ export async function initEnv(context) { * Check team provider info to ensure it hasn't already been created for current env */ const currEnv = amplify.getEnvInfo().envName; - const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); - const teamProviderInfo = amplify.readJsonFile(teamProviderInfoFilePath); + const teamProviderInfo = stateManager.getTeamProviderInfo(); if ( teamProviderInfo[currEnv][categories] && teamProviderInfo[currEnv][categories][category] && @@ -153,16 +167,15 @@ export async function initEnv(context) { teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; - fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); }) .then(() => { context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); }); } -export async function getPermissionPolicies(context, resourceOpsMapping) { - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); +export async function getPermissionPolicies(context: $TSContext, resourceOpsMapping: $TSObject) { + const amplifyMeta = stateManager.getMeta(); const permissionPolicies = []; const resourceAttributes = []; @@ -171,7 +184,7 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { try { const providerName = amplifyMeta[category][resourceName].providerPlugin; if (providerName) { - const providerController = require(`./provider-utils/${providerName}/index`); + const providerController = await import(path.join('.', 'provider-utils', providerName, 'index')); const { policy, attributes } = await providerController.getPermissionPolicies( context, amplifyMeta[category][resourceName].service, @@ -181,10 +194,10 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); } else { - context.print.error(`Provider not configured for ${category}: ${resourceName}`); + printer.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - context.print.warning(`Could not get policies for ${category}: ${resourceName}`); + printer.warn(`Could not get policies for ${category}: ${resourceName}`); throw e; } }), @@ -192,7 +205,7 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { return { permissionPolicies, resourceAttributes }; } -export async function executeAmplifyCommand(context) { +export async function executeAmplifyCommand(context: $TSContext) { let commandPath = path.normalize(path.join(__dirname, 'commands')); if (context.input.command === 'help') { commandPath = path.join(commandPath, category); @@ -200,11 +213,11 @@ export async function executeAmplifyCommand(context) { commandPath = path.join(commandPath, category, context.input.command); } - const commandModule = require(commandPath); + const commandModule = await import(commandPath); await commandModule.run(context); } -export const executeAmplifyHeadlessCommand = async (context, headlessPayload: string) => { +export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => { switch (context.input.command) { case 'add': await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); @@ -213,23 +226,24 @@ export const executeAmplifyHeadlessCommand = async (context, headlessPayload: st await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); break; default: - context.print.error(`Headless mode for ${context.input.command} api is not implemented yet`); + printer.error(`Headless mode for ${context.input.command} api is not implemented yet`); } }; -export async function handleAmplifyEvent(context, args) { - context.print.info(`${category} handleAmplifyEvent to be implemented`); - context.print.info(`Received event args ${args}`); +export async function handleAmplifyEvent(context: $TSContext, args) { + printer.info(`${category} handleAmplifyEvent to be implemented`); + printer.info(`Received event args ${args}`); } -export async function addGraphQLAuthorizationMode(context, args) { +export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TSObject) { const { authType, printLeadText, authSettings } = args; - const apiName = getAppSyncResourceName(context.amplify.getProjectMeta()); + const meta = stateManager.getMeta(); + const apiName = getAppSyncResourceName(meta); if (!apiName) { return; } - const authConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + const authConfig = getAppSyncAuthConfig(meta); const addAuthConfig = await askAuthQuestions(authType, context, printLeadText, authSettings); authConfig.additionalAuthenticationProviders.push(addAuthConfig); await context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); @@ -250,3 +264,23 @@ export async function addGraphQLAuthorizationMode(context, args) { return addAuthConfig; } + +export async function transformCategoryStack(context: $TSContext, resource: $TSObject) { + if (resource.service === AmplifySupportedService.APIGW) { + if (canResourceBeTransformed(resource.resourceName)) { + const backendDir = pathManager.getBackendDirPath(); + const overrideDir = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, resource.resourceName); + await buildOverrideDir(backendDir, overrideDir).catch(error => { + printer.debug(`Skipping build as ${error.message}`); + return false; + }); + // Rebuild CFN + const apigwStack = new ApigwStackTransform(context, resource.resourceName); + apigwStack.transform(); + } + } +} + +function canResourceBeTransformed(resourceName: string) { + return stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); +} 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 new file mode 100644 index 0000000000..c155b40cf9 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts @@ -0,0 +1,250 @@ +import { + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + CLIInputSchemaValidator, + isResourceNameUnique, + JSONUtilities, + PathConstants, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import { join } from 'path'; +import { ApigwInputs, ApigwStackTransform, CrudOperation, Path, PermissionSetting } from './cdk-stack-builder'; +import { ApigwWalkthroughReturnPromise } from './service-walkthrough-types/apigw-types'; + +export class ApigwInputState { + private static instance: ApigwInputState; + projectRootPath: string; + resourceName: string; + paths: { [pathName: string]: Path }; + + private constructor(private readonly context: $TSContext, resourceName?: string) { + this.projectRootPath = pathManager.findProjectRoot(); + this.resourceName = resourceName; + ApigwInputState.instance = this; + } + + public static getInstance(context: $TSContext, resourceName?: string) { + if (!ApigwInputState.instance) { + new ApigwInputState(context, resourceName); + } + return ApigwInputState.instance; + } + + 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, + }; + + await 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(); + + await this.context.amplify.updateamplifyMetaAfterResourceUpdate( + AmplifyCategories.API, + adminQueriesProps.apiName, + 'dependsOn', + adminQueriesProps.dependsOn, + ); + }; + + public addApigwResource = async (serviceWalkthroughPromise: ApigwWalkthroughReturnPromise, options: $TSObject) => { + 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<$TSObject>) => { + const { answers } = await updateWalkthroughPromise; + + this.resourceName = answers.resourceName; + this.paths = answers.paths; + + // this.addPolicyResourceNameToPaths(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.confirmContinue(`Migration for ${this.resourceName} is required. Continue?`))) { + return; + } + const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); + + this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + this.context.filesystem.remove(join(resourceDirPath, 'admin-queries-cloudformation-template.json')); + + return this.updateAdminQueriesResource(adminQueriesProps); + }; + + public migrateApigwResource = async (resourceName: string) => { + this.resourceName = this.resourceName ?? resourceName; + if (!(await prompter.confirmContinue(`Migration for ${this.resourceName} is required. Continue?`))) { + return; + } + const deprecatedParametersFileName = 'api-params.json'; + console.log('DEBUG', this.projectRootPath, AmplifyCategories.API, this.resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); + const deprecatedParametersFilePath = join(resourceDirPath, deprecatedParametersFileName); + let deprecatedParameters: $TSObject; + try { + deprecatedParameters = JSONUtilities.readJson<$TSObject>(deprecatedParametersFilePath); + } catch (e) { + printer.error(`Error reading ${deprecatedParametersFileName} file for ${this.resourceName} resource`); + throw e; + } + + this.paths = {}; + + function convertDeprecatedPermissionToCRUD(deprecatedPrivacy: string) { + let privacyList: string[]; + if (deprecatedPrivacy === 'r') { + privacyList = [CrudOperation.READ]; + } else if (deprecatedPrivacy === 'rw') { + privacyList = [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE]; + } + return privacyList; + } + + deprecatedParameters.paths.forEach((path: $TSObject) => { + let pathPermissionSetting = + path.privacy.open === true + ? PermissionSetting.OPEN + : path.privacy.private === true + ? PermissionSetting.PRIVATE + : PermissionSetting.PROTECTED; + + let auth; + let guest; + // convert deprecated permissions to CRUD structure + if (path.privacy.auth && ['r', 'rw'].includes(path.privacy.auth)) { + auth = convertDeprecatedPermissionToCRUD(path.privacy.auth); + } + if (path.privacy.unauth && ['r', 'rw'].includes(path.privacy.unauth)) { + auth = convertDeprecatedPermissionToCRUD(path.privacy.unauth); + } + + this.paths[path.name] = { + permissions: { + setting: pathPermissionSetting, + auth, + guest, + }, + lambdaFunction: path.lambdaFunction, + }; + }); + + await this.createApigwArtifacts(); + + this.context.filesystem.remove(deprecatedParametersFilePath); + this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + this.context.filesystem.remove(join(resourceDirPath, PathConstants.CfnFileName(this.resourceName))); + }; + + public cliInputsFileExists() { + return stateManager.resourceInputsJsonExists(this.projectRootPath, AmplifyCategories.API, this.resourceName); + } + + public getCliInputPayload() { + return stateManager.getResourceInputsJson(this.projectRootPath, AmplifyCategories.API, this.resourceName); + } + + public isCLIInputsValid(cliInputs?: ApigwInputs) { + if (!cliInputs) { + cliInputs = this.getCliInputPayload(); + } + + const schemaValidator = new CLIInputSchemaValidator(AmplifySupportedService.APIGW, AmplifyCategories.API, 'APIGatewayCLIInputs'); + 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); + await stack.transform(); + } + + convertCrudOperationsToPermissions(crudOps: CrudOperation[]) { + const output = []; + for (const op of crudOps) { + switch (op) { + case CrudOperation.CREATE: + output.push('/POST'); + break; + case CrudOperation.READ: + output.push('/GET'); + break; + case CrudOperation.UPDATE: + output.push('/PUT'); + output.push('/PATCH'); + break; + case CrudOperation.DELETE: + output.push('/DELETE'); + break; + } + } + return output; + } +} + +type AdminQueriesProps = { + apiName: string; + functionName: string; + authResourceName: string; + dependsOn: $TSObject[]; +}; 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 index 824a2cafef..418b53b47f 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts @@ -1,8 +1,8 @@ -import path from 'path'; +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')); +export const rootAssetDir = path.resolve(path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation')); 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 new file mode 100644 index 0000000000..2d42d8cb4b --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts @@ -0,0 +1,402 @@ +import * as apigw from '@aws-cdk/aws-apigateway'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { $TSObject, JSONUtilities } from 'amplify-cli-core'; +import { AmplifyApigwResourceTemplate, ApigwInputs, ApigwPathPolicy } 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 { + _scope: cdk.Construct; + restApi!: apigw.CfnRestApi; + deploymentResource: apigw.CfnDeployment; + _lambdaPermission: lambda.CfnPermission; + _props: ApigwInputs; + paths: $TSObject; + policies: { [pathName: string]: ApigwPathPolicy }; + _cfnParameterMap: Map = new Map(); + + constructor(scope: cdk.Construct, id: string, props: ApigwInputs) { + super(scope, id, undefined); + this._scope = scope; + this._props = props; + this.paths = {}; + this.templateOptions.templateFormatVersion = CFN_TEMPLATE_FORMAT_VERSION; + this.templateOptions.description = ROOT_CFN_DESCRIPTION; + } + + /** + * + * @param props + * @param logicalId + */ + addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void { + new cdk.CfnOutput(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void { + new cdk.CfnMapping(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void { + new cdk.CfnCondition(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void { + new cdk.CfnResource(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addLambdaPermissionCfnResource(props: lambda.CfnPermissionProps, logicalId: string): void { + new lambda.CfnPermission(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnParameter(props: cdk.CfnParameterProps, logicalId: string): void { + if (this._cfnParameterMap.has(logicalId)) { + throw new Error('logical id already exists'); + } + this._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); + } + + renderCloudFormationTemplate = (): string => { + return JSONUtilities.stringify(this._toCloudFormation()); + }; + + generateAdminQueriesStack = (resourceName: string, authResourceName: string) => { + this._constructCfnPaths(resourceName); + + this.restApi = new apigw.CfnRestApi(this, resourceName, { + description: '', // TODO - left blank in current CLI + 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: '', // TODO - left blank in current CLI + 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', + }, + }, + }, + }); + + this._setDeploymentResource(resourceName); + }; + + private _constructCfnPaths(resourceName: string) { + for (const [pathName, path] of Object.entries(this._props.paths)) { + let lambdaPermissionLogicalId: string; + if (resourceName === 'AdminQueries') { + this.paths[`/{proxy+}`] = getAdminQueriesPathObject(path.lambdaFunction); + lambdaPermissionLogicalId = 'AdminQueriesAPIGWPolicyForLambda'; + } else { + this.paths[pathName] = getDefaultPathObject(path.lambdaFunction); + this.paths[`${pathName}/{proxy+}`] = getDefaultPathObject(path.lambdaFunction); + lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; + } + + this.addLambdaPermissionCfnResource( + { + 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 = (resourceName: string) => { + this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}`, { + restApiId: cdk.Fn.ref(resourceName), + stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), + }); + }; +} + +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 getDefaultPathObject = (lambdaFunctionName: string) => ({ + 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${lambdaFunctionName}Arn`), + '/invocations', + ]), + passthroughBehavior: 'when_no_match', + httpMethod: 'POST', + type: 'aws_proxy', + }, + }, +}); + +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 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 new file mode 100644 index 0000000000..75f7794429 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts @@ -0,0 +1,197 @@ +import * as cdk from '@aws-cdk/core'; +import { + $TSAny, + $TSContext, + AmplifyCategories, + buildOverrideDir, + getAmplifyResourceByCategories, + JSONUtilities, + PathConstants, + pathManager, + stateManager, + Template, + writeCFNTemplate, +} from 'amplify-cli-core'; +import { formatter, printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { AmplifyApigwResourceStack, ApigwInputs } from '.'; +import { category } from '../../../category-constants'; +import { ApigwInputState } from '../apigw-input-state'; + +export class ApigwStackTransform { + _app: cdk.App; + cliInputs: ApigwInputs; + resourceTemplateObj: AmplifyApigwResourceStack | undefined; + cliInputsState: ApigwInputState; + cfn!: Template; + cfnInputParams!: {}; + resourceName: string; + + constructor(context: $TSContext, resourceName: string) { + this._app = new cdk.App(); + this.resourceName = resourceName; + + // Validate the cli-inputs.json for the resource + this.cliInputsState = ApigwInputState.getInstance(context, this.resourceName); + this.cliInputs = this.cliInputsState.getCliInputPayload(); + this.cliInputsState.isCLIInputsValid(); + } + + async transform() { + let authResourceName: string; + if (this.resourceName === 'AdminQueries') { + [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter(resourceName => resourceName !== 'UserPoolGroups'); + } + + // Generate cloudformation stack from cli-inputs.json + this.generateStack(authResourceName); + + // Generate cloudformation stack input params from cli-inputs.json + this.generateCfnInputParameters(); + + // Modify cloudformation files based on overrides + await this.applyOverrides(); + + // Save generated cloudformation.json and parameters.json files + await this.saveBuildFiles(); + } + + // TODO generate params + generateCfnInputParameters() { + this.cfnInputParams = {}; + } + + generateStack(authResourceName?: string) { + this.resourceTemplateObj = new AmplifyApigwResourceStack(this._app, 'AmplifyApigwResourceStack', this.cliInputs); + + if (authResourceName) { + this.resourceTemplateObj.addCfnParameter( + { + type: 'String', + default: `auth${authResourceName}UserPoolId`, + }, + `auth${authResourceName}UserPoolId`, + ); + } + + // Add Parameters + for (const path of Object.values(this.cliInputs.paths)) { + 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://', + 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 === 'AdminQueries' + ? this.resourceTemplateObj.generateAdminQueriesStack(this.resourceName, authResourceName) + : this.resourceTemplateObj.generateStackResources(this.resourceName); + } + + async applyOverrides() { + const backendDir = pathManager.getBackendDirPath(); + const overrideFilePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); + + const isBuild = await buildOverrideDir(backendDir, overrideFilePath).catch(error => { + printer.debug(`Skipping build as ${error.message}`); + return false; + }); + // skip if packageManager or override.ts not found + if (isBuild) { + const { overrideProps } = await import(path.join(overrideFilePath, 'build', 'override.js')).catch(error => { + formatter.list(['No override file found', `To override ${this.resourceName} run "amplify override api"`]); + return undefined; + }); + + // TODO: Check Script Options + if (overrideProps && typeof overrideProps === 'function') { + try { + this.resourceTemplateObj = overrideProps(this.resourceTemplateObj); + + // The vm module enables compiling and running code within V8 Virtual Machine contexts. + // The vm module is not a security mechanism. Do not use it to run untrusted code. + // const script = new vm.Script(overrideCode); + // script.runInContext(vm.createContext(cognitoStackTemplateObj)); + return; + } catch (error: $TSAny) { + throw new Error(error); + } + } + } + } + + async saveBuildFiles() { + if (this.resourceTemplateObj) { + this.cfn = JSONUtilities.parse(this.resourceTemplateObj.renderCloudFormationTemplate()); + } + + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, 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); + } +} 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 new file mode 100644 index 0000000000..7b96c26fd5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000000..2d01ec4b3f --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts @@ -0,0 +1,53 @@ +import * as cdk from '@aws-cdk/core'; +import * as apigwCdk from '@aws-cdk/aws-apigateway'; +import * as iamCdk from '@aws-cdk/aws-iam'; + +export type ApigwInputs = { + version: number; + paths: 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): 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 index f06fc27941..3b5ed5d8c8 100644 --- 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 @@ -1,4 +1,4 @@ -import { isResourceNameUnique } from 'amplify-cli-core'; +import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, @@ -6,11 +6,12 @@ import { ResolutionStrategy, UpdateApiRequest, } from 'amplify-headless-interface'; +import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; import _ from 'lodash'; import * as path from 'path'; -import uuid from 'uuid'; +import { v4 as uuid } from 'uuid'; import { category } from '../../category-constants'; import { ApiArtifactHandler, ApiArtifactHandlerOptions } from '../api-artifact-handler'; import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants'; @@ -22,7 +23,7 @@ import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-c // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; -export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { +export const getCfnApiArtifactHandler = (context: $TSContext): ApiArtifactHandler => { return new CfnApiArtifactHandler(context); }; const resolversDirName = 'resolvers'; @@ -35,16 +36,17 @@ const defaultCfnParameters = (apiName: string) => ({ DynamoDBEnableServerSideEncryption: false, }); class CfnApiArtifactHandler implements ApiArtifactHandler { - private readonly context: any; + private readonly context: $TSContext; - constructor(context) { + 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 existingApiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + const meta = stateManager.getMeta(); + const existingApiName = getAppSyncResourceName(meta); if (existingApiName) { throw new Error(`GraphQL API ${existingApiName} already exists in the project. Use 'amplify update api' to make modifications.`); } @@ -98,7 +100,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { // for each service and delegate to the correct one updateArtifacts = async (request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise => { const updates = request.serviceModification; - const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + const apiName = getAppSyncResourceName(stateManager.getMeta()); if (!apiName) { throw new Error(`No AppSync API configured in the project. Use 'amplify add api' to create an API.`); } @@ -110,7 +112,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); await writeResolverConfig(updates.conflictResolution, resourceDir); } - const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); + const authConfig = getAppSyncAuthConfig(stateManager.getMeta()); const oldConfigHadApiKey = authConfigHasApiKey(authConfig); if (updates.defaultAuthType) { authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); @@ -129,14 +131,14 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - printApiKeyWarnings(this.context, oldConfigHadApiKey, authConfigHasApiKey(authConfig)); + printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; private writeSchema = (resourceDir: string, schema: string) => { fs.writeFileSync(path.join(resourceDir, gqlSchemaFilename), schema); }; - private getResourceDir = (apiName: string) => path.join(this.context.amplify.pathManager.getBackendDirPath(), category, apiName); + private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); private createAmplifyMeta = authConfig => ({ service: 'AppSync', @@ -180,8 +182,8 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private getCfnParameters = (apiName: string, authConfig, resourceDir: string) => { - const params = - this.context.amplify.readJsonFile(path.join(resourceDir, cfnParametersFilename), undefined, false) || defaultCfnParameters(apiName); + const cfnPath = path.join(resourceDir, cfnParametersFilename); + const params = JSONUtilities.readJson<$TSAny>(cfnPath, { throwIfNotExist: false }) || defaultCfnParameters(apiName); const cognitoPool = this.getCognitoUserPool(authConfig); if (cognitoPool) { params.AuthCognitoUserPoolId = cognitoPool; @@ -198,7 +200,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const defaultAuth = authConfig.defaultAuthentication || {}; if (defaultAuth.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { let userPoolId; - const configuredUserPoolName = checkIfAuthExists(this.context); + const configuredUserPoolName = checkIfAuthExists(); if (authConfig.userPoolConfig) { ({ userPoolId } = authConfig.userPoolConfig); @@ -217,7 +219,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private createSyncFunction = async () => { - const targetDir = this.context.amplify.pathManager.getBackendDirPath(); + const targetDir = pathManager.getBackendDirPath(); const assetDir = path.normalize(path.join(rootAssetDir, 'sync-conflict-handler')); const [shortId] = uuid().split('-'); @@ -232,17 +234,17 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { { dir: assetDir, template: 'sync-conflict-handler-index.js.ejs', - target: `${targetDir}/function/${functionName}/src/index.js`, + target: path.join(targetDir, 'function', functionName, 'src', 'index.js'), }, { dir: assetDir, template: 'sync-conflict-handler-package.json.ejs', - target: `${targetDir}/function/${functionName}/src/package.json`, + target: path.join(targetDir, 'function', functionName, 'src', 'package.json'), }, { dir: assetDir, template: 'sync-conflict-handler-template.json.ejs', - target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + target: path.join(targetDir, 'function', functionName, `${functionName}-cloudformation-template.json`), }, ]; @@ -256,7 +258,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - this.context.print.success(`Successfully added ${functionName} function locally`); + printer.success(`Successfully added ${functionName} function locally`); return functionName + '-${env}'; }; @@ -268,7 +270,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { * * write to the transformer conf if the resolverConfig is valid */ -export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir) => { +export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir: string) => { const localTransformerConfig = await readTransformerConfiguration(resourceDir); localTransformerConfig.ResolverConfig = conflictResolutionToResolverConfig(conflictResolution); await writeTransformerConfiguration(resourceDir, localTransformerConfig); 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 index 0a402bd123..1bc866ab6c 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts @@ -1,22 +1,22 @@ -import fs from 'fs-extra'; -import path from 'path'; -import uuid from 'uuid'; +import { $TSContext, createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +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'; -import { createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; export const addResource = async ( serviceWalkthroughPromise: Promise, - context, - category, + context: $TSContext, + category: string, service, options, apiType: API_TYPE, ) => { - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const walkthroughOptions = await serviceWalkthroughPromise; const { @@ -31,7 +31,7 @@ export const addResource = async ( dependsOn = [], mutableParametersState, } = walkthroughOptions; - const resourceDirPath = path.join(projectBackendDirPath, category, resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); let [authName, updatedDependsOn] = await getResourceDependencies({ dependsOn, restrictAccess, category, resourceName, context }); @@ -88,36 +88,37 @@ export const addResource = async ( if (imageSource.type === IMAGE_SOURCE_TYPE.TEMPLATE) { fs.copySync( - path.join(__dirname, '../../../resources/awscloudformation/container-templates', imageSource.template), + path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation/container-templates', imageSource.template), path.join(resourceDirPath, 'src'), - { recursive: true } + { 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); - context.print.success(`Successfully added resource ${resourceName} locally.`); - context.print.info(''); - context.print.success('Next steps:'); + printer.success(`Successfully added resource ${resourceName} locally.`); + printer.info(''); + printer.success('Next steps:'); if (deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED) { - context.print.info(`- Place your Dockerfile, docker-compose.yml and any related container source files in "amplify/backend/api/${resourceName}/src"`); + 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) { - context.print.info( + printer.info( `- Ensure you have the Dockerfile, docker-compose.yml and any related container source files in your Github path: ${gitHubInfo.path}`, ); } - context.print.info( + printer.info( `- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers`, ); - context.print.info(`- To access AWS resources outside of this Amplify app, edit the ${customPoliciesPath}`); - context.print.info('- Run "amplify push" to build and deploy your image'); + 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; }; @@ -131,7 +132,7 @@ const getResourceDependencies = async ({ }: { restrictAccess: boolean; dependsOn: ResourceDependency[]; - context: any; + context: $TSContext; category: string; resourceName: string; }) => { @@ -165,7 +166,7 @@ const getResourceDependencies = async ({ apiRequirements, ]); } catch (e) { - context.print.error(e); + printer.error(e); throw e; } } else { @@ -192,7 +193,7 @@ const getResourceDependencies = async ({ return [authName, updatedDependsOn]; }; -export const updateResource = async (serviceWalkthroughPromise: Promise, context, category) => { +export const updateResource = async (serviceWalkthroughPromise: Promise, context: $TSContext, category: string) => { const options = await serviceWalkthroughPromise; const { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts similarity index 68% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts index 7ab876f8fa..60dbcd9da4 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts @@ -1,6 +1,6 @@ -const uuid = require('uuid'); +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +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 = { @@ -11,7 +11,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts similarity index 71% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts index 0d5cb71570..8c48966c22 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts @@ -1,6 +1,7 @@ -const uuid = require('uuid'); +import { $TSMeta } from 'amplify-cli-core'; +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +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('-'); @@ -16,7 +17,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; 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 index da44caf946..0f77dee83e 100644 --- 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 @@ -1,6 +1,6 @@ -const uuid = require('uuid'); +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +export const getAllDefaults = () => { const [shortId] = uuid().split('-'); const defaults = { resourceName: `container${shortId}`, @@ -8,7 +8,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; 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 index 39f92df12e..a66729ca10 100644 --- 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 @@ -1,3 +1 @@ -import { getContainers } from "./converter"; - -export { getContainers }; \ No newline at end of file +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 index c66f371960..01ca720b38 100644 --- 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 @@ -7,8 +7,8 @@ import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; import * as route53targets from '@aws-cdk/aws-route53-targets'; import * as cdk from '@aws-cdk/core'; -import { ContainersStack, ContainersStackProps } from './base-api-stack'; import { v4 as uuid } from 'uuid'; +import { ContainersStack, ContainersStackProps } from './base-api-stack'; type EcsStackProps = ContainersStackProps & Readonly<{ diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index 4ee7ce6fee..f4563957d0 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -1,28 +1,52 @@ -import { serviceWalkthroughResultToAddApiRequest } from './utils/service-walkthrough-result-to-add-api-request'; -import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; -import { serviceMetadataFor, getServiceWalkthrough, datasourceMetadataFor } from './utils/dynamic-imports'; -import { legacyAddResource } from './legacy-add-resource'; -import { legacyUpdateResource } from './legacy-update-resource'; +import { $TSAny, $TSContext, $TSObject, AmplifySupportedService, exitOnNextTick, NotImplementedError } from 'amplify-cli-core'; import { UpdateApiRequest } from 'amplify-headless-interface'; -import { editSchemaFlow } from './utils/edit-schema-flow'; -import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; -import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; +import { printer } from 'amplify-prompts'; import inquirer from 'inquirer'; +import * as path from 'path'; +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, - ServiceConfiguration, getPermissionPolicies as getContainerPermissionPolicies, + ServiceConfiguration, } from './service-walkthroughs/containers-walkthrough'; -import { category } from '../../category-constants'; +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: $TSObject[] }, +) { + const apigwInputState = ApigwInputState.getInstance(context, apiProps.apiName); + return apigwInputState.addAdminQueriesResource(apiProps); +} + +export async function updateAdminQueriesApi( + context: $TSContext, + apiProps: { apiName: string; functionName: string; authResourceName: string; dependsOn: $TSObject[] }, +) { + const apigwInputState = ApigwInputState.getInstance(context, apiProps.apiName); + // Check for migration + + if (!apigwInputState.cliInputsFileExists()) { + await apigwInputState.migrateAdminQueries(apiProps); + } else { + return apigwInputState.addAdminQueriesResource(apiProps); + } +} -export async function console(context, service) { +export async function console(context: $TSContext, service: string) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { openConsole } = require(serviceWalkthroughSrc); + 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'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -30,24 +54,23 @@ export async function console(context, service) { return openConsole(context); } -async function addContainerResource(context, category, service, options, apiType) { +async function addContainerResource(context: $TSContext, service: string, options, apiType: API_TYPE) { const serviceWalkthroughFilename = 'containers-walkthrough.js'; - const defaultValuesFilename = 'containers-defaults.js'; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, apiType); + const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, apiType); return await addContainer(serviceWalkthroughPromise, context, category, service, options, apiType); } -async function addNonContainerResource(context, category, service, options) { +async function addNonContainerResource(context: $TSContext, service: string, options) { const serviceMetadata = await serviceMetadataFor(service); - const { serviceWalkthroughFilename, defaultValuesFilename } = serviceMetadata; + const { serviceWalkthroughFilename } = serviceMetadata; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); + const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, serviceMetadata); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: const walkthroughResult = await serviceWalkthroughPromise; const askToEdit = walkthroughResult.askToEdit; const apiName = await getCfnApiArtifactHandler(context).createArtifacts(serviceWalkthroughResultToAddApiRequest(walkthroughResult)); @@ -55,23 +78,26 @@ async function addNonContainerResource(context, category, service, options) { await editSchemaFlow(context, apiName); } return apiName; + case AmplifySupportedService.APIGW: + const apigwInputState = ApigwInputState.getInstance(context); + return apigwInputState.addApigwResource(serviceWalkthroughPromise, options); default: return legacyAddResource(serviceWalkthroughPromise, context, category, service, options); } } -export async function addResource(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 'AppSync': - useContainerResource = await isGraphQLContainer(context); + case AmplifySupportedService.APPSYNC: + useContainerResource = await isGraphQLContainer(); apiType = API_TYPE.GRAPHQL; break; - case 'API Gateway': - useContainerResource = await isRestContainer(context); + case AmplifySupportedService.APIGW: + useContainerResource = await isRestContainer(); apiType = API_TYPE.REST; break; default: @@ -80,11 +106,11 @@ export async function addResource(context, category, service, options) { } return useContainerResource - ? addContainerResource(context, category, service, options, apiType) - : addNonContainerResource(context, category, service, options); + ? addContainerResource(context, service, options, apiType) + : addNonContainerResource(context, service, options); } -function isContainersEnabled(context) { +function isContainersEnabled(context: $TSContext) { const { frontend } = context.amplify.getProjectConfig(); if (frontend) { const { config: { ServerlessContainers = false } = {} } = context.amplify.getProjectConfig()[frontend] || {}; @@ -95,14 +121,14 @@ function isContainersEnabled(context) { return false; } -async function isGraphQLContainer(context): Promise { +async function isGraphQLContainer(): Promise { const { graphqlSelection } = await inquirer.prompt({ name: 'graphqlSelection', message: 'Which service would you like to use', type: 'list', choices: [ { - name: 'AppSync', + name: AmplifySupportedService.APPSYNC, value: false, }, { @@ -115,7 +141,7 @@ async function isGraphQLContainer(context): Promise { return graphqlSelection; } -async function isRestContainer(context) { +async function isRestContainer() { const { restSelection } = await inquirer.prompt({ name: 'restSelection', message: 'Which service would you like to use', @@ -135,22 +161,18 @@ async function isRestContainer(context) { return restSelection; } -export async function updateResource(context, category, service, options) { +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); + const { hasAPIGatewayContainerResource, hasAPIGatewayLambdaResource, hasGraphQLAppSyncResource, hasGraphqlContainerResource } = + await describeApiResourcesBySubCategory(context); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: if (hasGraphQLAppSyncResource && hasGraphqlContainerResource) { - useContainerResource = await isGraphQLContainer(context); + useContainerResource = await isGraphQLContainer(); } else if (hasGraphqlContainerResource) { useContainerResource = true; } else { @@ -158,9 +180,9 @@ export async function updateResource(context, category, service, options) { } apiType = API_TYPE.GRAPHQL; break; - case 'API Gateway': + case AmplifySupportedService.APIGW: if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { - useContainerResource = await isRestContainer(context); + useContainerResource = await isRestContainer(); } else if (hasAPIGatewayContainerResource) { useContainerResource = true; } else { @@ -173,12 +195,10 @@ export async function updateResource(context, category, service, options) { } } - return useContainerResource - ? updateContainerResource(context, category, service, apiType) - : updateNonContainerResource(context, category, service); + return useContainerResource ? updateContainerResource(context, category, service, apiType) : updateNonContainerResource(context, service); } -async function describeApiResourcesBySubCategory(context) { +async function describeApiResourcesBySubCategory(context: $TSContext) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources.filter(resource => resource.category === category && resource.mobileHubMigrated !== true); @@ -191,9 +211,9 @@ async function describeApiResourcesBySubCategory(context) { hasAPIGatewayContainerResource = hasAPIGatewayContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); - hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === 'API Gateway'; + hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === AmplifySupportedService.APIGW; - hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === 'AppSync'; + hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === AmplifySupportedService.APPSYNC; hasGraphqlContainerResource = hasGraphqlContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); @@ -207,33 +227,32 @@ async function describeApiResourcesBySubCategory(context) { }; } -async function updateContainerResource(context, category, service, apiType: API_TYPE) { +async function updateContainerResource(context: $TSContext, category: string, service: string, apiType: API_TYPE) { const serviceWalkthroughFilename = 'containers-walkthrough'; - const defaultValuesFilename = 'containers-defaults.js'; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { updateWalkthrough } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { updateWalkthrough } = await import(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } - const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, apiType); + const updateWalkthroughPromise: Promise = updateWalkthrough(context, apiType); updateContainer(updateWalkthroughPromise, context, category); } -async function updateNonContainerResource(context, category, service) { +async function updateNonContainerResource(context: $TSContext, service: string) { const serviceMetadata = await serviceMetadataFor(service); const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { updateWalkthrough } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { updateWalkthrough } = await import(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -241,14 +260,15 @@ async function updateNonContainerResource(context, category, service) { const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); default: - return legacyUpdateResource(updateWalkthroughPromise, context, category, service); + const apigwInputState = ApigwInputState.getInstance(context); + return apigwInputState.updateApigwResource(updateWalkthroughPromise); } } -export async function migrateResource(context, projectPath, service, resourceName) { +export async function migrateResource(context: $TSContext, projectPath: string, service: string, resourceName: string) { if (service === 'ElasticContainer') { return migrateResourceContainer(context, projectPath, service, resourceName); } else { @@ -256,53 +276,53 @@ export async function migrateResource(context, projectPath, service, resourceNam } } -async function migrateResourceContainer(context, projectPath, service, resourceName) { - context.print.info(`No migration required for ${resourceName}`); +async function migrateResourceContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { + printer.info(`No migration required for ${resourceName}`); return; } -async function migrateResourceNonContainer(context, projectPath, service, resourceName) { +async function migrateResourceNonContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { migrate } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { migrate } = await import(serviceWalkthroughSrc); if (!migrate) { - context.print.info(`No migration required for ${resourceName}`); + printer.info(`No migration required for ${resourceName}`); return; } return await migrate(context, projectPath, resourceName); } -export async function addDatasource(context, category, datasource) { +export async function addDatasource(context: $TSContext, category, datasource) { const serviceMetadata = await datasourceMetadataFor(datasource); - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, defaultValuesFilename, serviceMetadata); + const { serviceWalkthroughFilename } = serviceMetadata; + return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, serviceMetadata); } -export async function getPermissionPolicies(context, service, resourceName, crudOptions) { +export async function getPermissionPolicies(context: $TSContext, service: string, resourceName: string, crudOptions) { if (service === 'ElasticContainer') { return getPermissionPoliciesContainer(context, service, resourceName, crudOptions); } else { - return getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions); + return getPermissionPoliciesNonContainer(service, resourceName, crudOptions); } } -async function getPermissionPoliciesContainer(context, service, resourceName, crudOptions) { +async function getPermissionPoliciesContainer(context: $TSContext, service: string, resourceName: string, crudOptions) { return getContainerPermissionPolicies(context, service, resourceName, crudOptions); } -async function getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions) { +async function getPermissionPoliciesNonContainer(service: string, resourceName: string, crudOptions: string[]) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { getIAMPolicies } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { getIAMPolicies } = await import(serviceWalkthroughSrc); if (!getIAMPolicies) { - context.print.info(`No policies found for ${resourceName}`); + printer.info(`No policies found for ${resourceName}`); return; } - return getIAMPolicies(resourceName, crudOptions, context); + 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 index ff7e33a189..29ced6ba3b 100644 --- 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 @@ -1,4 +1,4 @@ -import { isResourceNameUnique, JSONUtilities } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, isResourceNameUnique, JSONUtilities, pathManager } from 'amplify-cli-core'; import * as fs from 'fs-extra'; import * as path from 'path'; import { cfnParametersFilename, parametersFileName, rootAssetDir } from './aws-constants'; @@ -6,10 +6,15 @@ 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, category, service, options) => { +export const legacyAddResource = async ( + serviceWalkthroughPromise: Promise<$TSAny>, + context: $TSContext, + category: string, + service: string, + options: $TSObject, +) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await serviceWalkthroughPromise; @@ -30,7 +35,7 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; - const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); isResourceNameUnique(category, parameters.resourceName); @@ -47,15 +52,14 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, }; // exported because the update flow still uses this method directly for now -export const copyCfnTemplate = (context, category, options, cfnFilename) => { - const { amplify } = context; - const targetDir = amplify.pathManager.getBackendDirPath(); +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: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, + target: path.join(resourceDirPath, `${options.resourceName}-cloudformation-template.json`), }, ]; 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 index 99a15a9365..930523a24a 100644 --- 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 @@ -1,15 +1,15 @@ -import { serviceMetadataFor } from './utils/dynamic-imports'; -import { copyCfnTemplate, addPolicyResourceNameToPaths } from './legacy-add-resource'; -import fs from 'fs-extra'; -import path from 'path'; +import { $TSAny, $TSContext, JSONUtilities, pathManager } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; +import * as path from 'path'; 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, category, service) => { +export const legacyUpdateResource = async (updateWalkthroughPromise: Promise<$TSAny>, context: $TSContext, category: string, service) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await updateWalkthroughPromise; - const options: any = {}; + const options: $TSAny = {}; if (result) { if (result.answers) { ({ answers } = result); @@ -25,11 +25,10 @@ export const legacyUpdateResource = async (updateWalkthroughPromise: Promise; + +export type ApigwAnswers = { + paths: { [pathName: string]: ApigwPath }; + resourceName: string; + functionArns?: string[]; + dependsOn?: $TSObject[]; +}; 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 index ac3390df3e..38f61d5289 100644 --- 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 @@ -1,113 +1,95 @@ -import { $TSContext, exitOnNextTick, isResourceNameUnique, open, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; -import * as fs from 'fs-extra'; +import { + $TSAny, + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + exitOnNextTick, + isResourceNameUnique, + open, + pathManager, + ResourceDoesNotExistError, + stateManager, +} from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; import inquirer from 'inquirer'; import os from 'os'; -import * as path from 'path'; -import uuid from 'uuid'; -import { rootAssetDir } from '../aws-constants'; +import { v4 as uuid } from 'uuid'; +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'; -// keep in sync with ServiceName in amplify-category-function, but probably it will not change -const FunctionServiceNameLambdaFunction = 'Lambda'; - -const category = 'api'; -const serviceName = 'API Gateway'; +const category = AmplifyCategories.API; +const serviceName = AmplifySupportedService.APIGW; const elasticContainerServiceName = 'ElasticContainer'; -const parametersFileName = 'api-params.json'; -const cfnParametersFilename = 'parameters.json'; - -export async function serviceWalkthrough(context, defaultValuesFilename) { - const { amplify } = context; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - let answers = { - paths: [], - }; +export async function serviceWalkthrough(context: $TSContext): ApigwWalkthroughReturnPromise { + const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); - const apiNames = await askApiNames(context, allDefaultValues); - answers = { ...answers, ...apiNames }; + const resourceName = await askApiName(context, allDefaultValues.resourceName); + const answers = { paths: {}, resourceName, dependsOn: undefined }; return pathFlow(context, answers); } -export async function updateWalkthrough(context, defaultValuesFilename) { - const { amplify } = context; +export async function updateWalkthrough(context: $TSContext) { const { allResources } = await context.amplify.getResourceStatus(); - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); const resources = allResources .filter(resource => resource.service === serviceName && resource.mobileHubMigrated !== true) .map(resource => resource.resourceName); - // There can only be one appsync resource if (resources.length === 0) { - const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; - context.print.error(errMessage); + 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 = { + let answers: $TSAny = { paths: [], }; - const question = [ - { - name: 'resourceName', - message: 'Please select the REST API you would want to update', - type: 'list', - choices: resources, - }, - { - name: 'operation', - message: 'What would you like to do', - type: 'list', - when: context.input.command !== 'add', - choices: [ - { name: 'Add another path', value: 'add' }, - { name: 'Update path', value: 'update' }, - { name: 'Remove path', value: 'remove' }, - ], - }, - ]; - - const updateApi = await inquirer.prompt(question); + 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') { - updateApi.operation = 'add'; + updateApiOperation = 'add'; } - if (updateApi.resourceName === 'AdminQueries') { + if (selectedApiName === 'AdminQueries') { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; - context.print.warning(errMessage); + printer.warn(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - const resourceDirPath = path.join(projectBackendDirPath, category, updateApi.resourceName as string); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let parameters; - try { - parameters = context.amplify.readJsonFile(parametersFilePath); - } catch (e) { - parameters = {}; + const projRoot = pathManager.findProjectRoot(); + if (!stateManager.resourceInputsJsonExists(projRoot, category, selectedApiName)) { + // Not yet migrated + console.log(selectedApiName); + await migrate(context, projRoot, selectedApiName); } - parameters.resourceName = updateApi.resourceName; + + const parameters = stateManager.getResourceInputsJson(projRoot, category, selectedApiName); + parameters.resourceName = selectedApiName; Object.assign(allDefaultValues, parameters); answers = { ...answers, ...parameters }; [answers.uuid] = uuid().split('-'); - const pathList = answers.paths.map(path => path.name); + const pathNames = Object.keys(answers.paths); let updatedResult = {}; - switch (updateApi.operation) { + switch (updateApiOperation) { case 'add': { updatedResult = pathFlow(context, answers); break; @@ -115,76 +97,52 @@ export async function updateWalkthrough(context, defaultValuesFilename) { case 'remove': { const pathToRemove = await inquirer.prompt({ name: 'path', - message: 'Please select the path you would want to remove', + message: 'Select the path you would want to remove', type: 'list', - choices: pathList, + choices: pathNames, }); - answers.paths = answers.paths.filter(path => path.name !== pathToRemove.path); + delete answers.paths[pathToRemove.path]; - const { dependsOn, functionArns } = await findDependsOn(answers.paths, context); + const { dependsOn, functionArns } = await findDependsOn(answers.paths); answers.dependsOn = dependsOn; answers.functionArns = functionArns; - updatedResult = { answers, dependsOn }; + updatedResult = { answers }; break; } case 'update': { const pathToEdit = await inquirer.prompt({ - name: 'path', - message: 'Please select the path you would want to edit', + name: 'pathName', + message: 'Select the path you would want to edit', type: 'list', - choices: pathList, + choices: pathNames, }); // removing path from paths list - const currentPath = answers.paths.find(path => path.name === pathToEdit.path); - answers.paths = answers.paths.filter(path => path.name !== pathToEdit.path); + const currentPath: ApigwPath = answers.paths[pathToEdit.pathName]; + delete answers.paths[pathToEdit.pathName]; updatedResult = pathFlow(context, answers, currentPath); break; } default: { - updatedResult = {}; + throw new Error(`Unrecognized API update operation "${updateApiOperation}"`); } } return updatedResult; } -async function pathFlow(context, answers, currentPath?) { +async function pathFlow(context: $TSContext, answers: ApigwAnswers, currentPath?: ApigwPath): ApigwWalkthroughReturnPromise { const pathsAnswer = await askPaths(context, answers, currentPath); - answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; - const { dependsOn } = pathsAnswer; - const privacy = { - auth: pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length, - unauth: pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length, - }; - - answers = { ...answers, privacy, dependsOn }; - - if ( - context.amplify.getProjectDetails() && - context.amplify.getProjectDetails().amplifyMeta && - context.amplify.getProjectDetails().amplifyMeta.providers && - context.amplify.getProjectDetails().amplifyMeta.providers.awscloudformation - ) { - // TODO: read from utility functions (Dustin PR) - const { amplifyMeta } = context.amplify.getProjectDetails(); - const providerInfo = amplifyMeta.providers.awscloudformation; - - answers.privacy.authRoleName = providerInfo.AuthRoleName; - answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; - } - - return { answers, dependsOn }; + return { answers: pathsAnswer }; } -async function askApiNames(context, defaults) { - const { amplify } = context; +async function askApiName(context: $TSContext, defaultResourceName: string) { const apiNameValidator = (input: string) => { - const amplifyValidatorOutput = amplify.inputValidation({ + const amplifyValidatorOutput = context.amplify.inputValidation({ validation: { operator: 'regex', value: '^[a-zA-Z0-9]+$', @@ -202,111 +160,90 @@ async function askApiNames(context, defaults) { return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : uniqueCheck; }; - const answer: { apiName?: string; resourceName: string } = 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: defaults.resourceName, - validate: apiNameValidator, - }, - ]); - - answer.apiName = answer.resourceName; + 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 answer; + return resourceName; } -async function askPrivacy(context, answers, currentPath) { +async function askPermissions( + context: $TSContext, + answers: $TSObject, + currentPath: ApigwPath, +): Promise<{ setting?: PermissionSetting; auth?: CrudOperation[]; open?: boolean; userPoolGroups?: $TSObject; unauth?: CrudOperation[] }> { while (true) { - const apiAccess = await inquirer.prompt({ - name: 'restrict', - type: 'confirm', - default: !(currentPath && currentPath.open), - message: 'Restrict API access', - }); + const apiAccess = await prompter.yesOrNo('Restrict API access', currentPath?.permissions?.setting !== PermissionSetting.OPEN); - if (!apiAccess.restrict) { - return { open: true }; + if (!apiAccess) { + return { setting: PermissionSetting.OPEN }; } - const userPoolGroupList = await context.amplify.getUserPoolGroupList(context); + const userPoolGroupList = context.amplify.getUserPoolGroupList(); let permissionSelected = 'Auth/Guest Users'; - const privacy: any = {}; + const permissions: $TSAny = {}; if (userPoolGroupList.length > 0) { do { if (permissionSelected === 'Learn more') { - context.print.info(''); - context.print.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(); + 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.', ); - context.print.info(''); + printer.blankLine(); } - const permissionSelection = await inquirer.prompt({ - name: 'selection', - type: 'list', - message: 'Restrict access by?', - choices: ['Auth/Guest Users', 'Individual Groups', 'Both', 'Learn more'], - default: 'Auth/Guest Users', - }); - - permissionSelected = permissionSelection.selection; + 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 answer = await inquirer.prompt({ - name: 'privacy', - type: 'list', - message: 'Who should have access?', - choices: [ + const permissionSetting = await prompter.pick<'one', string>( + 'Who should have access?', + [ { name: 'Authenticated users only', - value: 'private', + value: PermissionSetting.PRIVATE, }, { name: 'Authenticated and Guest users', - value: 'protected', + value: PermissionSetting.PROTECTED, }, ], - default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', - }); + { initial: currentPath?.permissions?.setting === PermissionSetting.PROTECTED ? 1 : 0 }, + ); - privacy[answer.privacy] = true; - - context.api = { - privacy: answer.privacy, - }; + permissions.setting = permissionSetting; let { - privacy: { auth: authPrivacy }, - } = currentPath || { privacy: {} }; + permissions: { auth: authPermissions }, + } = currentPath || { permissions: { auth: [] } }; let { - privacy: { unauth: unauthPrivacy }, - } = currentPath || { privacy: {} }; - - // convert legacy permissions to CRUD structure - if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { - authPrivacy = convertToCRUD(authPrivacy); - } - if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { - unauthPrivacy = convertToCRUD(unauthPrivacy); - } + permissions: { unauth: unauthPermissions }, + } = currentPath || { permissions: { unauth: [] } }; - if (answer.privacy === 'private') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + if (permissionSetting === PermissionSetting.PRIVATE) { + permissions.auth = await askCRUD('Authenticated', authPermissions); - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); } - if (answer.privacy === 'protected') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); - privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); - const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + if (permissionSetting === PermissionSetting.PROTECTED) { + permissions.auth = await askCRUD('Authenticated', authPermissions); + permissions.unauth = await askCRUD('Guest', unauthPermissions); + const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; await ensureAuth(context, apiRequirements, answers.resourceName); } @@ -315,60 +252,53 @@ async function askPrivacy(context, answers, currentPath) { if (permissionSelected === 'Both' || permissionSelected === 'Individual Groups') { // Enable Auth if not enabled - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); // Get Auth resource name - const authResourceName = await getAuthResourceName(context); + const authResourceName = getAuthResourceName(); answers.authResourceName = authResourceName; let defaultSelectedGroups = []; - if (currentPath && currentPath.privacy && currentPath.privacy.userPoolGroups) { - defaultSelectedGroups = Object.keys(currentPath.privacy.userPoolGroups); + if (currentPath?.permissions?.userPoolGroups) { + defaultSelectedGroups = Object.keys(currentPath.permissions.userPoolGroups); } - const userPoolGroupSelection = await inquirer.prompt([ - { - name: 'userpoolGroups', - type: 'checkbox', - message: 'Select groups:', - choices: userPoolGroupList, - default: defaultSelectedGroups, - validate: inputs => { - if (inputs.length === 0) { - return 'Select at least one option'; - } - return true; - }, + const userPoolGroupSelection = await inquirer.prompt({ + name: 'userpoolGroups', + type: 'checkbox', + message: 'Select groups:', + choices: userPoolGroupList, + default: defaultSelectedGroups, + validate: inputs => { + if (inputs.length === 0) { + return 'Select at least one option'; + } + return true; }, - ]); + }); const selectedUserPoolGroupList = userPoolGroupSelection.userpoolGroups; - for (let i = 0; i < selectedUserPoolGroupList.length; i += 1) { + for (const selectedUserPoolGroup of selectedUserPoolGroupList) { let defaults = []; - if ( - currentPath && - currentPath.privacy && - currentPath.privacy.userPoolGroups && - currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]] - ) { - defaults = currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]]; + if (currentPath?.permissions?.userPoolGroups?.[selectedUserPoolGroup]) { + defaults = currentPath.permissions.userPoolGroups[selectedUserPoolGroup]; } - if (!privacy.userPoolGroups) { - privacy.userPoolGroups = {}; + if (!permissions.userPoolGroups) { + permissions.userPoolGroups = {}; } - privacy.userPoolGroups[selectedUserPoolGroupList[i]] = await askReadWrite(selectedUserPoolGroupList[i], context, defaults); + permissions.userPoolGroups[selectedUserPoolGroup] = await askCRUD(selectedUserPoolGroup, defaults); } } - return privacy; + return permissions; } } -async function ensureAuth(context, apiRequirements, resourceName) { - const checkResult = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ +async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, resourceName: string) { + const checkResult: $TSAny = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ apiRequirements, context, 'api', @@ -382,7 +312,7 @@ async function ensureAuth(context, apiRequirements, resourceName) { } if (checkResult.errors && checkResult.errors.length > 0) { - context.print.warning(checkResult.errors.join(os.EOL)); + printer.warn(checkResult.errors.join(os.EOL)); } // If auth is not imported and there were errors, adjust or enable auth configuration @@ -390,61 +320,36 @@ async function ensureAuth(context, apiRequirements, resourceName) { try { await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ context, - 'api', + AmplifyCategories.API, resourceName, apiRequirements, ]); } catch (error) { - context.print.error(error); + printer.error(error); throw error; } } } -async function askReadWrite(userType, context, privacy) { - const permissionMap = { - create: ['/POST'], - read: ['/GET'], - update: ['/PUT', '/PATCH'], - delete: ['/DELETE'], - }; - - const defaults = []; - if (privacy) { - Object.values(permissionMap).forEach((el, index) => { - if (el.every(i => privacy.includes(i))) { - defaults.push(Object.keys(permissionMap)[index]); - } - }); - } - - const crudAnswers = await context.amplify.crudFlow(userType, permissionMap, defaults); +async function askCRUD(userType: string, permissions: string[] = []) { + const crudOptions = ['create', 'read', 'update', 'delete']; + const crudAnswers = await prompter.pick<'many', string>(`What permissions do you want to grant to ${userType}`, crudOptions, { + returnSize: 'many', + initial: permissions.map(p => crudOptions.indexOf(p)), + }); return crudAnswers; } -async function askPaths(context, answers, currentPath) { - // const existingLambdaArns = true; - - const existingFunctions = functionsExist(context); +async function askPaths(context: $TSContext, answers: $TSObject, currentPath: ApigwPath): Promise { + const existingFunctions = functionsExist(); - const choices = [ - { - name: 'Create a new Lambda function', - value: 'newFunction', - }, - ]; - - /* - Removing this option for now in favor of multi-env support - - NOT CRITICAL - if (existingLambdaArns) { - choices.push({ - name: 'Use a Lambda function already deployed on AWS', - value: 'arn', - }); - } - */ + let defaultFunctionType = 'newFunction'; + const defaultChoice = { + name: 'Create a new Lambda function', + value: defaultFunctionType, + }; + const choices = [defaultChoice]; if (existingFunctions) { choices.push({ @@ -453,28 +358,19 @@ async function askPaths(context, answers, currentPath) { }); } - let defaultFunctionType = 'newFunction'; - if (currentPath) { - defaultFunctionType = currentPath.lambdaArn ? 'arn' : 'projectFunction'; - } - - const paths = [...answers.paths]; + const paths = answers.paths; - let addAnotherPath; + let addAnotherPath: boolean; do { - let pathName; - let isPathValid; + let pathName: string; + let isPathValid: boolean; do { - const pathAnswer = await inquirer.prompt({ - name: 'name', - type: 'input', - message: 'Provide a path (e.g., /book/{isbn}):', - default: currentPath ? currentPath.name : '/items', - validate: value => validatePathName(value), + pathName = await prompter.input('Provide a path (e.g., /book/{isbn}):', { + initial: currentPath ? currentPath.name : '/items', + validate: validatePathName, }); - pathName = pathAnswer.name; - const overlapCheckResult = checkForPathOverlap(pathName, paths); + 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; @@ -483,81 +379,64 @@ async function askPaths(context, answers, currentPath) { // 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 inquirer.prompt({ - name: 'isOverlappingPathOK', - type: 'confirm', - message: `The path ${lowerOrderPath} overlaps with ${higherOrderPath}. Users authorized to access ${higherOrderPath} will also have access to ${lowerOrderPath}. Are you sure you want to continue?`, - default: false, - }) - ).isOverlappingPathOK; + + 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 lambdaAnswer = await inquirer.prompt({ - name: 'functionType', - type: 'list', - message: 'Choose a Lambda source', - choices, - default: defaultFunctionType, - }); + const functionType = await prompter.pick<'one', string>('Choose a Lambda source', choices, { initial: choices.indexOf(defaultChoice) }); - // TODO: add path validation like awsmobile-cli does let path = { name: pathName }; let lambda; do { - lambda = await askLambdaSource(context, lambdaAnswer.functionType, path.name, currentPath); + lambda = await askLambdaSource(context, functionType, pathName, currentPath); } while (!lambda); - const privacy = await askPrivacy(context, answers, currentPath); - path = { ...path, ...lambda, privacy }; - paths.push(path); + const permissions = await askPermissions(context, answers, currentPath); + path = { ...path, ...lambda, permissions }; + paths[pathName] = path; if (currentPath) { break; } - addAnotherPath = ( - await inquirer.prompt({ - name: 'anotherPath', - type: 'confirm', - message: 'Do you want to add another path?', - default: false, - }) - ).anotherPath; + addAnotherPath = await prompter.confirmContinue('Do you want to add another path?'); } while (addAnotherPath); - const { dependsOn, functionArns } = await findDependsOn(paths, context); + const { dependsOn, functionArns } = await findDependsOn(paths); - return { paths, dependsOn, functionArns }; + return { paths, dependsOn, resourceName: answers.resourceName, functionArns }; } -async function findDependsOn(paths, context) { +async function findDependsOn(paths: $TSObject[]) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; const functionArns = []; - for (let i = 0; i < paths.length; i += 1) { - if (paths[i].lambdaFunction && !paths[i].lambdaArn) { - if (!dependsOn.find(func => func.resourceName === paths[i].lambdaFunction)) { + 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: paths[i].lambdaFunction, + resourceName: path.lambdaFunction, attributes: ['Name', 'Arn'], }); } } - if (!functionArns.find(func => func.lambdaFunction === paths[i].lambdaFunction)) { + if (!functionArns.find(func => func.lambdaFunction === path.lambdaFunction)) { functionArns.push({ - lambdaFunction: paths[i].lambdaFunction, - lambdaArn: paths[i].lambdaArn, + lambdaFunction: path.lambdaFunction, + lambdaArn: path.lambdaArn, }); } - if (paths[i].privacy && paths[i].privacy.userPoolGroups) { - const userPoolGroups = Object.keys(paths[i].privacy.userPoolGroups); + if (path?.permissions?.userPoolGroups) { + const userPoolGroups = Object.keys(path.privacy.userPoolGroups); if (userPoolGroups.length > 0) { // Get auth resource name - const authResourceName = await getAuthResourceName(context); + const authResourceName = getAuthResourceName(); if (!dependsOn.find(resource => resource.resourceName === authResourceName)) { dependsOn.push({ @@ -582,26 +461,27 @@ async function findDependsOn(paths, context) { return { dependsOn, functionArns }; } -async function getAuthResourceName(context) { - let authResources = (await context.amplify.getResourceStatus('auth')).allResources; - authResources = authResources.filter(resource => resource.service === 'Cognito'); +function getAuthResourceName(): string { + const meta = stateManager.getMeta(); + const authResources = (meta?.auth || []).filter(resource => resource.service === AmplifySupportedService.COGNITO); if (authResources.length === 0) { - throw new Error('No auth resource found. Please add it using amplify add auth'); + throw new Error('No auth resource found. Add it using amplify add auth'); } const authResourceName = authResources[0].resourceName; return authResourceName; } -function functionsExist(context) { - if (!context.amplify.getProjectDetails().amplifyMeta.function) { +function functionsExist() { + const meta = stateManager.getMeta(); + if (!meta.function) { return false; } - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; + const functionResources = meta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { + if (functionResources[resourceName].service === AmplifySupportedService.LAMBDA) { lambdaFunctions.push(resourceName); } }); @@ -613,26 +493,20 @@ function functionsExist(context) { return true; } -async function askLambdaSource(context, functionType, path, currentPath) { +async function askLambdaSource(context: $TSContext, functionType: string, path: string, currentPath: ApigwPath) { switch (functionType) { case 'arn': return askLambdaArn(context, currentPath); case 'projectFunction': - return askLambdaFromProject(context, currentPath); + return askLambdaFromProject(currentPath); case 'newFunction': - return newLambdaFunction(context, path); + return newLambdaFunction(context as $TSAny, path); default: throw new Error('Type not supported'); } } -async function newLambdaFunction(context, path) { - context.api = { - path, - // ExpressJS represents path parameters as /:param instead of /{param}. This expression performs this replacement. - expressPath: formatCFNPathParamsForExpressJs(path), - functionTemplate: 'serverless', - }; +async function newLambdaFunction(context: $TSContext, path: string) { let params = { functionTemplate: { parameters: { @@ -642,39 +516,35 @@ async function newLambdaFunction(context, path) { }, }; - const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ + const resourceName = await context.amplify.invokePluginMethod(context, AmplifyCategories.FUNCTION, undefined, 'add', [ context, 'awscloudformation', - FunctionServiceNameLambdaFunction, + AmplifySupportedService.LAMBDA, params, ]); - context.print.success('Succesfully added the Lambda function locally'); + printer.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; } -async function askLambdaFromProject(context, currentPath) { - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; +async function askLambdaFromProject(currentPath?: ApigwPath) { + const meta = stateManager.getMeta(); const lambdaFunctions = []; - Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { + Object.keys(meta?.function || {}).forEach(resourceName => { + if (meta.function[resourceName].service === AmplifySupportedService.LAMBDA) { lambdaFunctions.push(resourceName); } }); - const answer = await inquirer.prompt({ - name: 'lambdaFunction', - type: 'list', - message: 'Choose the Lambda function to invoke by this path', - choices: lambdaFunctions, - default: currentPath ? currentPath.lambdaFunction : lambdaFunctions[0], + 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: answer.lambdaFunction }; + return { lambdaFunction }; } -async function askLambdaArn(context, currentPath) { +async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions'); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ @@ -683,16 +553,16 @@ async function askLambdaArn(context, currentPath) { })); if (lambdaOptions.length === 0) { - context.print.error('You do not have any Lambda functions configured for the selected Region'); + printer.error('You do not have any Lambda functions configured for the selected Region'); return null; } const lambdaCloudOptionQuestion = { type: 'list', name: 'lambdaChoice', - message: 'Please select a Lambda function', + message: 'Select a Lambda function', choices: lambdaOptions, - default: currentPath && currentPath.lambdaArn ? `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, + default: currentPath && currentPath.lambdaFunction ? `${currentPath.lambdaFunction}` : `${lambdaOptions[0].value}`, }; let lambdaOption; @@ -700,7 +570,7 @@ async function askLambdaArn(context, currentPath) { try { lambdaOption = await inquirer.prompt([lambdaCloudOptionQuestion]); } catch (err) { - context.print.error('Select a Lambda Function'); + printer.error('Select a Lambda Function'); } } @@ -712,56 +582,12 @@ async function askLambdaArn(context, currentPath) { }; } -export async function migrate(context, projectPath, resourceName) { - const { amplify } = context; - - const targetDir = amplify.pathManager.getBackendDirPath(); - const resourceDirPath = path.join(targetDir, category, resourceName); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let parameters; - try { - parameters = amplify.readJsonFile(parametersFilePath); - } catch (e) { - context.print.error(`Error reading api-params.json file for ${resourceName} resource`); - throw e; - } - const copyJobs = [ - { - dir: path.join(rootAssetDir, 'cloudformation-templates'), - template: 'apigw-cloudformation-template-default.json.ejs', - target: `${targetDir}/${category}/${resourceName}/${resourceName}-cloudformation-template.json`, - }, - ]; - - // copy over the files - await context.amplify.copyBatch(context, copyJobs, parameters, true, false); - - // Create parameters.json file - const cfnParameters = { - authRoleName: { - Ref: 'AuthRoleName', - }, - unauthRoleName: { - Ref: 'UnauthRoleName', - }, - }; - - const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - const jsonString = JSON.stringify(cfnParameters, null, 4); - fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); -} - -function convertToCRUD(privacy) { - if (privacy === 'r') { - privacy = ['/GET']; - } else if (privacy === 'rw') { - privacy = ['/POST', '/GET', '/PUT', '/PATCH', '/DELETE']; - } - - return privacy; +export async function migrate(context: $TSContext, projectPath: string, resourceName: string) { + const apigwInputState = ApigwInputState.getInstance(context, resourceName); + return apigwInputState.migrateApigwResource(resourceName); } -export function getIAMPolicies(resourceName, crudOptions) { +export function getIAMPolicies(resourceName: string, crudOptions: string[]) { let policy = {}; const actions = []; @@ -780,7 +606,7 @@ export function getIAMPolicies(resourceName, crudOptions) { actions.push('apigateway:DELETE'); break; default: - console.log(`${crudOption} not supported`); + printer.info(`${crudOption} not supported`); } }); @@ -812,7 +638,7 @@ export function getIAMPolicies(resourceName, crudOptions) { return { policy, attributes }; } -export const openConsole = async (context: $TSContext) => { +export const openConsole = async (context?: $TSContext) => { const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; const { Region } = amplifyMeta.providers.awscloudformation; @@ -830,12 +656,7 @@ export const openConsole = async (context: $TSContext) => { let selectedApi = restApis[0]; if (restApis.length > 1) { - ({ selectedApi } = await inquirer.prompt({ - type: 'list', - name: 'selectedApi', - choices: restApis, - message: 'Please select the API', - })); + selectedApi = await prompter.pick<'one', string>('Select the API', restApis); } const selectedResource = categoryAmplifyMeta[selectedApi]; @@ -853,34 +674,29 @@ export const openConsole = async (context: $TSContext) => { 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, - }, - ], - }); + const selectedConsole = await prompter.pick<'one', string>('Which console 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 { - context.print.error('Option not available'); + printer.error('Option not available'); return; } } open(url, { wait: false }); } else { - context.print.error('There are no REST APIs pushed to the cloud'); + 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-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts index 1d0a92fb11..10d0b2eac0 100644 --- 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 @@ -1,21 +1,22 @@ -import inquirer from 'inquirer'; +import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import chalk from 'chalk'; -import ora from 'ora'; import { DataApiParams } from 'graphql-relational-schema-transformer'; -import { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick, $TSContext, $TSObject } from 'amplify-cli-core'; +import inquirer from 'inquirer'; +import ora from 'ora'; const spinner = ora(''); const category = 'api'; const providerName = 'awscloudformation'; -export async function serviceWalkthrough(context: $TSContext, defaultValuesFilename: string, datasourceMetadata: $TSObject) { +export async function serviceWalkthrough(context: $TSContext, datasourceMetadata: $TSObject) { 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -24,9 +25,9 @@ export async function serviceWalkthrough(context: $TSContext, defaultValuesFilen let appSyncApi: string; const apis = Object.keys(amplifyMeta[category]); - for (let i = 0; i < apis.length; i += 1) { - if (amplifyMeta[category][apis[i]].service === 'AppSync') { - appSyncApi = apis[i]; + for (const api of apis) { + if (amplifyMeta[category][api].service === 'AppSync') { + appSyncApi = api; break; } } @@ -35,7 +36,7 @@ export async function serviceWalkthrough(context: $TSContext, defaultValuesFilen 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -86,7 +87,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { if (serverlessClusters.length === 0) { const errMessage = 'No properly configured Aurora Serverless clusters found.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -110,7 +111,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { // Pick first and only value const firstCluster = Array.from(clusters.values())[0]; - context.print.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); return { selectedClusterArn: firstCluster.DBClusterArn, @@ -148,7 +149,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, if (secretsForCluster.length === 0) { const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); @@ -169,7 +170,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, // Pick first and only value selectedSecretArn = Array.from(secrets.values())[0]; - context.print.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); } return selectedSecretArn; @@ -206,14 +207,14 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn const msg = `Ensure that '${secretArn}' contains your database credentials. ` + 'Please note that Aurora Serverless does not support IAM database authentication.'; - context.print.error(msg); + printer.error(msg); } } if (databaseList.length === 0) { const errMessage = 'No database found in the selected cluster.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -224,7 +225,7 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn return await promptWalkthroughQuestion(inputs, 3, databaseList); } - context.print.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); return databaseList[0]; } 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 index 933134e813..508160615f 100644 --- 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 @@ -1,30 +1,33 @@ -import { ListQuestion, CheckboxQuestion, ListChoiceOptions } from 'inquirer'; -import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; -import inquirer from 'inquirer'; -import fs from 'fs-extra'; -import path from 'path'; -import { rootAssetDir, provider } from '../aws-constants'; -import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; -import { category } from '../../../category-constants'; -import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; -import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; -import _ from 'lodash'; -import chalk from 'chalk'; -import uuid from 'uuid'; -import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; +import { Duration, Expiration } from '@aws-cdk/core'; import { - ResourceAlreadyExistsError, - ResourceDoesNotExistError, - UnknownResourceTypeError, + $TSContext, + $TSObject, exitOnNextTick, - stateManager, FeatureFlags, - $TSContext, open, + pathManager, + ResourceAlreadyExistsError, + ResourceDoesNotExistError, + stateManager, + UnknownResourceTypeError, } from 'amplify-cli-core'; -import { Duration, Expiration } from '@aws-cdk/core'; +import { UpdateApiRequest } from 'amplify-headless-interface'; +import { printer } from '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 * as path from 'path'; +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 { defineGlobalSandboxMode } from '../utils/global-sandbox-mode'; +import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; const serviceName = 'AppSync'; const elasticContainerServiceName = 'ElasticContainer'; @@ -151,11 +154,11 @@ export const openConsole = async (context: $TSContext) => { url = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); if (isAdminApp) { if (region !== Region) { - context.print.warning(`Region mismatch: Amplify service returned '${region}', but found '${Region}' in amplify-meta.json.`); + 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; @@ -190,26 +193,24 @@ export const openConsole = async (context: $TSContext) => { } else if (selectedConsole === codePipeline) { url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; } else { - context.print.error('Option not available'); + printer.error('Option not available'); return; } } open(url, { wait: false }); } else { - context.print.error('AppSync API is not pushed in the cloud.'); + printer.error('AppSync API is not pushed in the cloud.'); } }; -const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { +const serviceApiInputWalkthrough = async (context: $TSContext, serviceMetadata) => { let continuePrompt = false; let authConfig; let defaultAuthType; let resolverConfig; const { amplify } = context; const { inputs } = serviceMetadata; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); let resourceAnswers = {}; @@ -336,7 +337,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile }; }; -const updateApiInputWalkthrough = async (context, project, resolverConfig, modelTypes) => { +const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject, resolverConfig, modelTypes) => { let authConfig; let defaultAuthType; const updateChoices = [ @@ -388,15 +389,16 @@ const updateApiInputWalkthrough = async (context, project, resolverConfig, model }; }; -export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { - const resourceName = resourceAlreadyExists(context); - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); +export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $TSObject) => { + const resourceName = resourceAlreadyExists(); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const transformerVersion = providerPlugin.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.'; - context.print.warning(errMessage); + printer.warn(errMessage); await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); exitOnNextTick(0); } @@ -404,7 +406,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { amplify } = context; const { inputs } = serviceMetadata; - const basicInfoAnswers = await serviceApiInputWalkthrough(context, defaultValuesFilename, serviceMetadata); + const basicInfoAnswers = await serviceApiInputWalkthrough(context, serviceMetadata); let schemaContent = ''; let askToEdit = true; @@ -431,7 +433,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen }; }; -export const updateWalkthrough = async (context): Promise => { +export const updateWalkthrough = async (context: $TSContext): Promise => { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; @@ -450,11 +452,10 @@ export const updateWalkthrough = async (context): Promise => { ); } ({ resourceName } = resource); - const backEndDir = context.amplify.pathManager.getBackendDirPath(); - resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); + 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -493,7 +494,7 @@ export const updateWalkthrough = async (context): Promise => { }; }; -async function displayApiInformation(context, resource, project) { +async function displayApiInformation(context: $TSContext, resource: $TSObject, project: $TSObject) { let authModes: string[] = []; authModes.push( `- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`, @@ -502,35 +503,35 @@ async function displayApiInformation(context, resource, project) { authModes.push(`- ${await displayAuthMode(context, resource, authMode.authenticationType)}`); }); - context.print.info(''); + printer.info(''); - context.print.success('General information'); - context.print.info('- Name: '.concat(resource.resourceName)); + printer.success('General information'); + printer.info('- Name: '.concat(resource.resourceName)); if (resource?.output?.GraphQLAPIEndpointOutput) { - context.print.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); + printer.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); } - context.print.info(''); + printer.info(''); - context.print.success('Authorization modes'); - authModes.forEach(authMode => context.print.info(authMode)); - context.print.info(''); + printer.success('Authorization modes'); + authModes.forEach(authMode => printer.info(authMode)); + printer.info(''); - context.print.success('Conflict detection (required for DataStore)'); + printer.success('Conflict detection (required for DataStore)'); if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - context.print.info( + printer.info( `- Conflict resolution strategy: ${ conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name }`, ); } else { - context.print.info('- Disabled'); + printer.info('- Disabled'); } - context.print.info(''); + printer.info(''); } -async function displayAuthMode(context, resource, authMode) { - if (authMode == 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { +async function displayAuthMode(context: $TSContext, resource: $TSObject, authMode: string) { + if (authMode === 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getAppSyncApiKeys', { apiId: resource.output.GraphQLAPIIdOutput, }); @@ -546,13 +547,13 @@ async function displayAuthMode(context, resource, authMode) { return authProviderChoices.find(choice => choice.value === authMode).name; } -async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { +async function askAdditionalQuestions(context: $TSContext, authConfig, defaultAuthType, modelTypes?) { authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); return { authConfig }; } -async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) { - let resolverConfigResponse: any = {}; +async function askResolverConflictQuestion(context: $TSContext, resolverConfig, modelTypes?) { + let resolverConfigResponse: $TSObject = {}; if (await context.prompt.confirm('Enable conflict detection?', !resolverConfig?.project)) { resolverConfigResponse = await askResolverConflictHandlerQuestion(context, modelTypes); @@ -561,8 +562,8 @@ async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) return resolverConfigResponse; } -async function askResolverConflictHandlerQuestion(context, modelTypes?) { - let resolverConfig: any = {}; +async function askResolverConflictHandlerQuestion(context: $TSContext, modelTypes?) { + let resolverConfig: $TSObject = {}; const askConflictResolutionStrategy = async msg => { let conflictResolutionStrategy; @@ -580,13 +581,13 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); - let syncConfig: any = { + let syncConfig: $TSObject = { ConflictHandler: conflictResolutionStrategy, ConflictDetection: 'VERSION', }; if (conflictResolutionStrategy === 'LAMBDA') { - const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); + const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(); syncConfig.LambdaConflictHandler = { name: lambdaFunctionName, new: newFunction, @@ -613,10 +614,8 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { if (selectedModelTypes.length > 0) { resolverConfig.models = {}; - for (let i = 0; i < selectedModelTypes.length; i += 1) { - resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( - `Select the resolution strategy for ${selectedModelTypes[i]} model`, - ); + for (const modelType of selectedModelTypes) { + resolverConfig.models[modelType] = await askConflictResolutionStrategy(`Select the resolution strategy for ${modelType} model`); } } } @@ -625,7 +624,7 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { return resolverConfig; } -async function askSyncFunctionQuestion(context) { +async function askSyncFunctionQuestion() { const syncLambdaQuestion = { type: 'list', name: 'syncLambdaAnswer', @@ -660,8 +659,8 @@ async function askSyncFunctionQuestion(context) { return { newFunction, lambdaFunctionName }; } -async function addLambdaAuthorizerChoice(context) { - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); +async function addLambdaAuthorizerChoice(context: $TSContext) { + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const transformerVersion = providerPlugin.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ @@ -671,9 +670,9 @@ async function addLambdaAuthorizerChoice(context) { } } -async function askDefaultAuthQuestion(context) { +async function askDefaultAuthQuestion(context: $TSContext) { await addLambdaAuthorizerChoice(context); - const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); const currentDefaultAuth = currentAuthConfig && currentAuthConfig.defaultAuthentication ? currentAuthConfig.defaultAuthentication.authenticationType : undefined; @@ -698,8 +697,8 @@ async function askDefaultAuthQuestion(context) { }; } -export async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { - const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); +export async function askAdditionalAuthQuestions(context: $TSContext, authConfig: $TSObject, defaultAuthType) { + const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); authConfig.additionalAuthenticationProviders = []; if (await context.prompt.confirm('Configure additional auth types?')) { // Get additional auth configured @@ -720,9 +719,7 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut const additionalProvidersAnswer = await inquirer.prompt([additionalProvidersQuestion]); - for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { - const authProvider = additionalProvidersAnswer.authType[i]; - + for (const authProvider of additionalProvidersAnswer.authType) { const config = await askAuthQuestions( authProvider, context, @@ -740,10 +737,10 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut return authConfig; } -export async function askAuthQuestions(authType, context, printLeadText = false, authSettings) { +export async function askAuthQuestions(authType: string, context: $TSContext, printLeadText = false, authSettings) { if (authType === 'AMAZON_COGNITO_USER_POOLS') { if (printLeadText) { - context.print.info('Cognito UserPool configuration'); + printer.info('Cognito UserPool configuration'); } const userPoolConfig = await askUserPoolQuestions(context); @@ -753,7 +750,7 @@ export async function askAuthQuestions(authType, context, printLeadText = false, if (authType === 'API_KEY') { if (printLeadText) { - context.print.info('API key configuration'); + printer.info('API key configuration'); } const apiKeyConfig = await askApiKeyQuestions(authSettings); @@ -769,7 +766,7 @@ export async function askAuthQuestions(authType, context, printLeadText = false, if (authType === 'OPENID_CONNECT') { if (printLeadText) { - context.print.info('OpenID Connect configuration'); + printer.info('OpenID Connect configuration'); } const openIDConnectConfig = await askOpenIDConnectQuestions(authSettings); @@ -788,17 +785,17 @@ export async function askAuthQuestions(authType, context, printLeadText = false, } const errMessage = `Unknown authType: ${authType}`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); exitOnNextTick(1); } -async function askUserPoolQuestions(context) { - let authResourceName = checkIfAuthExists(context); +async function askUserPoolQuestions(context: $TSContext) { + let authResourceName = checkIfAuthExists(); if (!authResourceName) { authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context, true]); } else { - context.print.info('Use a Cognito user pool configured as a part of this project.'); + printer.info('Use a Cognito user pool configured as a part of this project.'); } // Added resources are prefixed with auth @@ -812,7 +809,7 @@ async function askUserPoolQuestions(context) { }; } -export async function askApiKeyQuestions(authSettings = undefined) { +export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { let defaultValues = { apiKeyExpirationDays: 7, description: undefined, @@ -853,7 +850,7 @@ export async function askApiKeyQuestions(authSettings = undefined) { }; } -async function askOpenIDConnectQuestions(authSettings) { +async function askOpenIDConnectQuestions(authSettings: $TSObject) { let defaultValues = { authTTL: undefined, clientId: undefined, @@ -907,7 +904,7 @@ async function askOpenIDConnectQuestions(authSettings) { }; } -async function validateDays(input) { +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) { @@ -917,7 +914,7 @@ async function validateDays(input) { return true; } -function validateIssuerUrl(input) { +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, @@ -930,7 +927,7 @@ function validateIssuerUrl(input) { return true; } -function validateTTL(input) { +function validateTTL(input: string) { const isValid = /^\d+$/.test(input); if (!isValid) { @@ -940,32 +937,32 @@ function validateTTL(input) { return true; } -function resourceAlreadyExists(context) { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); +function resourceAlreadyExists() { + const meta = stateManager.getMeta(); let resourceName; - if (amplifyMeta[category]) { - const categoryResources = amplifyMeta[category]; - Object.keys(categoryResources).forEach(resource => { + 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 => { +export const migrate = async (context: $TSContext) => { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true, }); }; -export const getIAMPolicies = (resourceName: string, operations: string[], context: any) => { - let policy: any = {}; +export const getIAMPolicies = (resourceName: string, operations: string[]) => { + let policy: $TSObject = {}; const resources = []; const actions = []; if (!FeatureFlags.getBoolean('appSync.generateGraphQLPermissions')) { @@ -985,7 +982,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[], conte actions.push('appsync:Delete*'); break; default: - console.log(`${crudOption} not supported`); + printer.info(`${crudOption} not supported`); } }); resources.push(buildPolicyResource(resourceName, null)); @@ -1001,7 +998,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[], conte }; const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; - if (authConfigHasApiKey(getAppSyncAuthConfig(context.amplify.getProjectMeta()))) { + if (authConfigHasApiKey(getAppSyncAuthConfig(stateManager.getMeta()))) { attributes.push('GraphQLAPIKeyOutput'); } @@ -1177,7 +1174,7 @@ async function createLambdaAuthorizerFunction(context: $TSContext) { const backendConfigs = { service: FunctionServiceNameLambdaFunction, - providerPlugin: provider, + providerPlugin: providerName, build: true, }; 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 index 9b38fb744f..5ba0df021b 100644 --- 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 @@ -1,8 +1,10 @@ -import { exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { printer } from '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'; @@ -44,11 +46,8 @@ export type ServiceConfiguration = { gitHubInfo?: GitHubSourceActionInfo; }; -export async function serviceWalkthrough(context, defaultValuesFilename, apiType: API_TYPE): Promise> { - const { amplify } = context; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); +export async function serviceWalkthrough(context: $TSContext, apiType: API_TYPE): Promise> { + const allDefaultValues = getAllDefaults(); const resourceName = await askResourceName(context, allDefaultValues); @@ -57,7 +56,7 @@ export async function serviceWalkthrough(context, defaultValuesFilename, apiType return { resourceName, ...containerInfo }; } -async function askResourceName(context, allDefaultValues) { +async function askResourceName(context: $TSContext, allDefaultValues: $TSObject) { const { amplify } = context; const { resourceName } = await inquirer.prompt([ @@ -80,7 +79,7 @@ async function askResourceName(context, allDefaultValues) { return resourceName; } -async function askContainerSource(context, resourceName: string, apiType: API_TYPE): Promise> { +async function askContainerSource(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { return newContainer(context, resourceName, apiType); } @@ -89,7 +88,7 @@ export enum IMAGE_SOURCE_TYPE { CUSTOM = 'CUSTOM', } -async function newContainer(context, resourceName: string, apiType: API_TYPE): Promise> { +async function newContainer(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { let imageSource: { type: IMAGE_SOURCE_TYPE; template?: string }; let choices = []; @@ -171,8 +170,8 @@ async function newContainer(context, resourceName: string, apiType: API_TYPE): P let gitHubToken: string; if (deploymentMechanismQuestion.deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - context.print.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); - context.print.info( + 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', ); @@ -234,7 +233,7 @@ async function newContainer(context, resourceName: string, apiType: API_TYPE): P }; } -export async function updateWalkthrough(context, defaultValuesFilename, apiType: API_TYPE) { +export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources @@ -247,7 +246,7 @@ export async function updateWalkthrough(context, defaultValuesFilename, apiType: // 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`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; @@ -302,7 +301,7 @@ export async function updateWalkthrough(context, defaultValuesFilename, apiType: const hasAccessableResources = ['storage', 'function'].some(categoryName => { return Object.keys(meta[categoryName] ?? {}).length > 0; }); - let rolePermissions: any = {}; + let rolePermissions: $TSAny = {}; if ( hasAccessableResources && (await context.amplify.confirmPrompt('Do you want to access other resources in this project from your api?')) 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 index d920a8d9c9..e3385279de 100644 --- 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 @@ -1,6 +1,7 @@ +import { $TSAny, $TSMeta, $TSObject, AmplifyCategories, AmplifySupportedService, stateManager } from 'amplify-cli-core'; import _ from 'lodash'; -export const authConfigHasApiKey = authConfig => { +export const authConfigHasApiKey = (authConfig?: $TSAny) => { if (!authConfig) { return false; } @@ -13,12 +14,11 @@ export const authConfigHasApiKey = authConfig => { ); }; -export const checkIfAuthExists = context => { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); +export const checkIfAuthExists = () => { + const amplifyMeta = stateManager.getMeta(); let authResourceName; - const authServiceName = 'Cognito'; - const authCategoryName = 'auth'; + const authServiceName = AmplifySupportedService.COGNITO; + const authCategoryName = AmplifyCategories.AUTH; if (amplifyMeta[authCategoryName] && Object.keys(amplifyMeta[authCategoryName]).length > 0) { const categoryResources = amplifyMeta[authCategoryName]; @@ -34,15 +34,15 @@ export const checkIfAuthExists = context => { // some utility functions to extract the AppSync API name and config from amplify-meta -export const getAppSyncAuthConfig = projectMeta => { +export const getAppSyncAuthConfig = (projectMeta: $TSMeta) => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { - const value = entry[1] as any; + const value = entry[1] as $TSAny; return value && value.output ? value.output.authConfig : {}; } }; -export const getAppSyncResourceName = (projectMeta: any): string | undefined => { +export const getAppSyncResourceName = (projectMeta: $TSMeta): string | undefined => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { return entry[0]; @@ -51,6 +51,8 @@ export const getAppSyncResourceName = (projectMeta: any): string | undefined => // project meta is the contents of amplify-meta.json // typically retreived using context.amplify.getProjectMeta() -const getAppSyncAmplifyMetaEntry = (projectMeta: any) => { - return Object.entries(projectMeta.api || {}).find(([, value]) => (value as any).service === 'AppSync'); +const getAppSyncAmplifyMetaEntry = (projectMeta: $TSMeta) => { + return Object.entries(projectMeta[AmplifyCategories.API] || {}).find( + ([, value]) => (value as $TSObject).service === AmplifySupportedService.APPSYNC, + ); }; 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 index 51da9da2da..5a1368cfa8 100644 --- 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 @@ -2,14 +2,14 @@ import { Octokit } from '@octokit/rest'; import * as fs from 'fs-extra'; import inquirer from 'inquirer'; import * as path from 'path'; -import uuid from 'uuid'; +import { v4 as uuid } from 'uuid'; 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 { JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; +import { $TSAny, $TSContext, JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; import { setExistingSecretArns } from './containers/set-existing-secret-arns'; import { category } from '../../../category-constants'; @@ -28,9 +28,9 @@ export type ApiResource = { restrictAccess: boolean; dependsOn: ResourceDependency[]; environmentMap: Record; - categoryPolicies: any[]; - mutableParametersState: any; - output?: Record; + categoryPolicies: $TSAny[]; + mutableParametersState: $TSAny; + output?: Record; apiType?: API_TYPE; exposedContainer?: { name: string; port: number }; }; @@ -46,7 +46,7 @@ type ContainerArtifactsMetadata = { }; export async function generateContainersArtifacts( - context: any, + context: $TSContext, resource: ApiResource, askForExposedContainer: boolean = false, ): Promise { @@ -116,7 +116,12 @@ export async function generateContainersArtifacts( }; } -export async function processDockerConfig(context: any, resource: ApiResource, srcPath: string, askForExposedContainer: boolean = false) { +export async function processDockerConfig( + context: $TSContext, + resource: ApiResource, + srcPath: string, + askForExposedContainer: boolean = false, +) { const { providers: { [cloudformationProviderName]: provider }, } = context.amplify.getProjectMeta(); @@ -306,7 +311,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s }; } -async function shouldUpdateSecrets(context: any, secrets: Record): Promise { +async function shouldUpdateSecrets(context: $TSContext, secrets: Record): Promise { const hasSecrets = Object.keys(secrets).length > 0; if (!hasSecrets || context.exeInfo.inputParams.yes) { 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 index 05b3688da0..2c7adced53 100644 --- 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 @@ -1,4 +1,10 @@ -export const serviceMetadataFor = async service => (await import('../../supported-services')).supportedServices[service]; -export const datasourceMetadataFor = async datasource => (await import('../../supported-datasources')).supportedDatasources[datasource]; -export const getServiceWalkthrough = async walkthroughFilename => - (await import(`../service-walkthroughs/${walkthroughFilename}`)).serviceWalkthrough; +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 index 1196423873..3d339aecd0 100644 --- 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 @@ -1,18 +1,14 @@ -import inquirer, { ConfirmQuestion } from 'inquirer'; -import path from 'path'; +import { $TSContext, pathManager } from 'amplify-cli-core'; +import { prompter } from 'amplify-prompts'; +import * as path from 'path'; import { category } from '../../../category-constants'; import { gqlSchemaFilename } from '../aws-constants'; -export const editSchemaFlow = async (context: any, apiName: string) => { - const prompt: ConfirmQuestion = { - type: 'confirm', - name: 'editNow', - message: 'Do you want to edit the schema now?', - default: true, - }; +export const editSchemaFlow = async (context: $TSContext, apiName: string) => { + if (!(await prompter.yesOrNo('Do you want to edit the schema now?', true))) { + return; + } - if (!(await inquirer.prompt(prompt)).editNow) return; - - const schemaPath = path.join(context.amplify.pathManager.getBackendDirPath(), category, apiName, gqlSchemaFilename); + 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/print-api-key-warnings.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/print-api-key-warnings.ts index f98601878b..14eeb6a933 100644 --- 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 @@ -1,16 +1,18 @@ +import { printer } from '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 = (context, oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { +export const printApiKeyWarnings = (oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { if (oldConfigHadApiKey && !newConfigHasApiKey) { - context.print.warning('The API_KEY auth type has been removed from the API.'); - context.print.warning( + 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.', ); - context.print.warning('⚠️ This must be done before running "amplify push" to prevent a push failure'); + printer.warn('⚠️ This must be done before running "amplify push" to prevent a push failure'); } if (!oldConfigHadApiKey && newConfigHasApiKey) { - context.print.warning('The API_KEY auth type has been added to the API.'); - context.print.warning( + 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/rest-api-path-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts index 37370c2dea..2893bfe9a9 100644 --- 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 @@ -37,7 +37,7 @@ export const validatePathName = (name: string) => { // } // // checkForPathOverlap assumes that all provided paths have previously been run through validatePathName(). -export const checkForPathOverlap = (name: string, paths: { name: string }[]) => { +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 @@ -59,7 +59,7 @@ export const checkForPathOverlap = (name: string, paths: { name: string }[]) => 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.map(path => path.name).find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); + overlappingPath = paths.find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); return overlappingPath !== undefined; }); if (subMatch) { diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index 65b5b01910..b0e2a08bf6 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -27,7 +27,6 @@ export const supportedDatasources = { }, ], alias: 'Aurora Serverless', - defaultValuesFilename: 'appSync-rds-defaults.js', serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index 99cc2e128b..70734fee70 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -122,7 +122,6 @@ export const supportedServices = { }, ], alias: 'GraphQL', - defaultValuesFilename: 'appSync-defaults.js', serviceWalkthroughFilename: 'appSync-walkthrough.js', cfnFilename: 'appSync-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', @@ -148,9 +147,7 @@ export const supportedServices = { }, ], alias: 'REST', - defaultValuesFilename: 'apigw-defaults.js', serviceWalkthroughFilename: 'apigw-walkthrough.js', - cfnFilename: 'apigw-cloudformation-template-default.json.ejs', provider: 'awscloudformation', }, }; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 5a69dbb23d..30baf56b86 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -4,7 +4,7 @@ "outDir": "lib", "rootDir": "src", "strict": false, // because package has been converted from js - "allowJs": true + "allowJs": false }, "exclude": [ "coverage", @@ -12,6 +12,8 @@ "resources/awscloudformation/lambdas", "resources/awscloudformation/container-templates", "resources/awscloudformation/graphql-lambda-authorizer", + "resources/awscloudformation/overrides-resource", + "scripts", "src/__tests__" ], "references": [ From cd1715176d240323eb97f0bb6b8e6cac3c93711b Mon Sep 17 00:00:00 2001 From: jhockett Date: Wed, 3 Nov 2021 16:24:22 -0700 Subject: [PATCH 487/587] fix: broken path on build-override --- .../provider-utils/awscloudformation/apigw-input-state.ts | 1 - .../service-walkthroughs/apigw-walkthrough.ts | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) 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 index c155b40cf9..758850e5a8 100644 --- 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 @@ -129,7 +129,6 @@ export class ApigwInputState { return; } const deprecatedParametersFileName = 'api-params.json'; - console.log('DEBUG', this.projectRootPath, AmplifyCategories.API, this.resourceName); const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); const deprecatedParametersFilePath = join(resourceDirPath, deprecatedParametersFileName); let deprecatedParameters: $TSObject; 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 index 38f61d5289..049a09ed4f 100644 --- 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 @@ -463,12 +463,14 @@ async function findDependsOn(paths: $TSObject[]) { function getAuthResourceName(): string { const meta = stateManager.getMeta(); - const authResources = (meta?.auth || []).filter(resource => resource.service === AmplifySupportedService.COGNITO); + const authResources = (Object.entries(meta?.auth) || []).filter( + ([_, resource]: [key: string, resource: $TSObject]) => 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].resourceName; + const [authResourceName] = authResources[0]; return authResourceName; } From 839d852196eac97181435f460b380696ea28b066 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Wed, 3 Nov 2021 22:41:57 -0700 Subject: [PATCH 488/587] fix: pushing multiple APIs at a time (#8663) --- .../src/commands/api/override.ts | 2 +- .../awscloudformation/apigw-input-state.ts | 13 ++----------- .../cdk-stack-builder/apigw-stack-transform.ts | 4 ++-- .../src/provider-utils/awscloudformation/index.ts | 10 +++++----- .../service-walkthroughs/apigw-walkthrough.ts | 7 ++++++- 5 files changed, 16 insertions(+), 20 deletions(-) diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts index a7d1047636..b5c57c0bef 100644 --- a/packages/amplify-category-api/src/commands/api/override.ts +++ b/packages/amplify-category-api/src/commands/api/override.ts @@ -54,7 +54,7 @@ export const run = async (context: $TSContext) => { throw 'To be implemented'; } else if (service === AmplifySupportedService.APIGW) { // Migration logic goes in here - const apigwInputState = ApigwInputState.getInstance(context, selectedResourceName); + const apigwInputState = new ApigwInputState(context, selectedResourceName); if (!apigwInputState.cliInputsFileExists()) { if (await prompter.yesOrNo('File migration required to continue. Do you want to continue?', true)) { await apigwInputState.migrateApigwResource(selectedResourceName); 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 index 758850e5a8..0eb42cb4b3 100644 --- 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 @@ -17,22 +17,13 @@ import { ApigwInputs, ApigwStackTransform, CrudOperation, Path, PermissionSettin import { ApigwWalkthroughReturnPromise } from './service-walkthrough-types/apigw-types'; export class ApigwInputState { - private static instance: ApigwInputState; projectRootPath: string; resourceName: string; paths: { [pathName: string]: Path }; - private constructor(private readonly context: $TSContext, resourceName?: string) { + constructor(private readonly context: $TSContext, resourceName?: string) { this.projectRootPath = pathManager.findProjectRoot(); this.resourceName = resourceName; - ApigwInputState.instance = this; - } - - public static getInstance(context: $TSContext, resourceName?: string) { - if (!ApigwInputState.instance) { - new ApigwInputState(context, resourceName); - } - return ApigwInputState.instance; } public addAdminQueriesResource = async (adminQueriesProps: AdminQueriesProps) => { @@ -214,7 +205,7 @@ export class ApigwInputState { stateManager.setResourceParametersJson(this.projectRootPath, AmplifyCategories.API, this.resourceName, {}); - const stack = new ApigwStackTransform(this.context, this.resourceName); + const stack = new ApigwStackTransform(this.context, this.resourceName, this); await stack.transform(); } 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 index 75f7794429..924ad98e4c 100644 --- 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 @@ -28,12 +28,12 @@ export class ApigwStackTransform { cfnInputParams!: {}; resourceName: string; - constructor(context: $TSContext, resourceName: string) { + 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 = ApigwInputState.getInstance(context, this.resourceName); + this.cliInputsState = cliInputState ?? new ApigwInputState(context, resourceName); this.cliInputs = this.cliInputsState.getCliInputPayload(); this.cliInputsState.isCLIInputsValid(); } diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index f4563957d0..f8e36add0f 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -21,7 +21,7 @@ export async function addAdminQueriesApi( context: $TSContext, apiProps: { apiName: string; functionName: string; authResourceName: string; dependsOn: $TSObject[] }, ) { - const apigwInputState = ApigwInputState.getInstance(context, apiProps.apiName); + const apigwInputState = new ApigwInputState(context, apiProps.apiName); return apigwInputState.addAdminQueriesResource(apiProps); } @@ -29,13 +29,13 @@ export async function updateAdminQueriesApi( context: $TSContext, apiProps: { apiName: string; functionName: string; authResourceName: string; dependsOn: $TSObject[] }, ) { - const apigwInputState = ApigwInputState.getInstance(context, apiProps.apiName); + const apigwInputState = new ApigwInputState(context, apiProps.apiName); // Check for migration if (!apigwInputState.cliInputsFileExists()) { await apigwInputState.migrateAdminQueries(apiProps); } else { - return apigwInputState.addAdminQueriesResource(apiProps); + return apigwInputState.updateAdminQueriesResource(apiProps); } } @@ -79,7 +79,7 @@ async function addNonContainerResource(context: $TSContext, service: string, opt } return apiName; case AmplifySupportedService.APIGW: - const apigwInputState = ApigwInputState.getInstance(context); + const apigwInputState = new ApigwInputState(context); return apigwInputState.addApigwResource(serviceWalkthroughPromise, options); default: return legacyAddResource(serviceWalkthroughPromise, context, category, service, options); @@ -263,7 +263,7 @@ async function updateNonContainerResource(context: $TSContext, service: string) case AmplifySupportedService.APPSYNC: return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); default: - const apigwInputState = ApigwInputState.getInstance(context); + const apigwInputState = new ApigwInputState(context); return apigwInputState.updateApigwResource(updateWalkthroughPromise); } } 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 index 049a09ed4f..860e748aa2 100644 --- 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 @@ -151,6 +151,11 @@ async function askApiName(context: $TSContext, defaultResourceName: string) { 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); @@ -585,7 +590,7 @@ async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { } export async function migrate(context: $TSContext, projectPath: string, resourceName: string) { - const apigwInputState = ApigwInputState.getInstance(context, resourceName); + const apigwInputState = new ApigwInputState(context, resourceName); return apigwInputState.migrateApigwResource(resourceName); } From edc04adbbff53d777dc4937581bbec9b7ca3016f Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 4 Nov 2021 08:50:05 -0700 Subject: [PATCH 489/587] fix: capitalization for filter, e2e test (#8667) * fix: capitalization for filter * test: fix prompt wait text --- .../cdk-stack-builder/apigw-stack-transform.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 924ad98e4c..7e5a682d32 100644 --- 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 @@ -41,7 +41,7 @@ export class ApigwStackTransform { async transform() { let authResourceName: string; if (this.resourceName === 'AdminQueries') { - [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter(resourceName => resourceName !== 'UserPoolGroups'); + [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter(resourceName => resourceName !== 'userPoolGroups'); } // Generate cloudformation stack from cli-inputs.json From 24d02faae31543e7f84100bf71b117383a1144d8 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Thu, 4 Nov 2021 16:31:12 -0700 Subject: [PATCH 490/587] fix: stack generation logic when multiple paths ref same Lambda (#8673) --- .../cdk-stack-builder/apigw-stack-builder.ts | 40 ++++++++++--------- .../apigw-stack-transform.ts | 32 ++++++++------- .../service-walkthroughs/apigw-walkthrough.ts | 2 +- 3 files changed, 41 insertions(+), 33 deletions(-) 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 index 2d42d8cb4b..085021435b 100644 --- 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 @@ -78,7 +78,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw */ addCfnParameter(props: cdk.CfnParameterProps, logicalId: string): void { if (this._cfnParameterMap.has(logicalId)) { - throw new Error('logical id already exists'); + throw new Error(`logical id "${logicalId}" already exists`); } this._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); } @@ -196,6 +196,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw }; private _constructCfnPaths(resourceName: string) { + const addedFunctionPermissions = new Set(); for (const [pathName, path] of Object.entries(this._props.paths)) { let lambdaPermissionLogicalId: string; if (resourceName === 'AdminQueries') { @@ -207,23 +208,26 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; } - this.addLambdaPermissionCfnResource( - { - 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, - ); + if (addedFunctionPermissions.has(path.lambdaFunction)) { + addedFunctionPermissions.add(path.lambdaFunction); + this.addLambdaPermissionCfnResource( + { + 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, + ); + } } } 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 index 7e5a682d32..a7ec91c018 100644 --- 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 @@ -76,21 +76,25 @@ export class ApigwStackTransform { } // Add Parameters + const addedFunctions = new Set(); for (const path of Object.values(this.cliInputs.paths)) { - 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`, - ); + 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( 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 index 860e748aa2..dea104bcc0 100644 --- 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 @@ -338,7 +338,7 @@ async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, async function askCRUD(userType: string, permissions: string[] = []) { const crudOptions = ['create', 'read', 'update', 'delete']; - const crudAnswers = await prompter.pick<'many', string>(`What permissions do you want to grant to ${userType}`, crudOptions, { + const crudAnswers = await prompter.pick<'many', string>(`What permissions do you want to grant to ${userType} users?`, crudOptions, { returnSize: 'many', initial: permissions.map(p => crudOptions.indexOf(p)), }); From 893aeb2a7bae87ad844faa47a22bb7c20c595f6a Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Fri, 5 Nov 2021 10:15:13 -0700 Subject: [PATCH 491/587] Apigw revert (#8690) * Revert "fix: stack generation logic when multiple paths ref same Lambda (#8673)" This reverts commit 67b7ebc6c8ead2161697ac99a8e74f3b1b1587f6. * Revert "fix: capitalization for filter, e2e test (#8667)" This reverts commit 97aa7b63afdd04880b9c4d6cd5d6587d297dc562. * Revert "fix: pushing multiple APIs at a time (#8663)" This reverts commit 139d06769aa1ec00cf3630212d9fc2805d1c36e5. * Revert "fix: broken path on build-override" This reverts commit 76428a8a7c630cfae053bdb8b8cfe4d4bcf7fe53. * Revert "feat: extensibility for REST APIs (#8598)" This reverts commit a6eb339c47ded4748893023ed4a733d0fbcdd8cc. --- packages/amplify-category-api/.npmignore | 1 - packages/amplify-category-api/package.json | 9 +- ...w-cloudformation-template-default.json.ejs | 512 ++++++++++++++ .../overrides-resource/APIGW/override.ts | 8 - .../overrides-resource/APIGW/package.json | 17 - .../overrides-resource/APIGW/tsconfig.json | 11 - .../APIGW/tsconfig.resource.json | 13 - .../APIGatewayCLIInputs.schema.json | 68 -- .../scripts/generateApiSchemas.ts | 14 - ...test.ts => add-graphql-datasource.test.js} | 4 +- .../cfn-api-artifact-handler.test.ts | 48 +- .../legacy-add-resource.test.ts | 19 +- .../legacy-update-resource.test.ts | 15 +- .../appSync-walkthrough.test.ts | 40 +- .../utils/rest-api-path-utils.test.ts | 8 +- .../amplify-category-api/src/commands/api.ts | 60 -- .../commands/api/add-graphql-datasource.ts | 256 +++---- .../src/commands/api/add.js | 75 ++ .../src/commands/api/add.ts | 64 -- .../src/commands/api/console.js | 25 + .../src/commands/api/console.ts | 24 - .../src/commands/api/gql-compile.js | 20 + .../src/commands/api/gql-compile.ts | 22 - .../src/commands/api/override.ts | 70 -- .../src/commands/api/push.js | 17 + .../src/commands/api/push.ts | 17 - .../src/commands/api/rebuild.ts | 5 +- .../src/commands/api/remove.js | 31 + .../src/commands/api/remove.ts | 32 - .../src/commands/api/update.js | 29 + .../src/commands/api/update.ts | 30 - packages/amplify-category-api/src/index.ts | 128 ++-- .../awscloudformation/apigw-input-state.ts | 240 ------- .../awscloudformation/aws-constants.ts | 4 +- .../cdk-stack-builder/apigw-stack-builder.ts | 406 ----------- .../apigw-stack-transform.ts | 201 ------ .../cdk-stack-builder/index.ts | 3 - .../cdk-stack-builder/types.ts | 53 -- .../cfn-api-artifact-handler.ts | 40 +- .../awscloudformation/containers-handler.ts | 45 +- .../{apigw-defaults.ts => apigw-defaults.js} | 8 +- ...ppSync-defaults.ts => appSync-defaults.js} | 9 +- .../default-values/containers-defaults.ts | 8 +- .../awscloudformation/docker-compose/index.ts | 4 +- .../awscloudformation/ecs-alb-stack.ts | 2 +- .../provider-utils/awscloudformation/index.ts | 178 +++-- .../awscloudformation/legacy-add-resource.ts | 20 +- .../legacy-update-resource.ts | 19 +- .../aPIGateway-user-input-types.ts | 37 - .../service-walkthrough-types/apigw-types.ts | 28 - .../service-walkthroughs/apigw-walkthrough.ts | 659 +++++++++++------- .../appSync-rds-walkthrough.ts | 33 +- .../appSync-walkthrough.ts | 197 +++--- .../containers-walkthrough.ts | 27 +- .../utils/amplify-meta-utils.ts | 24 +- .../utils/containers-artifacts.ts | 21 +- .../utils/dynamic-imports.ts | 14 +- .../utils/edit-schema-flow.ts | 20 +- .../utils/print-api-key-warnings.ts | 14 +- .../utils/rest-api-path-utils.ts | 4 +- .../provider-utils/supported-datasources.ts | 1 + .../src/provider-utils/supported-services.ts | 3 + packages/amplify-category-api/tsconfig.json | 4 +- 63 files changed, 1706 insertions(+), 2312 deletions(-) create mode 100644 packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs delete mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts 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/schemas/aPIGateway/APIGatewayCLIInputs.schema.json delete mode 100644 packages/amplify-category-api/scripts/generateApiSchemas.ts rename packages/amplify-category-api/src/__tests__/commands/api/{add-graphql-datasource.test.ts => add-graphql-datasource.test.js} (87%) delete mode 100644 packages/amplify-category-api/src/commands/api.ts create mode 100644 packages/amplify-category-api/src/commands/api/add.js delete mode 100644 packages/amplify-category-api/src/commands/api/add.ts create mode 100644 packages/amplify-category-api/src/commands/api/console.js delete mode 100644 packages/amplify-category-api/src/commands/api/console.ts create mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.js delete mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.ts delete mode 100644 packages/amplify-category-api/src/commands/api/override.ts create mode 100644 packages/amplify-category-api/src/commands/api/push.js delete mode 100644 packages/amplify-category-api/src/commands/api/push.ts create mode 100644 packages/amplify-category-api/src/commands/api/remove.js delete mode 100644 packages/amplify-category-api/src/commands/api/remove.ts create mode 100644 packages/amplify-category-api/src/commands/api/update.js delete mode 100644 packages/amplify-category-api/src/commands/api/update.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/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 rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{apigw-defaults.ts => apigw-defaults.js} (68%) rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{appSync-defaults.ts => appSync-defaults.js} (71%) 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 diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore index 3af03e1d7c..89eeb1ee92 100644 --- a/packages/amplify-category-api/.npmignore +++ b/packages/amplify-category-api/.npmignore @@ -1,6 +1,5 @@ **/__mocks__/** **/__tests__/** ./src -!resources/overrides-resource/tsconfig.json tsconfig.json tsconfig.tsbuildinfo diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4d0cc890b1..ed50de180e 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { - "name": "@aws-amplify/amplify-category-api", - "version": "1.0.0", + "name": "amplify-category-api", + "version": "2.33.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -14,8 +14,7 @@ "build": "tsc", "watch": "tsc -w", "clean": "rimraf lib tsconfig.tsbuildinfo", - "test": "jest", - "generateSchemas": "ts-node ./scripts/generateApiSchemas.ts" + "test": "jest" }, "dependencies": { "@aws-amplify/graphql-transformer-migrator": "0.2.0", @@ -80,7 +79,7 @@ "js-yaml": "^4.0.0", "lodash": "^4.17.21", "ora": "^4.0.3", - "uuid": "^8.3.2" + "uuid": "^3.4.0" }, "devDependencies": { "@types/js-yaml": "^4.0.0" diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs new file mode 100644 index 0000000000..959fb43c00 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs @@ -0,0 +1,512 @@ +{ + "AWSTemplateFormatVersion": "2010-09-09", + "Description": "API Gateway resource stack creation using Amplify CLI", + <% if (props.dependsOn) { %> + "Parameters": { + "env": { + "Type": "String" + }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> + <% 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": { + <% for(var i=0; i < props.paths.length; i++) { %> + <%if (props.paths[i].privacy && props.paths[i].privacy.userPoolGroups) { %> + <% let selectedUserPoolGroupList = Object.keys(props.paths[i].privacy.userPoolGroups); %> + <% for(var j=0; j < selectedUserPoolGroupList.length; j++) { %> + "<%=selectedUserPoolGroupList[j]%>Group<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>Policy": { + "DependsOn": [ + "<%= props.apiName %>" + ], + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyName": "<%= props.apiName %>-<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>-<%=selectedUserPoolGroupList[j]%>-group-policy", + "Roles": [ + { + "Fn::Join": [ + "", + [ + { + "Ref": "auth<%= props.authResourceName%>UserPoolId" + }, + "-<%=selectedUserPoolGroupList[j]%>GroupRole" + ] + ] + } + ], + "PolicyDocument": { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": [ + "execute-api:Invoke" + ], + "Resource": [ + + <% for(var x=0; x < props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length; x++) { %> + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", + "<%= props.paths[i].policyResourceName %>/*" + ] + ] + }, + { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/", + { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", + "<%= props.paths[i].policyResourceName %>" + ] + ] + } + <% if (x !== props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length - 1) { %> + , + <% } %> + <% } %> + ] + } + ] + } + } + }, + <% } %> + <% } %> + <% } %> + "<%= props.apiName %>": { + "Type": "AWS::ApiGateway::RestApi", + "Properties": { + "Description": "", + "Name": "<%= props.apiName %>", + "Body": { + "swagger": "2.0", + "info": { + "version": "2018-05-24T17:52:00Z", + "title": "<%= props.apiName %>" + }, + "host": { + "Fn::Join": [ + "", + [ + "apigateway.", + { + "Ref": "AWS::Region" + }, + ".amazonaws.com" + ] + ] + }, + "basePath": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "/Prod", + { + "Fn::Join": [ + "", + [ + "/", + { + "Ref": "env" + } + ] + ] + } + ] + }, + "schemes": [ + "https" + ], + "paths": { + <% for(var i=0; i < props.paths.length; i++) { %> + "<%= props.paths[i].name %>": { + "options": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "200 response", + "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,X-Amz-User-Agent'", + "method.response.header.Access-Control-Allow-Origin": "'*'" + } + } + }, + "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" + } + } + }, + <%if (!props.paths[i].privacy.open) { %> + "security": [ + { + "sigv4": [] + } + ], + <% } %> + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + <% if (props.paths[i].lambdaArn ) { %> + "<%= props.paths[i].lambdaArn %>", + <% } else { %> + { + + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" + }, + <% } %> + "/invocations" + ] + ] + }, + "passthroughBehavior": "when_no_match", + "httpMethod": "POST", + "type": "aws_proxy" + } + } + }, + "<%= props.paths[i].name %>/{proxy+}": { + "options": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "responses": { + "200": { + "description": "200 response", + "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,X-Amz-User-Agent'", + "method.response.header.Access-Control-Allow-Origin": "'*'" + } + } + }, + "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" + } + } + }, + <%if (!props.paths[i].privacy.open) { %> + "security": [ + { + "sigv4": [] + } + ], + <% } %> + "x-amazon-apigateway-integration": { + "responses": { + "default": { + "statusCode": "200" + } + }, + "uri": { + "Fn::Join": [ + "", + [ + "arn:aws:apigateway:", + { + "Ref": "AWS::Region" + }, + ":lambda:path/2015-03-31/functions/", + <% if (props.paths[i].lambdaArn) { %> + "<%= props.paths[i].lambdaArn %>", + <% } else { %> + { + + "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" + }, + <% } %> + "/invocations" + ] + ] + }, + "passthroughBehavior": "when_no_match", + "httpMethod": "POST", + "type": "aws_proxy" + } + } + }<% if (i !== props.paths.length - 1) { %>,<% } %> + <% } %> + }, + "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" + } + } + }, + "FailOnWarnings": true + } + }, + + <%if (props.functionArns) { %> + <% for (var i=0; i < props.functionArns.length; i++) { %> + + "function<%= props.functionArns[i].lambdaFunction.replace(/[^0-9a-zA-Z]/gi, '') %>Permission<%= props.apiName %>": { + "Type": "AWS::Lambda::Permission", + "Properties": { + "FunctionName": <% if (props.functionArns[i].lambdaArn) {%> "<%= props.functionArns[i].lambdaArn %>", <% } else { %> + { + "Ref": "function<%= props.functionArns[i].lambdaFunction %>Name" + }, + <% } %> + "Action": "lambda:InvokeFunction", + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Join": [ + "", + [ + "arn:aws:execute-api:", + { + "Ref": "AWS::Region" + }, + ":", + { + "Ref": "AWS::AccountId" + }, + ":", + { + "Ref": "<%= props.apiName %>" + }, + "/*/*/*" + ] + ] + } + } + }, + <% } %> + <% } %> + + "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { + "Type": "AWS::ApiGateway::Deployment", + "Properties": { + "Description": "The Development stage deployment of your API.", + "StageName": { + "Fn::If": [ + "ShouldNotCreateEnvResources", + "Prod", + { + "Ref": "env" + } + ] + }, + "RestApiId": { + "Ref": "<%= props.apiName %>" + } + } + } + }, + "Outputs": { + "RootUrl": { + "Description": "Root URL of the API gateway", + "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} + }, + "ApiName": { + "Description": "API Friendly name", + "Value": "<%= props.resourceName %>" + }, + "ApiId": { + "Description": "API ID (prefix of API URL)", + "Value": {"Ref": "<%= props.apiName %>"} + } + } + } diff --git a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts deleted file mode 100644 index ac3781476a..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts +++ /dev/null @@ -1,8 +0,0 @@ -// This file is used to override the REST API resource configuration -// import { AmplifyApigwResourceTemplate } from '@aws-amplify/cli-overrides-helper'; - -/* TODO: Need to change props to Root-Stack specific props when props are ready */ -export function overrideProps(props: any) { - /* Override props (AmplifyApigwResourceTemplate) with new parameters */ - return props; -} 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 61f6fd48bc..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "overrides-for-root-stack", - "version": "1.0.0", - "description": "", - "scripts": { - "build": "tsc", - "watch": "tsc -w", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "dependencies": { - "fs-extra": "^9.1.0" - }, - "devDependencies": { - "@types/fs-extra": "^9.0.11", - "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/schemas/aPIGateway/APIGatewayCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json deleted file mode 100644 index a0b2cbe39b..0000000000 --- a/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json +++ /dev/null @@ -1,68 +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": "array", - "items": { - "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#" -} diff --git a/packages/amplify-category-api/scripts/generateApiSchemas.ts b/packages/amplify-category-api/scripts/generateApiSchemas.ts deleted file mode 100644 index e611a1a84b..0000000000 --- a/packages/amplify-category-api/scripts/generateApiSchemas.ts +++ /dev/null @@ -1,14 +0,0 @@ -import * as SchemaGenerator from 'amplify-cli-core'; - -type TypeDef = SchemaGenerator.TypeDef; - -const ApigwTypeDef: TypeDef = { - typeName: 'APIGatewayCLIInputs', - service: 'API Gateway', -}; - -// Defines the type names and the paths to the TS files that define them -const apigwCategoryTypeDefs: TypeDef[] = [ApigwTypeDef]; - -const schemaGenerator = new SchemaGenerator.CLIInputSchemaGenerator(apigwCategoryTypeDefs); -schemaGenerator.generateJSONSchemas(); // convert CLI input data into json schemas. 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.js similarity index 87% rename from packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts rename to packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js index b0acae414d..701aadaa8c 100644 --- 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.js @@ -1,5 +1,5 @@ -import { readSchema } from '../../../commands/api/add-graphql-datasource'; -import * as path from 'path'; +const { readSchema } = require('../../../commands/api/add-graphql-datasource'); +const path = require('path'); describe('read schema', () => { it('Valid schema present in folder', async () => { 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 index 1d3cbeefbf..e8dfa51770 100644 --- 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 @@ -1,23 +1,19 @@ -import { $TSContext, pathManager, stateManager } from 'amplify-cli-core'; +import path from 'path'; +import fs from 'fs-extra'; +import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; +import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from 'amplify-prompts'; -import * as fs from 'fs-extra'; -import { writeTransformerConfiguration } from 'graphql-transformer-core'; -import _ from 'lodash'; -import * as path from 'path'; import { category } from '../../../category-constants'; -import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; +import { writeTransformerConfiguration } from 'graphql-transformer-core'; import { rootAssetDir } from '../../../provider-utils/awscloudformation/aws-constants'; -import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; import { - authConfigHasApiKey, - getAppSyncAuthConfig, getAppSyncResourceName, + getAppSyncAuthConfig, + authConfigHasApiKey, } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +import _ from 'lodash'; jest.mock('fs-extra'); -const printer_mock = printer as jest.Mocked; -printer_mock.warn = jest.fn(); jest.mock('graphql-transformer-core', () => ({ readTransformerConfiguration: jest.fn(async () => ({})), @@ -34,26 +30,32 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', jest.mock('amplify-cli-core'); -const backendDirPathStub = 'backendDirPath'; -const testApiName = 'testApiName'; - -const pathManager_mock = pathManager as jest.Mocked; -pathManager_mock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); -const stateManager_mock = stateManager as jest.Mocked; - const fs_mock = fs as unknown as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; +const backendDirPathStub = 'backendDirPath'; + +const testApiName = 'testApiName'; + const context_stub = { + print: { + success: jest.fn(), + warning: jest.fn(), + }, amplify: { updateamplifyMetaAfterResourceAdd: jest.fn(), updateamplifyMetaAfterResourceUpdate: jest.fn(), updateBackendConfigAfterResourceUpdate: jest.fn(), executeProviderUtils: jest.fn(), copyBatch: jest.fn(), + getProjectMeta: jest.fn(), + readJsonFile: jest.fn(), + pathManager: { + getBackendDirPath: jest.fn(() => backendDirPathStub), + }, }, }; @@ -78,7 +80,7 @@ describe('create artifacts', () => { }); beforeEach(() => { jest.clearAllMocks(); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); }); it('does not create a second API if one already exists', async () => { @@ -178,7 +180,7 @@ describe('update artifacts', () => { beforeEach(() => { jest.clearAllMocks(); updateRequestStub = _.cloneDeep(updateRequestStubBase); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); }); it('throws error if no GQL API in project', () => { @@ -234,12 +236,12 @@ describe('update artifacts', () => { it('prints warning when adding API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(printer_mock.warn.mock.calls.length).toBe(2); + expect(context_stub.print.warning.mock.calls.length).toBe(2); }); it('prints warning when removing API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(printer_mock.warn.mock.calls.length).toBe(3); + expect(context_stub.print.warning.mock.calls.length).toBe(3); }); }); 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 index ada52d192c..4dc7ed152f 100644 --- 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 @@ -1,29 +1,22 @@ import { legacyAddResource } from '../../../provider-utils/awscloudformation/legacy-add-resource'; import { category } from '../../../category-constants'; -import { $TSAny, $TSContext } from 'amplify-cli-core'; jest.mock('fs-extra'); -jest.mock('amplify-cli-core', () => ({ - isResourceNameUnique: jest.fn().mockReturnValue(true), - JSONUtilities: { - readJson: jest.fn(), - writeJson: jest.fn(), - }, - pathManager: { - getResourceDirectoryPath: jest.fn(_ => 'mock/backend/path'), - }, -})); +jest.mock('amplify-cli-core'); describe('legacy add resource', () => { const contextStub = { amplify: { + pathManager: { + getBackendDirPath: jest.fn(_ => 'mock/backend/path'), + }, updateamplifyMetaAfterResourceAdd: jest.fn(), copyBatch: jest.fn(), }, }; it('sets policy resource name in paths object before copying template', async () => { - const stubWalkthroughPromise: Promise<$TSAny> = Promise.resolve({ + const stubWalkthroughPromise: Promise = Promise.resolve({ answers: { resourceName: 'mockResourceName', paths: [ @@ -36,7 +29,7 @@ describe('legacy add resource', () => { ], }, }); - await legacyAddResource(stubWalkthroughPromise, contextStub as unknown as $TSContext, category, 'API Gateway', {}); + await legacyAddResource(stubWalkthroughPromise, contextStub, 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 index cf6e04f21f..135f62250f 100644 --- 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 @@ -1,21 +1,14 @@ -import { $TSContext } from 'amplify-cli-core'; import { legacyUpdateResource } from '../../../provider-utils/awscloudformation/legacy-update-resource'; import { category } from '../../../category-constants'; jest.mock('fs-extra'); -jest.mock('amplify-cli-core', () => ({ - JSONUtilities: { - readJson: jest.fn(), - writeJson: jest.fn(), - }, - pathManager: { - getResourceDirectoryPath: jest.fn(_ => 'mock/backend/path'), - }, -})); describe('legacy update resource', () => { const contextStub = { amplify: { + pathManager: { + getBackendDirPath: jest.fn(_ => 'mock/backend/path'), + }, updateamplifyMetaAfterResourceUpdate: jest.fn(), copyBatch: jest.fn(), }, @@ -35,7 +28,7 @@ describe('legacy update resource', () => { ], }, }); - await legacyUpdateResource(stubWalkthroughPromise, contextStub as unknown as $TSContext, category, 'API Gateway'); + await legacyUpdateResource(stubWalkthroughPromise, contextStub, category, 'API Gateway'); expect(contextStub.amplify.copyBatch.mock.calls[0][2]).toMatchSnapshot(); }); }); 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 index 9b2db83f7b..6e6a75c8d8 100644 --- 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 @@ -1,51 +1,42 @@ -import { $TSAny, $TSContext, FeatureFlags, pathManager, stateManager } from 'amplify-cli-core'; import { - askAdditionalAuthQuestions, getIAMPolicies, + askAdditionalAuthQuestions, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; - +import { FeatureFlags } from 'amplify-cli-core'; jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), })); jest.mock('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); +const context_stub = (prompt: jest.Mock) => ({ + prompt: { + confirm: prompt, + }, + amplify: { + getProjectMeta: jest.fn(), + }, +}); type IAMArtifact = { attributes: string[]; - policy: $TSAny; + 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']); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -58,7 +49,7 @@ describe('get IAM policies', () => { it('includes API key if it exists', async () => { mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -72,7 +63,7 @@ describe('get IAM policies', () => { 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']); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query', 'Mutate'], context_stub(confirmPromptFalse_mock)); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -82,11 +73,10 @@ describe('get IAM policies', () => { 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']); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['create', 'update'], context_stub(confirmPromptFalse_mock)); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", 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 index 6facce6d56..7c82402f42 100644 --- 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 @@ -4,7 +4,7 @@ import { formatCFNPathParamsForExpressJs, } from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; -const stubOtherPaths = ['/other/path', '/sub/path', '/path/{with}/{params}']; +const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }, { name: '/path/{with}/{params}' }]; test('validatePathName_validPath', () => { expect(validatePathName('/some/path')).toBe(true); @@ -56,9 +56,9 @@ test('checkForPathOverlap_subPathParamsNoMatch', () => { }); test('checkForPathOverlap_pathMatch', () => { - expect(checkForPathOverlap(stubOtherPaths[0], stubOtherPaths)).toEqual({ - higherOrderPath: stubOtherPaths[0], - lowerOrderPath: stubOtherPaths[0], + expect(checkForPathOverlap(stubOtherPaths[0].name, stubOtherPaths)).toEqual({ + higherOrderPath: stubOtherPaths[0].name, + lowerOrderPath: stubOtherPaths[0].name, }); }); 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 d9741de9a9..0000000000 --- a/packages/amplify-category-api/src/commands/api.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import * as path from 'path'; - -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: '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', - }, - ]; - - 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 index b9a235b802..d4bd9be8d8 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -1,169 +1,171 @@ -import { mergeTypeDefs } from '@graphql-tools/merge'; -import { $TSAny, $TSContext, exitOnNextTick, FeatureFlags, pathManager, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; +import * as path from 'path'; import * as graphql from 'graphql'; +import _ from 'lodash'; +import inquirer from 'inquirer'; import { - AuroraServerlessMySQLDatabaseReader, RelationalDBSchemaTransformer, RelationalDBTemplateGenerator, + AuroraServerlessMySQLDatabaseReader, } from 'graphql-relational-schema-transformer'; -import inquirer from 'inquirer'; -import _ from 'lodash'; -import * as path from 'path'; +import { mergeTypeDefs } from '@graphql-tools/merge'; +import { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick, $TSAny, $TSContext, stateManager, pathManager } from 'amplify-cli-core'; const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; const providerName = 'awscloudformation'; -export const name = subcommand; +module.exports = { + name: subcommand, + run: async (context: $TSContext) => { + try { + const servicesMetadata = (await import('../../provider-utils/supported-datasources')).supportedDatasources; -export const run = async (context: $TSContext) => { - try { - const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; - const AWS = await getAwsClient(context, 'list'); + const AWS = await getAwsClient(context, 'list'); - const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); + const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); - const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); + const providerController = await import(`../../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); + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } - const { resourceName, databaseName } = answers; + const { datasource } = result; + const answers = await providerController.addDatasource(context, category, datasource); + + const { resourceName, databaseName } = answers; + + /** + * Write the new env specific datasource information into + * the team-provider-info file + */ + const currEnv = context.amplify.getEnvInfo().envName; + const teamProviderInfo = stateManager.getTeamProviderInfo(); + + _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { + rdsRegion: answers.region, + rdsClusterIdentifier: answers.dbClusterArn, + rdsSecretStoreArn: answers.secretStoreArn, + rdsDatabaseName: answers.databaseName, + }); + + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); + + 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 instrospection to get the GraphQL Schema and Template Context + */ + const improvePluralizationFlag = FeatureFlags.getBoolean('graphqltransformer.improvePluralization'); + const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName, improvePluralizationFlag); + const graphqlSchemaContext = await relationalSchemaTransformer.introspectDatabaseSchema(); + + if (graphqlSchemaContext === null) { + context.print.warning('No importable tables were found in the selected Database.'); + context.print.info(''); + return; + } - /** - * Write the new env specific datasource information into - * the team-provider-info file - */ - const currEnv = context.amplify.getEnvInfo().envName; - const teamProviderInfo = stateManager.getTeamProviderInfo(); + /** + * Merge the GraphQL Schema with the existing schema.graphql in the projects stack + * + */ + const apiDirPath = path.join(pathManager.getBackendDirPath(), category, resourceName); - _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { - rdsRegion: answers.region, - rdsClusterIdentifier: answers.dbClusterArn, - rdsSecretStoreArn: answers.secretStoreArn, - rdsDatabaseName: answers.databaseName, - }); + fs.ensureDirSync(apiDirPath); - stateManager.setTeamProviderInfo(undefined, teamProviderInfo); - - 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 instrospection to get the GraphQL Schema and Template Context - */ - 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.info(''); - return; - } + const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); + const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; + const schemaDirectoryPath = path.join(apiDirPath, 'schema'); - /** - * Merge the GraphQL Schema with the existing schema.graphql in the projects stack - * - */ - const apiDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); + if (fs.existsSync(graphqlSchemaFilePath)) { + const typesToBeMerged = [rdsGraphQLSchemaDoc]; + const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - fs.ensureDirSync(apiDirPath); + if (currGraphQLSchemaDoc) { + typesToBeMerged.unshift(currGraphQLSchemaDoc); + } else { + context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); + context.print.info(''); + } - const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); - const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const schemaDirectoryPath = path.join(apiDirPath, 'schema'); + const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); - if (fs.existsSync(graphqlSchemaFilePath)) { - const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); + } else if (fs.existsSync(schemaDirectoryPath)) { + const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); - if (currGraphQLSchemaDoc) { - typesToBeMerged.unshift(currGraphQLSchemaDoc); + fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); } else { - printer.warn(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); - printer.info(''); + throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); } - const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); + const resolversDir = path.join(apiDirPath, 'resolvers'); - fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); - } else if (fs.existsSync(schemaDirectoryPath)) { - const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); + /** + * Instantiate a new Relational Template Generator and create + * the template and relational resolvers + */ - fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); - } else { - throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); - } + const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); - const resolversDir = path.join(apiDirPath, 'resolvers'); + let template = templateGenerator.createTemplate(context); - /** - * Instantiate a new Relational Template Generator and create - * the template and relational resolvers - */ + template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); - const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); + const cfn = templateGenerator.printCloudformationTemplate(template); - let template = templateGenerator.createTemplate(context); + /** + * Add the generated the CFN to the appropriate nested stacks directory + */ - template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); + const stacksDir = path.join(apiDirPath, 'stacks'); + const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); - const cfn = templateGenerator.printCloudformationTemplate(template); + fs.writeFileSync(writeToPath, cfn, 'utf8'); - /** - * Add the generated the CFN to the appropriate nested stacks directory - */ + context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); - const stacksDir = path.join(apiDirPath, 'stacks'); - const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); + context.print.success(`Successfully added the ${datasource} datasource locally`); + context.print.info(''); + context.print.success('Some next steps:'); + context.print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); + context.print.info( + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', + ); + context.print.info(''); + } catch (error) { + context.print.info(error.stack); + context.print.error('There was an error adding the datasource'); - fs.writeFileSync(writeToPath, cfn, 'utf8'); + await context.usageData.emitError(error); - 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.info(error.stack); - printer.error('There was an error adding the datasource'); - - await context.usageData.emitError(error); - - process.exitCode = 1; - } + process.exitCode = 1; + } + }, + readSchema, }; -async function datasourceSelectionPrompt(context: $TSContext, supportedDatasources) { +async function datasourceSelectionPrompt(context, supportedDatasources) { const options = []; Object.keys(supportedDatasources).forEach(datasource => { const optionName = @@ -182,7 +184,7 @@ async function datasourceSelectionPrompt(context: $TSContext, supportedDatasourc if (options.length === 0) { const errMessage = `No datasources defined by configured providers for category: ${category}`; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -191,7 +193,7 @@ async function datasourceSelectionPrompt(context: $TSContext, supportedDatasourc if (options.length === 1) { // No need to ask questions - printer.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); + context.print.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); return new Promise(resolve => { resolve(options[0].value); @@ -217,7 +219,7 @@ async function getAwsClient(context: $TSContext, action: string) { return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); } -export function readSchema(graphqlSchemaFilePath: string) { +function readSchema(graphqlSchemaFilePath) { const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); if (graphqlSchemaRaw.trim().length === 0) { diff --git a/packages/amplify-category-api/src/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js new file mode 100644 index 0000000000..d883208b45 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/add.js @@ -0,0 +1,75 @@ +const inquirer = require('inquirer'); +const subcommand = 'add'; +const category = 'api'; +const apiGatewayService = 'API Gateway'; + +let options; + +module.exports = { + name: subcommand, + run: async context => { + const { amplify } = context; + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(async result => { + options = { + service: result.service, + providerPlugin: result.providerName, + }; + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.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, category, result.service, options); + }) + .then(resourceName => { + const { print } = context; + print.success(`Successfully added resource ${resourceName} locally`); + print.info(''); + print.success('Some next steps:'); + print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); + print.info( + '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', + ); + print.info(''); + }) + .catch(err => { + context.print.info(err.stack); + context.print.error('There was an error adding the API resource'); + context.usageData.emitError(err); + process.exitCode = 1; + }); + }, +}; + +async function shouldUpdateExistingRestApi(context, selectedService) { + if (selectedService !== apiGatewayService) { + return false; + } + + const { allResources } = await context.amplify.getResourceStatus(); + const hasRestApis = allResources.some(resource => resource.service === apiGatewayService && resource.mobileHubMigrated !== true); + + if (!hasRestApis) { + return false; + } + + const question = [ + { + name: 'update', + message: 'Would you like to add a new path to an existing REST API:', + type: 'confirm', + default: true, + }, + ]; + const answer = await inquirer.prompt(question); + + return answer.update; +} 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 bf2f64e8c2..0000000000 --- a/packages/amplify-category-api/src/commands/api/add.ts +++ /dev/null @@ -1,64 +0,0 @@ -import { $TSContext, $TSObject, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; -import * as path from 'path'; - -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.info(err.stack); - printer.error('There was an error adding the API resource'); - await context.usageData.emitError(err); - process.exitCode = 1; - }); -}; - -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: $TSObject) => 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.js b/packages/amplify-category-api/src/commands/api/console.js new file mode 100644 index 0000000000..a8bc4d57bc --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/console.js @@ -0,0 +1,25 @@ +const subcommand = 'console'; +const category = 'api'; + +module.exports = { + name: subcommand, + run: async context => { + const { amplify } = context; + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(async result => { + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + throw new Error(`Provider "${result.providerName}" is not configured for this category`); + } + return await providerController.console(context, result.service); + }) + .catch(err => { + context.print.error('Error opening console.'); + context.print.info(err.message); + context.usageData.emitError(err); + process.exitCode = 1; + }); + }, +}; 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 2e2430047b..0000000000 --- a/packages/amplify-category-api/src/commands/api/console.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import * as path from 'path'; - -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.'); - printer.info(err.message); - await context.usageData.emitError(err); - process.exitCode = 1; - } -}; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.js b/packages/amplify-category-api/src/commands/api/gql-compile.js new file mode 100644 index 0000000000..a53e64d0fe --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/gql-compile.js @@ -0,0 +1,20 @@ +const subcommand = 'gql-compile'; + +module.exports = { + name: subcommand, + run: async context => { + try { + const { + parameters: { options }, + } = context; + await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + forceCompile: true, + minify: options['minify'], + }); + } catch (err) { + context.print.error(err.toString()); + context.usageData.emitError(err); + process.exitCode = 1; + } + }, +}; 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 bcbbfba4f8..0000000000 --- a/packages/amplify-category-api/src/commands/api/gql-compile.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { $TSContext } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; - -const subcommand = 'gql-compile'; - -export const name = subcommand; - -export const run = async (context: $TSContext) => { - try { - const { - parameters: { options }, - } = context; - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - forceCompile: true, - minify: options['minify'], - }); - } catch (err) { - printer.error(err.toString()); - await context.usageData.emitError(err); - process.exitCode = 1; - } -}; 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 b5c57c0bef..0000000000 --- a/packages/amplify-category-api/src/commands/api/override.ts +++ /dev/null @@ -1,70 +0,0 @@ -import { - $TSContext, - AmplifyCategories, - AmplifySupportedService, - generateOverrideSkeleton, - pathManager, - stateManager, -} from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; -import * as path from 'path'; -import { ApigwInputState } from '../../provider-utils/awscloudformation/apigw-input-state'; -import { ApigwStackTransform } from '../../provider-utils/awscloudformation/cdk-stack-builder'; - -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) { - throw 'To be implemented'; - } else if (service === AmplifySupportedService.APIGW) { - // Migration logic goes in here - const apigwInputState = new ApigwInputState(context, selectedResourceName); - if (!apigwInputState.cliInputsFileExists()) { - if (await prompter.yesOrNo('File migration required to continue. Do you want to continue?', true)) { - await apigwInputState.migrateApigwResource(selectedResourceName); - const stackGenerator = new ApigwStackTransform(context, selectedResourceName); - stackGenerator.transform(); - } else { - return; - } - } - } - - await generateOverrideSkeleton(context, srcPath, destPath); -}; diff --git a/packages/amplify-category-api/src/commands/api/push.js b/packages/amplify-category-api/src/commands/api/push.js new file mode 100644 index 0000000000..8a0da0bb5a --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/push.js @@ -0,0 +1,17 @@ +const subcommand = 'push'; +const category = 'api'; + +module.exports = { + name: subcommand, + run: async context => { + const { amplify, parameters } = context; + const resourceName = parameters.first; + context.amplify.constructExeInfo(context); + return amplify.pushResources(context, category, resourceName).catch(err => { + context.print.error('There was an error pushing the API resource'); + context.print.error(err.toString()); + context.usageData.emitError(err); + process.exitCode = 1; + }); + }, +}; 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 ce32110c1c..0000000000 --- a/packages/amplify-category-api/src/commands/api/push.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; - -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).catch(async err => { - printer.error('There was an error pushing the API resource'); - printer.error(err.toString()); - await context.usageData.emitError(err); - process.exitCode = 1; - }); -}; diff --git a/packages/amplify-category-api/src/commands/api/rebuild.ts b/packages/amplify-category-api/src/commands/api/rebuild.ts index 55c269da95..26b8ead364 100644 --- a/packages/amplify-category-api/src/commands/api/rebuild.ts +++ b/packages/amplify-category-api/src/commands/api/rebuild.ts @@ -1,7 +1,8 @@ -import { $TSAny, $TSContext, AmplifyCategories, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; import { printer, prompter, exact } from 'amplify-prompts'; const subcommand = 'rebuild'; +const category = 'api'; export const name = subcommand; @@ -35,5 +36,5 @@ export const run = async (context: $TSContext) => { const { amplify, parameters } = context; const resourceName = parameters.first; amplify.constructExeInfo(context); - return amplify.pushResources(context, AmplifyCategories.API, resourceName, undefined, rebuild); + return amplify.pushResources(context, category, resourceName, undefined, rebuild); }; diff --git a/packages/amplify-category-api/src/commands/api/remove.js b/packages/amplify-category-api/src/commands/api/remove.js new file mode 100644 index 0000000000..8c334611a5 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/remove.js @@ -0,0 +1,31 @@ +const path = require('path'); + +const subcommand = 'remove'; +const category = 'api'; +const gqlConfigFilename = '.graphqlconfig.yml'; + +module.exports = { + name: subcommand, + run: async context => { + const { amplify, parameters } = context; + const resourceName = parameters.first; + + return amplify + .removeResource(context, category, resourceName) + .then(resourceValues => { + if (!resourceValues) return; // indicates that the customer selected "no" at the confirmation prompt + if (resourceValues.service === 'AppSync') { + const { projectPath } = amplify.getEnvInfo(); + + const gqlConfigFile = path.normalize(path.join(projectPath, gqlConfigFilename)); + context.filesystem.remove(gqlConfigFile); + } + }) + .catch(err => { + context.print.info(err.stack); + context.print.error('There was an error removing the api resource'); + context.usageData.emitError(err); + process.exitCode = 1; + }); + }, +}; 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 ac67429d87..0000000000 --- a/packages/amplify-category-api/src/commands/api/remove.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { $TSContext, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import * as path from 'path'; - -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.info(err.stack); - printer.error('There was an error removing the api resource'); - await context.usageData.emitError(err); - process.exitCode = 1; - } -}; diff --git a/packages/amplify-category-api/src/commands/api/update.js b/packages/amplify-category-api/src/commands/api/update.js new file mode 100644 index 0000000000..03dbb328f1 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/update.js @@ -0,0 +1,29 @@ +const subcommand = 'update'; +const category = 'api'; + +module.exports = { + name: subcommand, + alias: ['configure'], + run: async context => { + const { amplify } = context; + const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; + + return amplify + .serviceSelectionPrompt(context, category, servicesMetadata) + .then(result => { + const providerController = require(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + context.print.error('Provider not configured for this category'); + return; + } + return providerController.updateResource(context, category, result.service); + }) + .then(() => context.print.success('Successfully updated resource')) + .catch(err => { + context.print.error(err.message); + console.log(err.stack); + context.usageData.emitError(err); + process.exitCode = 1; + }); + }, +}; 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 8813a045be..0000000000 --- a/packages/amplify-category-api/src/commands/api/update.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import * as path from 'path'; - -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')) - .catch(async err => { - printer.error(err.message); - printer.info(err.stack); - await context.usageData.emitError(err); - process.exitCode = 1; - }); -}; diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index f556148476..4ada1ab74d 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -1,57 +1,42 @@ -import { - $TSContext, - $TSObject, - AmplifyCategories, - AmplifySupportedService, - buildOverrideDir, - pathManager, - stateManager, -} from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; -import * as fs from 'fs-extra'; -import * as path from 'path'; +import fs from 'fs-extra'; +import path from 'path'; import { run } from './commands/api/console'; -import { getAppSyncAuthConfig, getAppSyncResourceName } 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 { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; 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'; -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 { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; +export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; export { - ApiResource, generateContainersArtifacts, + ApiResource, processDockerConfig, } from './provider-utils/awscloudformation/utils/containers-artifacts'; -export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; +export { getContainers } from './provider-utils/awscloudformation/docker-compose'; +export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; + +const category = 'api'; -const category = AmplifyCategories.API; const categories = 'categories'; -export async function console(context: $TSContext) { +export async function console(context) { await run(context); } -export async function migrate(context: $TSContext, serviceName?: string) { - const { projectPath } = context.migrationInfo; - const amplifyMeta = stateManager.getMeta(); +export async function migrate(context, serviceName) { + const { projectPath, amplifyMeta } = context.migrationInfo; const migrateResourcePromises = []; - for (const categoryName of Object.keys(amplifyMeta)) { + Object.keys(amplifyMeta).forEach(categoryName => { if (categoryName === category) { - for (const resourceName of Object.keys(amplifyMeta[category])) { + Object.keys(amplifyMeta[category]).forEach(resourceName => { try { if (amplifyMeta[category][resourceName].providerPlugin) { - const providerController = await import( - path.join('.', 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') - ); + const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( @@ -60,20 +45,20 @@ export async function migrate(context: $TSContext, serviceName?: string) { } } } else { - printer.error(`Provider not configured for ${category}: ${resourceName}`); + context.print.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - printer.warn(`Could not run migration for ${category}: ${resourceName}`); + context.print.warning(`Could not run migration for ${category}: ${resourceName}`); throw e; } - } + }); } - } + }); await Promise.all(migrateResourcePromises); } -export async function initEnv(context: $TSContext) { +export async function initEnv(context) { const datasource = 'Aurora Serverless'; const service = 'service'; const rdsInit = 'rdsInit'; @@ -88,7 +73,7 @@ export async function initEnv(context: $TSContext) { * Check if we need to do the walkthrough, by looking to see if previous environments have * configured an RDS datasource */ - const backendConfigFilePath = pathManager.getBackendConfigFilePath(); + const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); // If this is a mobile hub migrated project without locally added resources then there is no // backend config exists yet. @@ -96,7 +81,7 @@ export async function initEnv(context: $TSContext) { return; } - const backendConfig = stateManager.getBackendConfig(); + const backendConfig = amplify.readJsonFile(backendConfigFilePath); if (!backendConfig[category]) { return; @@ -104,9 +89,9 @@ export async function initEnv(context: $TSContext) { let resourceName; const apis = Object.keys(backendConfig[category]); - for (const api of apis) { - if (backendConfig[category][api][service] === AmplifySupportedService.APPSYNC) { - resourceName = api; + for (let i = 0; i < apis.length; i += 1) { + if (backendConfig[category][apis[i]][service] === 'AppSync') { + resourceName = apis[i]; break; } } @@ -121,10 +106,10 @@ export async function initEnv(context: $TSContext) { return; } - const providerController = await import(path.join('.', 'provider-utils', provider, 'index')); + const providerController = require('./provider-utils/awscloudformation/index'); if (!providerController) { - printer.error('Provider not configured for this category'); + context.print.error('Provider not configured for this category'); return; } @@ -132,7 +117,8 @@ export async function initEnv(context: $TSContext) { * Check team provider info to ensure it hasn't already been created for current env */ const currEnv = amplify.getEnvInfo().envName; - const teamProviderInfo = stateManager.getTeamProviderInfo(); + const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); + const teamProviderInfo = amplify.readJsonFile(teamProviderInfoFilePath); if ( teamProviderInfo[currEnv][categories] && teamProviderInfo[currEnv][categories][category] && @@ -167,15 +153,16 @@ export async function initEnv(context: $TSContext) { teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; - stateManager.setTeamProviderInfo(undefined, teamProviderInfo); + fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); }) .then(() => { context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); }); } -export async function getPermissionPolicies(context: $TSContext, resourceOpsMapping: $TSObject) { - const amplifyMeta = stateManager.getMeta(); +export async function getPermissionPolicies(context, resourceOpsMapping) { + const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); + const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); const permissionPolicies = []; const resourceAttributes = []; @@ -184,7 +171,7 @@ export async function getPermissionPolicies(context: $TSContext, resourceOpsMapp try { const providerName = amplifyMeta[category][resourceName].providerPlugin; if (providerName) { - const providerController = await import(path.join('.', 'provider-utils', providerName, 'index')); + const providerController = require(`./provider-utils/${providerName}/index`); const { policy, attributes } = await providerController.getPermissionPolicies( context, amplifyMeta[category][resourceName].service, @@ -194,10 +181,10 @@ export async function getPermissionPolicies(context: $TSContext, resourceOpsMapp permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); } else { - printer.error(`Provider not configured for ${category}: ${resourceName}`); + context.print.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - printer.warn(`Could not get policies for ${category}: ${resourceName}`); + context.print.warning(`Could not get policies for ${category}: ${resourceName}`); throw e; } }), @@ -205,7 +192,7 @@ export async function getPermissionPolicies(context: $TSContext, resourceOpsMapp return { permissionPolicies, resourceAttributes }; } -export async function executeAmplifyCommand(context: $TSContext) { +export async function executeAmplifyCommand(context) { let commandPath = path.normalize(path.join(__dirname, 'commands')); if (context.input.command === 'help') { commandPath = path.join(commandPath, category); @@ -213,11 +200,11 @@ export async function executeAmplifyCommand(context: $TSContext) { commandPath = path.join(commandPath, category, context.input.command); } - const commandModule = await import(commandPath); + const commandModule = require(commandPath); await commandModule.run(context); } -export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => { +export const executeAmplifyHeadlessCommand = async (context, headlessPayload: string) => { switch (context.input.command) { case 'add': await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); @@ -226,24 +213,23 @@ export const executeAmplifyHeadlessCommand = async (context: $TSContext, headles await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); break; default: - printer.error(`Headless mode for ${context.input.command} api is not implemented yet`); + context.print.error(`Headless mode for ${context.input.command} api is not implemented yet`); } }; -export async function handleAmplifyEvent(context: $TSContext, args) { - printer.info(`${category} handleAmplifyEvent to be implemented`); - printer.info(`Received event args ${args}`); +export async function handleAmplifyEvent(context, args) { + context.print.info(`${category} handleAmplifyEvent to be implemented`); + context.print.info(`Received event args ${args}`); } -export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TSObject) { +export async function addGraphQLAuthorizationMode(context, args) { const { authType, printLeadText, authSettings } = args; - const meta = stateManager.getMeta(); - const apiName = getAppSyncResourceName(meta); + const apiName = getAppSyncResourceName(context.amplify.getProjectMeta()); if (!apiName) { return; } - const authConfig = getAppSyncAuthConfig(meta); + const authConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); const addAuthConfig = await askAuthQuestions(authType, context, printLeadText, authSettings); authConfig.additionalAuthenticationProviders.push(addAuthConfig); await context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); @@ -264,23 +250,3 @@ export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TS return addAuthConfig; } - -export async function transformCategoryStack(context: $TSContext, resource: $TSObject) { - if (resource.service === AmplifySupportedService.APIGW) { - if (canResourceBeTransformed(resource.resourceName)) { - const backendDir = pathManager.getBackendDirPath(); - const overrideDir = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, resource.resourceName); - await buildOverrideDir(backendDir, overrideDir).catch(error => { - printer.debug(`Skipping build as ${error.message}`); - return false; - }); - // Rebuild CFN - const apigwStack = new ApigwStackTransform(context, resource.resourceName); - apigwStack.transform(); - } - } -} - -function canResourceBeTransformed(resourceName: string) { - return stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); -} 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 0eb42cb4b3..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts +++ /dev/null @@ -1,240 +0,0 @@ -import { - $TSContext, - $TSObject, - AmplifyCategories, - AmplifySupportedService, - CLIInputSchemaValidator, - isResourceNameUnique, - JSONUtilities, - PathConstants, - pathManager, - stateManager, -} from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; -import * as fs from 'fs-extra'; -import { join } from 'path'; -import { ApigwInputs, ApigwStackTransform, CrudOperation, Path, PermissionSetting } from './cdk-stack-builder'; -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, - }; - - await 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(); - - await this.context.amplify.updateamplifyMetaAfterResourceUpdate( - AmplifyCategories.API, - adminQueriesProps.apiName, - 'dependsOn', - adminQueriesProps.dependsOn, - ); - }; - - public addApigwResource = async (serviceWalkthroughPromise: ApigwWalkthroughReturnPromise, options: $TSObject) => { - 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<$TSObject>) => { - const { answers } = await updateWalkthroughPromise; - - this.resourceName = answers.resourceName; - this.paths = answers.paths; - - // this.addPolicyResourceNameToPaths(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.confirmContinue(`Migration for ${this.resourceName} is required. Continue?`))) { - return; - } - const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - - this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - this.context.filesystem.remove(join(resourceDirPath, 'admin-queries-cloudformation-template.json')); - - return this.updateAdminQueriesResource(adminQueriesProps); - }; - - public migrateApigwResource = async (resourceName: string) => { - this.resourceName = this.resourceName ?? resourceName; - if (!(await prompter.confirmContinue(`Migration for ${this.resourceName} is required. Continue?`))) { - return; - } - const deprecatedParametersFileName = 'api-params.json'; - const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - const deprecatedParametersFilePath = join(resourceDirPath, deprecatedParametersFileName); - let deprecatedParameters: $TSObject; - try { - deprecatedParameters = JSONUtilities.readJson<$TSObject>(deprecatedParametersFilePath); - } catch (e) { - printer.error(`Error reading ${deprecatedParametersFileName} file for ${this.resourceName} resource`); - throw e; - } - - this.paths = {}; - - function convertDeprecatedPermissionToCRUD(deprecatedPrivacy: string) { - let privacyList: string[]; - if (deprecatedPrivacy === 'r') { - privacyList = [CrudOperation.READ]; - } else if (deprecatedPrivacy === 'rw') { - privacyList = [CrudOperation.CREATE, CrudOperation.READ, CrudOperation.UPDATE, CrudOperation.DELETE]; - } - return privacyList; - } - - deprecatedParameters.paths.forEach((path: $TSObject) => { - let pathPermissionSetting = - path.privacy.open === true - ? PermissionSetting.OPEN - : path.privacy.private === true - ? PermissionSetting.PRIVATE - : PermissionSetting.PROTECTED; - - let auth; - let guest; - // convert deprecated permissions to CRUD structure - if (path.privacy.auth && ['r', 'rw'].includes(path.privacy.auth)) { - auth = convertDeprecatedPermissionToCRUD(path.privacy.auth); - } - if (path.privacy.unauth && ['r', 'rw'].includes(path.privacy.unauth)) { - auth = convertDeprecatedPermissionToCRUD(path.privacy.unauth); - } - - this.paths[path.name] = { - permissions: { - setting: pathPermissionSetting, - auth, - guest, - }, - lambdaFunction: path.lambdaFunction, - }; - }); - - await this.createApigwArtifacts(); - - this.context.filesystem.remove(deprecatedParametersFilePath); - this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - this.context.filesystem.remove(join(resourceDirPath, PathConstants.CfnFileName(this.resourceName))); - }; - - public cliInputsFileExists() { - return stateManager.resourceInputsJsonExists(this.projectRootPath, AmplifyCategories.API, this.resourceName); - } - - public getCliInputPayload() { - return stateManager.getResourceInputsJson(this.projectRootPath, AmplifyCategories.API, this.resourceName); - } - - public isCLIInputsValid(cliInputs?: ApigwInputs) { - if (!cliInputs) { - cliInputs = this.getCliInputPayload(); - } - - const schemaValidator = new CLIInputSchemaValidator(AmplifySupportedService.APIGW, AmplifyCategories.API, 'APIGatewayCLIInputs'); - 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(); - } - - convertCrudOperationsToPermissions(crudOps: CrudOperation[]) { - const output = []; - for (const op of crudOps) { - switch (op) { - case CrudOperation.CREATE: - output.push('/POST'); - break; - case CrudOperation.READ: - output.push('/GET'); - break; - case CrudOperation.UPDATE: - output.push('/PUT'); - output.push('/PATCH'); - break; - case CrudOperation.DELETE: - output.push('/DELETE'); - break; - } - } - return output; - } -} - -type AdminQueriesProps = { - apiName: string; - functionName: string; - authResourceName: string; - dependsOn: $TSObject[]; -}; 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 index 418b53b47f..824a2cafef 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts @@ -1,8 +1,8 @@ -import * as path from 'path'; +import 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')); +export const rootAssetDir = path.resolve(path.join(__dirname, '../../../resources/awscloudformation')); 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 085021435b..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts +++ /dev/null @@ -1,406 +0,0 @@ -import * as apigw from '@aws-cdk/aws-apigateway'; -import * as lambda from '@aws-cdk/aws-lambda'; -import * as cdk from '@aws-cdk/core'; -import { $TSObject, JSONUtilities } from 'amplify-cli-core'; -import { AmplifyApigwResourceTemplate, ApigwInputs, ApigwPathPolicy } 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 { - _scope: cdk.Construct; - restApi!: apigw.CfnRestApi; - deploymentResource: apigw.CfnDeployment; - _lambdaPermission: lambda.CfnPermission; - _props: ApigwInputs; - paths: $TSObject; - policies: { [pathName: string]: ApigwPathPolicy }; - _cfnParameterMap: Map = new Map(); - - constructor(scope: cdk.Construct, id: string, props: ApigwInputs) { - super(scope, id, undefined); - this._scope = scope; - this._props = props; - this.paths = {}; - this.templateOptions.templateFormatVersion = CFN_TEMPLATE_FORMAT_VERSION; - this.templateOptions.description = ROOT_CFN_DESCRIPTION; - } - - /** - * - * @param props - * @param logicalId - */ - addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void { - new cdk.CfnOutput(this, logicalId, props); - } - - /** - * - * @param props - * @param logicalId - */ - addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void { - new cdk.CfnMapping(this, logicalId, props); - } - - /** - * - * @param props - * @param logicalId - */ - addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void { - new cdk.CfnCondition(this, logicalId, props); - } - - /** - * - * @param props - * @param logicalId - */ - addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void { - new cdk.CfnResource(this, logicalId, props); - } - - /** - * - * @param props - * @param logicalId - */ - addLambdaPermissionCfnResource(props: lambda.CfnPermissionProps, logicalId: string): void { - new lambda.CfnPermission(this, logicalId, props); - } - - /** - * - * @param props - * @param logicalId - */ - addCfnParameter(props: cdk.CfnParameterProps, logicalId: string): void { - if (this._cfnParameterMap.has(logicalId)) { - throw new Error(`logical id "${logicalId}" already exists`); - } - this._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); - } - - renderCloudFormationTemplate = (): string => { - return JSONUtilities.stringify(this._toCloudFormation()); - }; - - generateAdminQueriesStack = (resourceName: string, authResourceName: string) => { - this._constructCfnPaths(resourceName); - - this.restApi = new apigw.CfnRestApi(this, resourceName, { - description: '', // TODO - left blank in current CLI - 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: '', // TODO - left blank in current CLI - 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', - }, - }, - }, - }); - - this._setDeploymentResource(resourceName); - }; - - private _constructCfnPaths(resourceName: string) { - const addedFunctionPermissions = new Set(); - for (const [pathName, path] of Object.entries(this._props.paths)) { - let lambdaPermissionLogicalId: string; - if (resourceName === 'AdminQueries') { - this.paths[`/{proxy+}`] = getAdminQueriesPathObject(path.lambdaFunction); - lambdaPermissionLogicalId = 'AdminQueriesAPIGWPolicyForLambda'; - } else { - this.paths[pathName] = getDefaultPathObject(path.lambdaFunction); - this.paths[`${pathName}/{proxy+}`] = getDefaultPathObject(path.lambdaFunction); - lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; - } - - if (addedFunctionPermissions.has(path.lambdaFunction)) { - addedFunctionPermissions.add(path.lambdaFunction); - this.addLambdaPermissionCfnResource( - { - 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 = (resourceName: string) => { - this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}`, { - restApiId: cdk.Fn.ref(resourceName), - stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), - }); - }; -} - -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 getDefaultPathObject = (lambdaFunctionName: string) => ({ - 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${lambdaFunctionName}Arn`), - '/invocations', - ]), - passthroughBehavior: 'when_no_match', - httpMethod: 'POST', - type: 'aws_proxy', - }, - }, -}); - -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 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 a7ec91c018..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts +++ /dev/null @@ -1,201 +0,0 @@ -import * as cdk from '@aws-cdk/core'; -import { - $TSAny, - $TSContext, - AmplifyCategories, - buildOverrideDir, - getAmplifyResourceByCategories, - JSONUtilities, - PathConstants, - pathManager, - stateManager, - Template, - writeCFNTemplate, -} from 'amplify-cli-core'; -import { formatter, printer } from 'amplify-prompts'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { AmplifyApigwResourceStack, ApigwInputs } from '.'; -import { category } from '../../../category-constants'; -import { ApigwInputState } from '../apigw-input-state'; - -export class ApigwStackTransform { - _app: cdk.App; - cliInputs: ApigwInputs; - resourceTemplateObj: AmplifyApigwResourceStack | undefined; - cliInputsState: ApigwInputState; - cfn!: Template; - cfnInputParams!: {}; - resourceName: string; - - 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(); - this.cliInputsState.isCLIInputsValid(); - } - - async transform() { - let authResourceName: string; - if (this.resourceName === 'AdminQueries') { - [authResourceName] = getAmplifyResourceByCategories(AmplifyCategories.AUTH).filter(resourceName => resourceName !== 'userPoolGroups'); - } - - // Generate cloudformation stack from cli-inputs.json - this.generateStack(authResourceName); - - // Generate cloudformation stack input params from cli-inputs.json - this.generateCfnInputParameters(); - - // Modify cloudformation files based on overrides - await this.applyOverrides(); - - // Save generated cloudformation.json and parameters.json files - await this.saveBuildFiles(); - } - - // TODO generate params - generateCfnInputParameters() { - this.cfnInputParams = {}; - } - - generateStack(authResourceName?: string) { - this.resourceTemplateObj = new AmplifyApigwResourceStack(this._app, 'AmplifyApigwResourceStack', this.cliInputs); - - if (authResourceName) { - this.resourceTemplateObj.addCfnParameter( - { - type: 'String', - default: `auth${authResourceName}UserPoolId`, - }, - `auth${authResourceName}UserPoolId`, - ); - } - - // 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://', - 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 === 'AdminQueries' - ? this.resourceTemplateObj.generateAdminQueriesStack(this.resourceName, authResourceName) - : this.resourceTemplateObj.generateStackResources(this.resourceName); - } - - async applyOverrides() { - const backendDir = pathManager.getBackendDirPath(); - const overrideFilePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); - - const isBuild = await buildOverrideDir(backendDir, overrideFilePath).catch(error => { - printer.debug(`Skipping build as ${error.message}`); - return false; - }); - // skip if packageManager or override.ts not found - if (isBuild) { - const { overrideProps } = await import(path.join(overrideFilePath, 'build', 'override.js')).catch(error => { - formatter.list(['No override file found', `To override ${this.resourceName} run "amplify override api"`]); - return undefined; - }); - - // TODO: Check Script Options - if (overrideProps && typeof overrideProps === 'function') { - try { - this.resourceTemplateObj = overrideProps(this.resourceTemplateObj); - - // The vm module enables compiling and running code within V8 Virtual Machine contexts. - // The vm module is not a security mechanism. Do not use it to run untrusted code. - // const script = new vm.Script(overrideCode); - // script.runInContext(vm.createContext(cognitoStackTemplateObj)); - return; - } catch (error: $TSAny) { - throw new Error(error); - } - } - } - } - - async saveBuildFiles() { - if (this.resourceTemplateObj) { - this.cfn = JSONUtilities.parse(this.resourceTemplateObj.renderCloudFormationTemplate()); - } - - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, 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); - } -} 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 2d01ec4b3f..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/core'; -import * as apigwCdk from '@aws-cdk/aws-apigateway'; -import * as iamCdk from '@aws-cdk/aws-iam'; - -export type ApigwInputs = { - version: number; - paths: 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): 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 index 3b5ed5d8c8..f06fc27941 100644 --- 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 @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { isResourceNameUnique } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, @@ -6,12 +6,11 @@ import { ResolutionStrategy, UpdateApiRequest, } from 'amplify-headless-interface'; -import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; import _ from 'lodash'; import * as path from 'path'; -import { v4 as uuid } from 'uuid'; +import uuid from 'uuid'; import { category } from '../../category-constants'; import { ApiArtifactHandler, ApiArtifactHandlerOptions } from '../api-artifact-handler'; import { cfnParametersFilename, gqlSchemaFilename, provider, rootAssetDir } from './aws-constants'; @@ -23,7 +22,7 @@ import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-c // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; -export const getCfnApiArtifactHandler = (context: $TSContext): ApiArtifactHandler => { +export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { return new CfnApiArtifactHandler(context); }; const resolversDirName = 'resolvers'; @@ -36,17 +35,16 @@ const defaultCfnParameters = (apiName: string) => ({ DynamoDBEnableServerSideEncryption: false, }); class CfnApiArtifactHandler implements ApiArtifactHandler { - private readonly context: $TSContext; + private readonly context: any; - constructor(context: $TSContext) { + constructor(context) { 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); + const existingApiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); if (existingApiName) { throw new Error(`GraphQL API ${existingApiName} already exists in the project. Use 'amplify update api' to make modifications.`); } @@ -100,7 +98,7 @@ class CfnApiArtifactHandler implements 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()); + const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); if (!apiName) { throw new Error(`No AppSync API configured in the project. Use 'amplify add api' to create an API.`); } @@ -112,7 +110,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); await writeResolverConfig(updates.conflictResolution, resourceDir); } - const authConfig = getAppSyncAuthConfig(stateManager.getMeta()); + const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); const oldConfigHadApiKey = authConfigHasApiKey(authConfig); if (updates.defaultAuthType) { authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); @@ -131,14 +129,14 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); + printApiKeyWarnings(this.context, oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; private writeSchema = (resourceDir: string, schema: string) => { fs.writeFileSync(path.join(resourceDir, gqlSchemaFilename), schema); }; - private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); + private getResourceDir = (apiName: string) => path.join(this.context.amplify.pathManager.getBackendDirPath(), category, apiName); private createAmplifyMeta = authConfig => ({ service: 'AppSync', @@ -182,8 +180,8 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private getCfnParameters = (apiName: string, authConfig, resourceDir: string) => { - const cfnPath = path.join(resourceDir, cfnParametersFilename); - const params = JSONUtilities.readJson<$TSAny>(cfnPath, { throwIfNotExist: false }) || defaultCfnParameters(apiName); + const params = + this.context.amplify.readJsonFile(path.join(resourceDir, cfnParametersFilename), undefined, false) || defaultCfnParameters(apiName); const cognitoPool = this.getCognitoUserPool(authConfig); if (cognitoPool) { params.AuthCognitoUserPoolId = cognitoPool; @@ -200,7 +198,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const defaultAuth = authConfig.defaultAuthentication || {}; if (defaultAuth.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { let userPoolId; - const configuredUserPoolName = checkIfAuthExists(); + const configuredUserPoolName = checkIfAuthExists(this.context); if (authConfig.userPoolConfig) { ({ userPoolId } = authConfig.userPoolConfig); @@ -219,7 +217,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private createSyncFunction = async () => { - const targetDir = pathManager.getBackendDirPath(); + const targetDir = this.context.amplify.pathManager.getBackendDirPath(); const assetDir = path.normalize(path.join(rootAssetDir, 'sync-conflict-handler')); const [shortId] = uuid().split('-'); @@ -234,17 +232,17 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { { dir: assetDir, template: 'sync-conflict-handler-index.js.ejs', - target: path.join(targetDir, 'function', functionName, 'src', 'index.js'), + target: `${targetDir}/function/${functionName}/src/index.js`, }, { dir: assetDir, template: 'sync-conflict-handler-package.json.ejs', - target: path.join(targetDir, 'function', functionName, 'src', 'package.json'), + target: `${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`), + target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, }, ]; @@ -258,7 +256,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - printer.success(`Successfully added ${functionName} function locally`); + this.context.print.success(`Successfully added ${functionName} function locally`); return functionName + '-${env}'; }; @@ -270,7 +268,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { * * write to the transformer conf if the resolverConfig is valid */ -export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir: string) => { +export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir) => { const localTransformerConfig = await readTransformerConfiguration(resourceDir); localTransformerConfig.ResolverConfig = conflictResolutionToResolverConfig(conflictResolution); await writeTransformerConfiguration(resourceDir, localTransformerConfig); 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 index 1bc866ab6c..0a402bd123 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts @@ -1,22 +1,22 @@ -import { $TSContext, createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { v4 as uuid } from 'uuid'; +import fs from 'fs-extra'; +import path from 'path'; +import 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'; +import { createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; export const addResource = async ( serviceWalkthroughPromise: Promise, - context: $TSContext, - category: string, + context, + category, service, options, apiType: API_TYPE, ) => { + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const walkthroughOptions = await serviceWalkthroughPromise; const { @@ -31,7 +31,7 @@ export const addResource = async ( dependsOn = [], mutableParametersState, } = walkthroughOptions; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); + const resourceDirPath = path.join(projectBackendDirPath, category, resourceName); let [authName, updatedDependsOn] = await getResourceDependencies({ dependsOn, restrictAccess, category, resourceName, context }); @@ -88,37 +88,36 @@ export const addResource = async ( if (imageSource.type === IMAGE_SOURCE_TYPE.TEMPLATE) { fs.copySync( - path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation/container-templates', imageSource.template), + path.join(__dirname, '../../../resources/awscloudformation/container-templates', imageSource.template), path.join(resourceDirPath, 'src'), - { recursive: true }, + { 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:'); + context.print.success(`Successfully added resource ${resourceName} locally.`); + context.print.info(''); + context.print.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"`, - ); + context.print.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( + context.print.info( `- Ensure you have the Dockerfile, docker-compose.yml and any related container source files in your Github path: ${gitHubInfo.path}`, ); } - printer.info( + context.print.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'); + context.print.info(`- To access AWS resources outside of this Amplify app, edit the ${customPoliciesPath}`); + context.print.info('- Run "amplify push" to build and deploy your image'); return resourceName; }; @@ -132,7 +131,7 @@ const getResourceDependencies = async ({ }: { restrictAccess: boolean; dependsOn: ResourceDependency[]; - context: $TSContext; + context: any; category: string; resourceName: string; }) => { @@ -166,7 +165,7 @@ const getResourceDependencies = async ({ apiRequirements, ]); } catch (e) { - printer.error(e); + context.print.error(e); throw e; } } else { @@ -193,7 +192,7 @@ const getResourceDependencies = async ({ return [authName, updatedDependsOn]; }; -export const updateResource = async (serviceWalkthroughPromise: Promise, context: $TSContext, category: string) => { +export const updateResource = async (serviceWalkthroughPromise: Promise, context, category) => { const options = await serviceWalkthroughPromise; const { 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.js similarity index 68% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js index 60dbcd9da4..7ab876f8fa 100644 --- 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.js @@ -1,6 +1,6 @@ -import { v4 as uuid } from 'uuid'; +const uuid = require('uuid'); -export const getAllDefaults = (project: { projectConfig: { projectName: string } }) => { +const getAllDefaults = project => { const name = project.projectConfig.projectName.toLowerCase().replace(/[^0-9a-zA-Z]/gi, ''); const [shortId] = uuid().split('-'); const defaults = { @@ -11,3 +11,7 @@ export const getAllDefaults = (project: { projectConfig: { projectName: string } return defaults; }; + +module.exports = { + getAllDefaults, +}; 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.js similarity index 71% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js index 8c48966c22..0d5cb71570 100644 --- 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.js @@ -1,7 +1,6 @@ -import { $TSMeta } from 'amplify-cli-core'; -import { v4 as uuid } from 'uuid'; +const uuid = require('uuid'); -export const getAllDefaults = (project: { amplifyMeta: $TSMeta; projectConfig: { projectName: string } }) => { +const getAllDefaults = project => { const name = project.projectConfig.projectName.toLowerCase(); const region = project.amplifyMeta.providers.awscloudformation.Region; const [shortId] = uuid().split('-'); @@ -17,3 +16,7 @@ export const getAllDefaults = (project: { amplifyMeta: $TSMeta; projectConfig: { return defaults; }; + +module.exports = { + getAllDefaults, +}; 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 index 0f77dee83e..da44caf946 100644 --- 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 @@ -1,6 +1,6 @@ -import { v4 as uuid } from 'uuid'; +const uuid = require('uuid'); -export const getAllDefaults = () => { +const getAllDefaults = project => { const [shortId] = uuid().split('-'); const defaults = { resourceName: `container${shortId}`, @@ -8,3 +8,7 @@ export const getAllDefaults = () => { return defaults; }; + +module.exports = { + getAllDefaults, +}; 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 index a66729ca10..39f92df12e 100644 --- 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 @@ -1 +1,3 @@ -export { getContainers } from './converter'; +import { getContainers } from "./converter"; + +export { getContainers }; \ No newline at end of file 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 index 01ca720b38..c66f371960 100644 --- 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 @@ -7,8 +7,8 @@ import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; import * as route53targets from '@aws-cdk/aws-route53-targets'; import * as cdk from '@aws-cdk/core'; -import { v4 as uuid } from 'uuid'; import { ContainersStack, ContainersStackProps } from './base-api-stack'; +import { v4 as uuid } from 'uuid'; type EcsStackProps = ContainersStackProps & Readonly<{ diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index f8e36add0f..4ee7ce6fee 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -1,52 +1,28 @@ -import { $TSAny, $TSContext, $TSObject, AmplifySupportedService, exitOnNextTick, NotImplementedError } from 'amplify-cli-core'; -import { UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from 'amplify-prompts'; -import inquirer from 'inquirer'; -import * as path from 'path'; -import { category } from '../../category-constants'; -import { ApigwInputState } from './apigw-input-state'; +import { serviceWalkthroughResultToAddApiRequest } from './utils/service-walkthrough-result-to-add-api-request'; import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; -import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; +import { serviceMetadataFor, getServiceWalkthrough, datasourceMetadataFor } from './utils/dynamic-imports'; import { legacyAddResource } from './legacy-add-resource'; +import { legacyUpdateResource } from './legacy-update-resource'; +import { UpdateApiRequest } from 'amplify-headless-interface'; +import { editSchemaFlow } from './utils/edit-schema-flow'; +import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; +import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; +import inquirer from 'inquirer'; import { API_TYPE, - getPermissionPolicies as getContainerPermissionPolicies, ServiceConfiguration, + getPermissionPolicies as getContainerPermissionPolicies, } 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: $TSObject[] }, -) { - 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: $TSObject[] }, -) { - const apigwInputState = new ApigwInputState(context, apiProps.apiName); - // Check for migration - - if (!apigwInputState.cliInputsFileExists()) { - await apigwInputState.migrateAdminQueries(apiProps); - } else { - return apigwInputState.updateAdminQueriesResource(apiProps); - } -} +import { category } from '../../category-constants'; -export async function console(context: $TSContext, service: string) { +export async function console(context, service) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { openConsole } = await import(serviceWalkthroughSrc); + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { openConsole } = require(serviceWalkthroughSrc); if (!openConsole) { const errMessage = 'Opening console functionality not available for this option'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -54,23 +30,24 @@ export async function console(context: $TSContext, service: string) { return openConsole(context); } -async function addContainerResource(context: $TSContext, service: string, options, apiType: API_TYPE) { +async function addContainerResource(context, category, service, options, apiType) { const serviceWalkthroughFilename = 'containers-walkthrough.js'; + const defaultValuesFilename = 'containers-defaults.js'; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, apiType); + const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, apiType); return await addContainer(serviceWalkthroughPromise, context, category, service, options, apiType); } -async function addNonContainerResource(context: $TSContext, service: string, options) { +async function addNonContainerResource(context, category, service, options) { const serviceMetadata = await serviceMetadataFor(service); - const { serviceWalkthroughFilename } = serviceMetadata; + const { serviceWalkthroughFilename, defaultValuesFilename } = serviceMetadata; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, serviceMetadata); + const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, serviceMetadata); switch (service) { - case AmplifySupportedService.APPSYNC: + case 'AppSync': const walkthroughResult = await serviceWalkthroughPromise; const askToEdit = walkthroughResult.askToEdit; const apiName = await getCfnApiArtifactHandler(context).createArtifacts(serviceWalkthroughResultToAddApiRequest(walkthroughResult)); @@ -78,26 +55,23 @@ async function addNonContainerResource(context: $TSContext, service: string, opt 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) { +export async function addResource(context, category, service, options) { let useContainerResource = false; let apiType = API_TYPE.GRAPHQL; if (isContainersEnabled(context)) { switch (service) { - case AmplifySupportedService.APPSYNC: - useContainerResource = await isGraphQLContainer(); + case 'AppSync': + useContainerResource = await isGraphQLContainer(context); apiType = API_TYPE.GRAPHQL; break; - case AmplifySupportedService.APIGW: - useContainerResource = await isRestContainer(); + case 'API Gateway': + useContainerResource = await isRestContainer(context); apiType = API_TYPE.REST; break; default: @@ -106,11 +80,11 @@ export async function addResource(context: $TSContext, service: string, options) } return useContainerResource - ? addContainerResource(context, service, options, apiType) - : addNonContainerResource(context, service, options); + ? addContainerResource(context, category, service, options, apiType) + : addNonContainerResource(context, category, service, options); } -function isContainersEnabled(context: $TSContext) { +function isContainersEnabled(context) { const { frontend } = context.amplify.getProjectConfig(); if (frontend) { const { config: { ServerlessContainers = false } = {} } = context.amplify.getProjectConfig()[frontend] || {}; @@ -121,14 +95,14 @@ function isContainersEnabled(context: $TSContext) { return false; } -async function isGraphQLContainer(): Promise { +async function isGraphQLContainer(context): Promise { const { graphqlSelection } = await inquirer.prompt({ name: 'graphqlSelection', message: 'Which service would you like to use', type: 'list', choices: [ { - name: AmplifySupportedService.APPSYNC, + name: 'AppSync', value: false, }, { @@ -141,7 +115,7 @@ async function isGraphQLContainer(): Promise { return graphqlSelection; } -async function isRestContainer() { +async function isRestContainer(context) { const { restSelection } = await inquirer.prompt({ name: 'restSelection', message: 'Which service would you like to use', @@ -161,18 +135,22 @@ async function isRestContainer() { return restSelection; } -export async function updateResource(context: $TSContext, category: string, service: string, options) { +export async function updateResource(context, category, service, 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); + const { + hasAPIGatewayContainerResource, + hasAPIGatewayLambdaResource, + hasGraphQLAppSyncResource, + hasGraphqlContainerResource, + } = await describeApiResourcesBySubCategory(context); switch (service) { - case AmplifySupportedService.APPSYNC: + case 'AppSync': if (hasGraphQLAppSyncResource && hasGraphqlContainerResource) { - useContainerResource = await isGraphQLContainer(); + useContainerResource = await isGraphQLContainer(context); } else if (hasGraphqlContainerResource) { useContainerResource = true; } else { @@ -180,9 +158,9 @@ export async function updateResource(context: $TSContext, category: string, serv } apiType = API_TYPE.GRAPHQL; break; - case AmplifySupportedService.APIGW: + case 'API Gateway': if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { - useContainerResource = await isRestContainer(); + useContainerResource = await isRestContainer(context); } else if (hasAPIGatewayContainerResource) { useContainerResource = true; } else { @@ -195,10 +173,12 @@ export async function updateResource(context: $TSContext, category: string, serv } } - return useContainerResource ? updateContainerResource(context, category, service, apiType) : updateNonContainerResource(context, service); + return useContainerResource + ? updateContainerResource(context, category, service, apiType) + : updateNonContainerResource(context, category, service); } -async function describeApiResourcesBySubCategory(context: $TSContext) { +async function describeApiResourcesBySubCategory(context) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources.filter(resource => resource.category === category && resource.mobileHubMigrated !== true); @@ -211,9 +191,9 @@ async function describeApiResourcesBySubCategory(context: $TSContext) { hasAPIGatewayContainerResource = hasAPIGatewayContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); - hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === AmplifySupportedService.APIGW; + hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === 'API Gateway'; - hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === AmplifySupportedService.APPSYNC; + hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === 'AppSync'; hasGraphqlContainerResource = hasGraphqlContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); @@ -227,32 +207,33 @@ async function describeApiResourcesBySubCategory(context: $TSContext) { }; } -async function updateContainerResource(context: $TSContext, category: string, service: string, apiType: API_TYPE) { +async function updateContainerResource(context, category, service, apiType: API_TYPE) { const serviceWalkthroughFilename = 'containers-walkthrough'; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { updateWalkthrough } = await import(serviceWalkthroughSrc); + const defaultValuesFilename = 'containers-defaults.js'; + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { updateWalkthrough } = require(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } - const updateWalkthroughPromise: Promise = updateWalkthrough(context, apiType); + const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, apiType); updateContainer(updateWalkthroughPromise, context, category); } -async function updateNonContainerResource(context: $TSContext, service: string) { +async function updateNonContainerResource(context, category, service) { const serviceMetadata = await serviceMetadataFor(service); const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { updateWalkthrough } = await import(serviceWalkthroughSrc); + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { updateWalkthrough } = require(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -260,15 +241,14 @@ async function updateNonContainerResource(context: $TSContext, service: string) const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); switch (service) { - case AmplifySupportedService.APPSYNC: + case 'AppSync': return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); default: - const apigwInputState = new ApigwInputState(context); - return apigwInputState.updateApigwResource(updateWalkthroughPromise); + return legacyUpdateResource(updateWalkthroughPromise, context, category, service); } } -export async function migrateResource(context: $TSContext, projectPath: string, service: string, resourceName: string) { +export async function migrateResource(context, projectPath, service, resourceName) { if (service === 'ElasticContainer') { return migrateResourceContainer(context, projectPath, service, resourceName); } else { @@ -276,53 +256,53 @@ export async function migrateResource(context: $TSContext, projectPath: string, } } -async function migrateResourceContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { - printer.info(`No migration required for ${resourceName}`); +async function migrateResourceContainer(context, projectPath, service, resourceName) { + context.print.info(`No migration required for ${resourceName}`); return; } -async function migrateResourceNonContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { +async function migrateResourceNonContainer(context, projectPath, service, resourceName) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { migrate } = await import(serviceWalkthroughSrc); + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { migrate } = require(serviceWalkthroughSrc); if (!migrate) { - printer.info(`No migration required for ${resourceName}`); + context.print.info(`No migration required for ${resourceName}`); return; } return await migrate(context, projectPath, resourceName); } -export async function addDatasource(context: $TSContext, category, datasource) { +export async function addDatasource(context, category, datasource) { const serviceMetadata = await datasourceMetadataFor(datasource); - const { serviceWalkthroughFilename } = serviceMetadata; - return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, serviceMetadata); + const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; + return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, defaultValuesFilename, serviceMetadata); } -export async function getPermissionPolicies(context: $TSContext, service: string, resourceName: string, crudOptions) { +export async function getPermissionPolicies(context, service, resourceName, crudOptions) { if (service === 'ElasticContainer') { return getPermissionPoliciesContainer(context, service, resourceName, crudOptions); } else { - return getPermissionPoliciesNonContainer(service, resourceName, crudOptions); + return getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions); } } -async function getPermissionPoliciesContainer(context: $TSContext, service: string, resourceName: string, crudOptions) { +async function getPermissionPoliciesContainer(context, service, resourceName, crudOptions) { return getContainerPermissionPolicies(context, service, resourceName, crudOptions); } -async function getPermissionPoliciesNonContainer(service: string, resourceName: string, crudOptions: string[]) { +async function getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); - const { getIAMPolicies } = await import(serviceWalkthroughSrc); + const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; + const { getIAMPolicies } = require(serviceWalkthroughSrc); if (!getIAMPolicies) { - printer.info(`No policies found for ${resourceName}`); + context.print.info(`No policies found for ${resourceName}`); return; } - return getIAMPolicies(resourceName, crudOptions); + return getIAMPolicies(resourceName, crudOptions, context); } 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 index 29ced6ba3b..ff7e33a189 100644 --- 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 @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, $TSObject, isResourceNameUnique, JSONUtilities, pathManager } from 'amplify-cli-core'; +import { isResourceNameUnique, JSONUtilities } from 'amplify-cli-core'; import * as fs from 'fs-extra'; import * as path from 'path'; import { cfnParametersFilename, parametersFileName, rootAssetDir } from './aws-constants'; @@ -6,15 +6,10 @@ 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<$TSAny>, - context: $TSContext, - category: string, - service: string, - options: $TSObject, -) => { +export const legacyAddResource = async (serviceWalkthroughPromise: Promise, context, category, service, options) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await serviceWalkthroughPromise; @@ -35,7 +30,7 @@ export const legacyAddResource = async ( copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); isResourceNameUnique(category, parameters.resourceName); @@ -52,14 +47,15 @@ export const legacyAddResource = async ( }; // 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); +export const copyCfnTemplate = (context, category, options, cfnFilename) => { + const { amplify } = context; + const targetDir = amplify.pathManager.getBackendDirPath(); const copyJobs = [ { dir: path.join(rootAssetDir, 'cloudformation-templates'), template: cfnFilename, - target: path.join(resourceDirPath, `${options.resourceName}-cloudformation-template.json`), + target: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, }, ]; 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 index 930523a24a..99a15a9365 100644 --- 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 @@ -1,15 +1,15 @@ -import { $TSAny, $TSContext, JSONUtilities, pathManager } from 'amplify-cli-core'; -import * as fs from 'fs-extra'; -import * as path from 'path'; -import { parametersFileName } from './aws-constants'; -import { addPolicyResourceNameToPaths, copyCfnTemplate } from './legacy-add-resource'; import { serviceMetadataFor } from './utils/dynamic-imports'; +import { copyCfnTemplate, addPolicyResourceNameToPaths } from './legacy-add-resource'; +import fs from 'fs-extra'; +import path from 'path'; +import { parametersFileName } from './aws-constants'; -export const legacyUpdateResource = async (updateWalkthroughPromise: Promise<$TSAny>, context: $TSContext, category: string, service) => { +export const legacyUpdateResource = async (updateWalkthroughPromise: Promise, context, category, service) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await updateWalkthroughPromise; - const options: $TSAny = {}; + const options: any = {}; if (result) { if (result.answers) { ({ answers } = result); @@ -25,10 +25,11 @@ export const legacyUpdateResource = async (updateWalkthroughPromise: Promise<$TS addPolicyResourceNameToPaths(answers.paths); copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; - const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); + const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); fs.ensureDirSync(resourceDirPath); const parametersFilePath = path.join(resourceDirPath, parametersFileName); - JSONUtilities.writeJson(parametersFilePath, parameters); + const jsonString = JSON.stringify(parameters, null, 4); + fs.writeFileSync(parametersFilePath, jsonString, 'utf8'); context.amplify.updateamplifyMetaAfterResourceUpdate(category, answers.resourceName, 'dependsOn', answers.dependsOn); } } 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 f17cb20de1..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 3e53588026..0000000000 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { $TSObject } from 'amplify-cli-core'; -import { CrudOperation, PermissionSetting } from '../cdk-stack-builder'; - -export type ApigwPath = { - name: string; - permissions: { - setting: PermissionSetting; - auth?: CrudOperation[]; - unauth?: CrudOperation[]; - userPoolGroups?: { - [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?: $TSObject[]; -}; 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 index dea104bcc0..ac3390df3e 100644 --- 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 @@ -1,95 +1,113 @@ -import { - $TSAny, - $TSContext, - $TSObject, - AmplifyCategories, - AmplifySupportedService, - exitOnNextTick, - isResourceNameUnique, - open, - pathManager, - ResourceDoesNotExistError, - stateManager, -} from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; +import { $TSContext, exitOnNextTick, isResourceNameUnique, open, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; import inquirer from 'inquirer'; import os from 'os'; -import { v4 as uuid } from 'uuid'; -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 * as path from 'path'; +import uuid from 'uuid'; +import { rootAssetDir } from '../aws-constants'; import { checkForPathOverlap, formatCFNPathParamsForExpressJs, validatePathName } from '../utils/rest-api-path-utils'; -const category = AmplifyCategories.API; -const serviceName = AmplifySupportedService.APIGW; +// keep in sync with ServiceName in amplify-category-function, but probably it will not change +const FunctionServiceNameLambdaFunction = 'Lambda'; + +const category = 'api'; +const serviceName = 'API Gateway'; const elasticContainerServiceName = 'ElasticContainer'; +const parametersFileName = 'api-params.json'; +const cfnParametersFilename = 'parameters.json'; + +export async function serviceWalkthrough(context, defaultValuesFilename) { + const { amplify } = context; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = await import(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); -export async function serviceWalkthrough(context: $TSContext): ApigwWalkthroughReturnPromise { - const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); + let answers = { + paths: [], + }; - const resourceName = await askApiName(context, allDefaultValues.resourceName); - const answers = { paths: {}, resourceName, dependsOn: undefined }; + const apiNames = await askApiNames(context, allDefaultValues); + answers = { ...answers, ...apiNames }; return pathFlow(context, answers); } -export async function updateWalkthrough(context: $TSContext) { +export async function updateWalkthrough(context, defaultValuesFilename) { + const { amplify } = context; const { allResources } = await context.amplify.getResourceStatus(); - const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = await import(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); const resources = allResources .filter(resource => resource.service === serviceName && resource.mobileHubMigrated !== true) .map(resource => resource.resourceName); + // There can only be one appsync resource 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); + const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; } - let answers: $TSAny = { + 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' }, - ]); + const question = [ + { + name: 'resourceName', + message: 'Please select the REST API you would want to update', + type: 'list', + choices: resources, + }, + { + name: 'operation', + message: 'What would you like to do', + type: 'list', + when: context.input.command !== 'add', + choices: [ + { name: 'Add another path', value: 'add' }, + { name: 'Update path', value: 'update' }, + { name: 'Remove path', value: 'remove' }, + ], + }, + ]; + + const updateApi = await inquirer.prompt(question); // 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'; + updateApi.operation = 'add'; } - if (selectedApiName === 'AdminQueries') { + if (updateApi.resourceName === 'AdminQueries') { const errMessage = `The Admin Queries API is maintained through the Auth category and should be updated using 'amplify update auth' command`; - printer.warn(errMessage); + context.print.warning(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } - const projRoot = pathManager.findProjectRoot(); - if (!stateManager.resourceInputsJsonExists(projRoot, category, selectedApiName)) { - // Not yet migrated - console.log(selectedApiName); - await migrate(context, projRoot, selectedApiName); + const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); + const resourceDirPath = path.join(projectBackendDirPath, category, updateApi.resourceName as string); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + let parameters; + try { + parameters = context.amplify.readJsonFile(parametersFilePath); + } catch (e) { + parameters = {}; } - - const parameters = stateManager.getResourceInputsJson(projRoot, category, selectedApiName); - parameters.resourceName = selectedApiName; + parameters.resourceName = updateApi.resourceName; Object.assign(allDefaultValues, parameters); answers = { ...answers, ...parameters }; [answers.uuid] = uuid().split('-'); - const pathNames = Object.keys(answers.paths); + const pathList = answers.paths.map(path => path.name); let updatedResult = {}; - switch (updateApiOperation) { + switch (updateApi.operation) { case 'add': { updatedResult = pathFlow(context, answers); break; @@ -97,52 +115,76 @@ export async function updateWalkthrough(context: $TSContext) { case 'remove': { const pathToRemove = await inquirer.prompt({ name: 'path', - message: 'Select the path you would want to remove', + message: 'Please select the path you would want to remove', type: 'list', - choices: pathNames, + choices: pathList, }); - delete answers.paths[pathToRemove.path]; + answers.paths = answers.paths.filter(path => path.name !== pathToRemove.path); - const { dependsOn, functionArns } = await findDependsOn(answers.paths); + const { dependsOn, functionArns } = await findDependsOn(answers.paths, context); answers.dependsOn = dependsOn; answers.functionArns = functionArns; - updatedResult = { answers }; + updatedResult = { answers, dependsOn }; break; } case 'update': { const pathToEdit = await inquirer.prompt({ - name: 'pathName', - message: 'Select the path you would want to edit', + name: 'path', + message: 'Please select the path you would want to edit', type: 'list', - choices: pathNames, + choices: pathList, }); // removing path from paths list - const currentPath: ApigwPath = answers.paths[pathToEdit.pathName]; - delete answers.paths[pathToEdit.pathName]; + const currentPath = answers.paths.find(path => path.name === pathToEdit.path); + answers.paths = answers.paths.filter(path => path.name !== pathToEdit.path); updatedResult = pathFlow(context, answers, currentPath); break; } default: { - throw new Error(`Unrecognized API update operation "${updateApiOperation}"`); + updatedResult = {}; } } return updatedResult; } -async function pathFlow(context: $TSContext, answers: ApigwAnswers, currentPath?: ApigwPath): ApigwWalkthroughReturnPromise { +async function pathFlow(context, answers, currentPath?) { const pathsAnswer = await askPaths(context, answers, currentPath); + answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; + const { dependsOn } = pathsAnswer; - return { answers: pathsAnswer }; + const privacy = { + auth: pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length, + unauth: pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length, + }; + + answers = { ...answers, privacy, dependsOn }; + + if ( + context.amplify.getProjectDetails() && + context.amplify.getProjectDetails().amplifyMeta && + context.amplify.getProjectDetails().amplifyMeta.providers && + context.amplify.getProjectDetails().amplifyMeta.providers.awscloudformation + ) { + // TODO: read from utility functions (Dustin PR) + const { amplifyMeta } = context.amplify.getProjectDetails(); + const providerInfo = amplifyMeta.providers.awscloudformation; + + answers.privacy.authRoleName = providerInfo.AuthRoleName; + answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; + } + + return { answers, dependsOn }; } -async function askApiName(context: $TSContext, defaultResourceName: string) { +async function askApiNames(context, defaults) { + const { amplify } = context; const apiNameValidator = (input: string) => { - const amplifyValidatorOutput = context.amplify.inputValidation({ + const amplifyValidatorOutput = amplify.inputValidation({ validation: { operator: 'regex', value: '^[a-zA-Z0-9]+$', @@ -151,11 +193,6 @@ async function askApiName(context: $TSContext, defaultResourceName: string) { 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); @@ -165,90 +202,111 @@ async function askApiName(context: $TSContext, defaultResourceName: string) { 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 }, - ); + const answer: { apiName?: string; resourceName: string } = 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: defaults.resourceName, + validate: apiNameValidator, + }, + ]); + + answer.apiName = answer.resourceName; - return resourceName; + return answer; } -async function askPermissions( - context: $TSContext, - answers: $TSObject, - currentPath: ApigwPath, -): Promise<{ setting?: PermissionSetting; auth?: CrudOperation[]; open?: boolean; userPoolGroups?: $TSObject; unauth?: CrudOperation[] }> { +async function askPrivacy(context, answers, currentPath) { while (true) { - const apiAccess = await prompter.yesOrNo('Restrict API access', currentPath?.permissions?.setting !== PermissionSetting.OPEN); + const apiAccess = await inquirer.prompt({ + name: 'restrict', + type: 'confirm', + default: !(currentPath && currentPath.open), + message: 'Restrict API access', + }); - if (!apiAccess) { - return { setting: PermissionSetting.OPEN }; + if (!apiAccess.restrict) { + return { open: true }; } - const userPoolGroupList = context.amplify.getUserPoolGroupList(); + const userPoolGroupList = await context.amplify.getUserPoolGroupList(context); let permissionSelected = 'Auth/Guest Users'; - const permissions: $TSAny = {}; + const privacy: any = {}; 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.', + context.print.info(''); + context.print.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(); + context.print.info(''); } - const permissionSelection = await prompter.pick<'one', string>('Restrict access by?', [ - 'Auth/Guest Users', - 'Individual Groups', - 'Both', - 'Learn more', - ]); - - permissionSelected = permissionSelection; + const permissionSelection = await inquirer.prompt({ + name: 'selection', + type: 'list', + message: 'Restrict access by?', + choices: ['Auth/Guest Users', 'Individual Groups', 'Both', 'Learn more'], + default: 'Auth/Guest Users', + }); + + permissionSelected = permissionSelection.selection; } while (permissionSelected === 'Learn more'); } if (permissionSelected === 'Both' || permissionSelected === 'Auth/Guest Users') { - const permissionSetting = await prompter.pick<'one', string>( - 'Who should have access?', - [ + const answer = await inquirer.prompt({ + name: 'privacy', + type: 'list', + message: 'Who should have access?', + choices: [ { name: 'Authenticated users only', - value: PermissionSetting.PRIVATE, + value: 'private', }, { name: 'Authenticated and Guest users', - value: PermissionSetting.PROTECTED, + value: 'protected', }, ], - { initial: currentPath?.permissions?.setting === PermissionSetting.PROTECTED ? 1 : 0 }, - ); + default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', + }); + + privacy[answer.privacy] = true; - permissions.setting = permissionSetting; + context.api = { + privacy: answer.privacy, + }; let { - permissions: { auth: authPermissions }, - } = currentPath || { permissions: { auth: [] } }; + privacy: { auth: authPrivacy }, + } = currentPath || { privacy: {} }; let { - permissions: { unauth: unauthPermissions }, - } = currentPath || { permissions: { unauth: [] } }; + privacy: { unauth: unauthPrivacy }, + } = currentPath || { privacy: {} }; - if (permissionSetting === PermissionSetting.PRIVATE) { - permissions.auth = await askCRUD('Authenticated', authPermissions); + // convert legacy permissions to CRUD structure + if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { + authPrivacy = convertToCRUD(authPrivacy); + } + if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { + unauthPrivacy = convertToCRUD(unauthPrivacy); + } + + if (answer.privacy === 'private') { + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); } - if (permissionSetting === PermissionSetting.PROTECTED) { - permissions.auth = await askCRUD('Authenticated', authPermissions); - permissions.unauth = await askCRUD('Guest', unauthPermissions); - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + if (answer.privacy === 'protected') { + privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); + const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; await ensureAuth(context, apiRequirements, answers.resourceName); } @@ -257,53 +315,60 @@ async function askPermissions( if (permissionSelected === 'Both' || permissionSelected === 'Individual Groups') { // Enable Auth if not enabled - const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); // Get Auth resource name - const authResourceName = getAuthResourceName(); + const authResourceName = await getAuthResourceName(context); answers.authResourceName = authResourceName; let defaultSelectedGroups = []; - if (currentPath?.permissions?.userPoolGroups) { - defaultSelectedGroups = Object.keys(currentPath.permissions.userPoolGroups); + if (currentPath && currentPath.privacy && currentPath.privacy.userPoolGroups) { + defaultSelectedGroups = Object.keys(currentPath.privacy.userPoolGroups); } - const userPoolGroupSelection = await inquirer.prompt({ - name: 'userpoolGroups', - type: 'checkbox', - message: 'Select groups:', - choices: userPoolGroupList, - default: defaultSelectedGroups, - validate: inputs => { - if (inputs.length === 0) { - return 'Select at least one option'; - } - return true; + const userPoolGroupSelection = await inquirer.prompt([ + { + name: 'userpoolGroups', + type: 'checkbox', + message: 'Select groups:', + choices: userPoolGroupList, + default: defaultSelectedGroups, + validate: inputs => { + if (inputs.length === 0) { + return 'Select at least one option'; + } + return true; + }, }, - }); + ]); const selectedUserPoolGroupList = userPoolGroupSelection.userpoolGroups; - for (const selectedUserPoolGroup of selectedUserPoolGroupList) { + for (let i = 0; i < selectedUserPoolGroupList.length; i += 1) { let defaults = []; - if (currentPath?.permissions?.userPoolGroups?.[selectedUserPoolGroup]) { - defaults = currentPath.permissions.userPoolGroups[selectedUserPoolGroup]; + if ( + currentPath && + currentPath.privacy && + currentPath.privacy.userPoolGroups && + currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]] + ) { + defaults = currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]]; } - if (!permissions.userPoolGroups) { - permissions.userPoolGroups = {}; + if (!privacy.userPoolGroups) { + privacy.userPoolGroups = {}; } - permissions.userPoolGroups[selectedUserPoolGroup] = await askCRUD(selectedUserPoolGroup, defaults); + privacy.userPoolGroups[selectedUserPoolGroupList[i]] = await askReadWrite(selectedUserPoolGroupList[i], context, defaults); } } - return permissions; + return privacy; } } -async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, resourceName: string) { - const checkResult: $TSAny = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ +async function ensureAuth(context, apiRequirements, resourceName) { + const checkResult = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ apiRequirements, context, 'api', @@ -317,7 +382,7 @@ async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, } if (checkResult.errors && checkResult.errors.length > 0) { - printer.warn(checkResult.errors.join(os.EOL)); + context.print.warning(checkResult.errors.join(os.EOL)); } // If auth is not imported and there were errors, adjust or enable auth configuration @@ -325,36 +390,61 @@ async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, try { await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ context, - AmplifyCategories.API, + 'api', resourceName, apiRequirements, ]); } catch (error) { - printer.error(error); + context.print.error(error); throw error; } } } -async function askCRUD(userType: string, permissions: string[] = []) { - const crudOptions = ['create', 'read', 'update', 'delete']; - const crudAnswers = await prompter.pick<'many', string>(`What permissions do you want to grant to ${userType} users?`, crudOptions, { - returnSize: 'many', - initial: permissions.map(p => crudOptions.indexOf(p)), - }); +async function askReadWrite(userType, context, privacy) { + const permissionMap = { + create: ['/POST'], + read: ['/GET'], + update: ['/PUT', '/PATCH'], + delete: ['/DELETE'], + }; + + const defaults = []; + if (privacy) { + Object.values(permissionMap).forEach((el, index) => { + if (el.every(i => privacy.includes(i))) { + defaults.push(Object.keys(permissionMap)[index]); + } + }); + } + + const crudAnswers = await context.amplify.crudFlow(userType, permissionMap, defaults); return crudAnswers; } -async function askPaths(context: $TSContext, answers: $TSObject, currentPath: ApigwPath): Promise { - const existingFunctions = functionsExist(); +async function askPaths(context, answers, currentPath) { + // const existingLambdaArns = true; - let defaultFunctionType = 'newFunction'; - const defaultChoice = { - name: 'Create a new Lambda function', - value: defaultFunctionType, - }; - const choices = [defaultChoice]; + const existingFunctions = functionsExist(context); + + const choices = [ + { + name: 'Create a new Lambda function', + value: 'newFunction', + }, + ]; + + /* + Removing this option for now in favor of multi-env support + - NOT CRITICAL + if (existingLambdaArns) { + choices.push({ + name: 'Use a Lambda function already deployed on AWS', + value: 'arn', + }); + } + */ if (existingFunctions) { choices.push({ @@ -363,19 +453,28 @@ async function askPaths(context: $TSContext, answers: $TSObject, currentPath: Ap }); } - const paths = answers.paths; + let defaultFunctionType = 'newFunction'; + if (currentPath) { + defaultFunctionType = currentPath.lambdaArn ? 'arn' : 'projectFunction'; + } + + const paths = [...answers.paths]; - let addAnotherPath: boolean; + let addAnotherPath; do { - let pathName: string; - let isPathValid: boolean; + let pathName; + let isPathValid; do { - pathName = await prompter.input('Provide a path (e.g., /book/{isbn}):', { - initial: currentPath ? currentPath.name : '/items', - validate: validatePathName, + const pathAnswer = await inquirer.prompt({ + name: 'name', + type: 'input', + message: 'Provide a path (e.g., /book/{isbn}):', + default: currentPath ? currentPath.name : '/items', + validate: value => validatePathName(value), }); + pathName = pathAnswer.name; - const overlapCheckResult = checkForPathOverlap(pathName, Object.keys(paths)); + const overlapCheckResult = checkForPathOverlap(pathName, 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; @@ -384,64 +483,81 @@ async function askPaths(context: $TSContext, answers: $TSObject, currentPath: Ap // 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?`, - ); + isPathValid = ( + await inquirer.prompt({ + name: 'isOverlappingPathOK', + type: 'confirm', + message: `The path ${lowerOrderPath} overlaps with ${higherOrderPath}. Users authorized to access ${higherOrderPath} will also have access to ${lowerOrderPath}. Are you sure you want to continue?`, + default: false, + }) + ).isOverlappingPathOK; } } while (!isPathValid); - const functionType = await prompter.pick<'one', string>('Choose a Lambda source', choices, { initial: choices.indexOf(defaultChoice) }); + const lambdaAnswer = await inquirer.prompt({ + name: 'functionType', + type: 'list', + message: 'Choose a Lambda source', + choices, + default: defaultFunctionType, + }); + // TODO: add path validation like awsmobile-cli does let path = { name: pathName }; let lambda; do { - lambda = await askLambdaSource(context, functionType, pathName, currentPath); + lambda = await askLambdaSource(context, lambdaAnswer.functionType, path.name, currentPath); } while (!lambda); - const permissions = await askPermissions(context, answers, currentPath); - path = { ...path, ...lambda, permissions }; - paths[pathName] = path; + const privacy = await askPrivacy(context, answers, currentPath); + path = { ...path, ...lambda, privacy }; + paths.push(path); if (currentPath) { break; } - addAnotherPath = await prompter.confirmContinue('Do you want to add another path?'); + addAnotherPath = ( + await inquirer.prompt({ + name: 'anotherPath', + type: 'confirm', + message: 'Do you want to add another path?', + default: false, + }) + ).anotherPath; } while (addAnotherPath); - const { dependsOn, functionArns } = await findDependsOn(paths); + const { dependsOn, functionArns } = await findDependsOn(paths, context); - return { paths, dependsOn, resourceName: answers.resourceName, functionArns }; + return { paths, dependsOn, functionArns }; } -async function findDependsOn(paths: $TSObject[]) { +async function findDependsOn(paths, context) { // 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)) { + for (let i = 0; i < paths.length; i += 1) { + if (paths[i].lambdaFunction && !paths[i].lambdaArn) { + if (!dependsOn.find(func => func.resourceName === paths[i].lambdaFunction)) { dependsOn.push({ category: 'function', - resourceName: path.lambdaFunction, + resourceName: paths[i].lambdaFunction, attributes: ['Name', 'Arn'], }); } } - if (!functionArns.find(func => func.lambdaFunction === path.lambdaFunction)) { + if (!functionArns.find(func => func.lambdaFunction === paths[i].lambdaFunction)) { functionArns.push({ - lambdaFunction: path.lambdaFunction, - lambdaArn: path.lambdaArn, + lambdaFunction: paths[i].lambdaFunction, + lambdaArn: paths[i].lambdaArn, }); } - if (path?.permissions?.userPoolGroups) { - const userPoolGroups = Object.keys(path.privacy.userPoolGroups); + if (paths[i].privacy && paths[i].privacy.userPoolGroups) { + const userPoolGroups = Object.keys(paths[i].privacy.userPoolGroups); if (userPoolGroups.length > 0) { // Get auth resource name - const authResourceName = getAuthResourceName(); + const authResourceName = await getAuthResourceName(context); if (!dependsOn.find(resource => resource.resourceName === authResourceName)) { dependsOn.push({ @@ -466,29 +582,26 @@ async function findDependsOn(paths: $TSObject[]) { return { dependsOn, functionArns }; } -function getAuthResourceName(): string { - const meta = stateManager.getMeta(); - const authResources = (Object.entries(meta?.auth) || []).filter( - ([_, resource]: [key: string, resource: $TSObject]) => resource.service === AmplifySupportedService.COGNITO, - ); +async function getAuthResourceName(context) { + let authResources = (await context.amplify.getResourceStatus('auth')).allResources; + authResources = authResources.filter(resource => resource.service === 'Cognito'); if (authResources.length === 0) { - throw new Error('No auth resource found. Add it using amplify add auth'); + throw new Error('No auth resource found. Please add it using amplify add auth'); } - const [authResourceName] = authResources[0]; + const authResourceName = authResources[0].resourceName; return authResourceName; } -function functionsExist() { - const meta = stateManager.getMeta(); - if (!meta.function) { +function functionsExist(context) { + if (!context.amplify.getProjectDetails().amplifyMeta.function) { return false; } - const functionResources = meta.function; + const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === AmplifySupportedService.LAMBDA) { + if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { lambdaFunctions.push(resourceName); } }); @@ -500,20 +613,26 @@ function functionsExist() { return true; } -async function askLambdaSource(context: $TSContext, functionType: string, path: string, currentPath: ApigwPath) { +async function askLambdaSource(context, functionType, path, currentPath) { switch (functionType) { case 'arn': return askLambdaArn(context, currentPath); case 'projectFunction': - return askLambdaFromProject(currentPath); + return askLambdaFromProject(context, currentPath); case 'newFunction': - return newLambdaFunction(context as $TSAny, path); + return newLambdaFunction(context, path); default: throw new Error('Type not supported'); } } -async function newLambdaFunction(context: $TSContext, path: string) { +async function newLambdaFunction(context, path) { + context.api = { + path, + // ExpressJS represents path parameters as /:param instead of /{param}. This expression performs this replacement. + expressPath: formatCFNPathParamsForExpressJs(path), + functionTemplate: 'serverless', + }; let params = { functionTemplate: { parameters: { @@ -523,35 +642,39 @@ async function newLambdaFunction(context: $TSContext, path: string) { }, }; - const resourceName = await context.amplify.invokePluginMethod(context, AmplifyCategories.FUNCTION, undefined, 'add', [ + const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ context, 'awscloudformation', - AmplifySupportedService.LAMBDA, + FunctionServiceNameLambdaFunction, params, ]); - printer.success('Succesfully added the Lambda function locally'); + context.print.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; } -async function askLambdaFromProject(currentPath?: ApigwPath) { - const meta = stateManager.getMeta(); +async function askLambdaFromProject(context, currentPath) { + const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; const lambdaFunctions = []; - Object.keys(meta?.function || {}).forEach(resourceName => { - if (meta.function[resourceName].service === AmplifySupportedService.LAMBDA) { + Object.keys(functionResources).forEach(resourceName => { + if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { 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, + const answer = await inquirer.prompt({ + name: 'lambdaFunction', + type: 'list', + message: 'Choose the Lambda function to invoke by this path', + choices: lambdaFunctions, + default: currentPath ? currentPath.lambdaFunction : lambdaFunctions[0], }); - return { lambdaFunction }; + return { lambdaFunction: answer.lambdaFunction }; } -async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { +async function askLambdaArn(context, currentPath) { const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions'); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ @@ -560,16 +683,16 @@ async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { })); if (lambdaOptions.length === 0) { - printer.error('You do not have any Lambda functions configured for the selected Region'); + context.print.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', + message: 'Please select a Lambda function', choices: lambdaOptions, - default: currentPath && currentPath.lambdaFunction ? `${currentPath.lambdaFunction}` : `${lambdaOptions[0].value}`, + default: currentPath && currentPath.lambdaArn ? `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, }; let lambdaOption; @@ -577,7 +700,7 @@ async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { try { lambdaOption = await inquirer.prompt([lambdaCloudOptionQuestion]); } catch (err) { - printer.error('Select a Lambda Function'); + context.print.error('Select a Lambda Function'); } } @@ -589,12 +712,56 @@ async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { }; } -export async function migrate(context: $TSContext, projectPath: string, resourceName: string) { - const apigwInputState = new ApigwInputState(context, resourceName); - return apigwInputState.migrateApigwResource(resourceName); +export async function migrate(context, projectPath, resourceName) { + const { amplify } = context; + + const targetDir = amplify.pathManager.getBackendDirPath(); + const resourceDirPath = path.join(targetDir, category, resourceName); + const parametersFilePath = path.join(resourceDirPath, parametersFileName); + let parameters; + try { + parameters = amplify.readJsonFile(parametersFilePath); + } catch (e) { + context.print.error(`Error reading api-params.json file for ${resourceName} resource`); + throw e; + } + const copyJobs = [ + { + dir: path.join(rootAssetDir, 'cloudformation-templates'), + template: 'apigw-cloudformation-template-default.json.ejs', + target: `${targetDir}/${category}/${resourceName}/${resourceName}-cloudformation-template.json`, + }, + ]; + + // copy over the files + await context.amplify.copyBatch(context, copyJobs, parameters, true, false); + + // Create parameters.json file + const cfnParameters = { + authRoleName: { + Ref: 'AuthRoleName', + }, + unauthRoleName: { + Ref: 'UnauthRoleName', + }, + }; + + const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); + const jsonString = JSON.stringify(cfnParameters, null, 4); + fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); +} + +function convertToCRUD(privacy) { + if (privacy === 'r') { + privacy = ['/GET']; + } else if (privacy === 'rw') { + privacy = ['/POST', '/GET', '/PUT', '/PATCH', '/DELETE']; + } + + return privacy; } -export function getIAMPolicies(resourceName: string, crudOptions: string[]) { +export function getIAMPolicies(resourceName, crudOptions) { let policy = {}; const actions = []; @@ -613,7 +780,7 @@ export function getIAMPolicies(resourceName: string, crudOptions: string[]) { actions.push('apigateway:DELETE'); break; default: - printer.info(`${crudOption} not supported`); + console.log(`${crudOption} not supported`); } }); @@ -645,7 +812,7 @@ export function getIAMPolicies(resourceName: string, crudOptions: string[]) { return { policy, attributes }; } -export const openConsole = async (context?: $TSContext) => { +export const openConsole = async (context: $TSContext) => { const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; const { Region } = amplifyMeta.providers.awscloudformation; @@ -663,7 +830,12 @@ export const openConsole = async (context?: $TSContext) => { let selectedApi = restApis[0]; if (restApis.length > 1) { - selectedApi = await prompter.pick<'one', string>('Select the API', restApis); + ({ selectedApi } = await inquirer.prompt({ + type: 'list', + name: 'selectedApi', + choices: restApis, + message: 'Please select the API', + })); } const selectedResource = categoryAmplifyMeta[selectedApi]; @@ -681,29 +853,34 @@ export const openConsole = async (context?: $TSContext) => { const codePipeline = 'CodePipeline'; const elasticContainer = 'ElasticContainer'; - const selectedConsole = await prompter.pick<'one', string>('Which console you want to open', [ - { - name: 'Elastic Container Service (Deployed container status)', - value: elasticContainer, - }, - { - name: 'CodePipeline (Container build status)', - value: codePipeline, - }, - ]); + 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'); + context.print.error('Option not available'); return; } } open(url, { wait: false }); } else { - printer.error('There are no REST APIs pushed to the cloud'); + context.print.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-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts index 10d0b2eac0..1d0a92fb11 100644 --- 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 @@ -1,22 +1,21 @@ -import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; -import chalk from 'chalk'; -import { DataApiParams } from 'graphql-relational-schema-transformer'; import inquirer from 'inquirer'; +import chalk from 'chalk'; import ora from 'ora'; +import { DataApiParams } from 'graphql-relational-schema-transformer'; +import { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick, $TSContext, $TSObject } from 'amplify-cli-core'; const spinner = ora(''); const category = 'api'; const providerName = 'awscloudformation'; -export async function serviceWalkthrough(context: $TSContext, datasourceMetadata: $TSObject) { +export async function serviceWalkthrough(context: $TSContext, defaultValuesFilename: string, datasourceMetadata: $TSObject) { 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); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -25,9 +24,9 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata let appSyncApi: string; const apis = Object.keys(amplifyMeta[category]); - for (const api of apis) { - if (amplifyMeta[category][api].service === 'AppSync') { - appSyncApi = api; + for (let i = 0; i < apis.length; i += 1) { + if (amplifyMeta[category][apis[i]].service === 'AppSync') { + appSyncApi = apis[i]; break; } } @@ -36,7 +35,7 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata 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); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -87,7 +86,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { if (serverlessClusters.length === 0) { const errMessage = 'No properly configured Aurora Serverless clusters found.'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -111,7 +110,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { // 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.`); + context.print.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); return { selectedClusterArn: firstCluster.DBClusterArn, @@ -149,7 +148,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, if (secretsForCluster.length === 0) { const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); @@ -170,7 +169,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, // 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.`); + context.print.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); } return selectedSecretArn; @@ -207,14 +206,14 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn const msg = `Ensure that '${secretArn}' contains your database credentials. ` + 'Please note that Aurora Serverless does not support IAM database authentication.'; - printer.error(msg); + context.print.error(msg); } } if (databaseList.length === 0) { const errMessage = 'No database found in the selected cluster.'; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -225,7 +224,7 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn return await promptWalkthroughQuestion(inputs, 3, databaseList); } - printer.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); + context.print.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); return databaseList[0]; } 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 index 508160615f..933134e813 100644 --- 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 @@ -1,33 +1,30 @@ -import { Duration, Expiration } from '@aws-cdk/core'; +import { ListQuestion, CheckboxQuestion, ListChoiceOptions } from 'inquirer'; +import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; +import inquirer from 'inquirer'; +import fs from 'fs-extra'; +import path from 'path'; +import { rootAssetDir, provider } from '../aws-constants'; +import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; +import { category } from '../../../category-constants'; +import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; +import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; +import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; +import _ from 'lodash'; +import chalk from 'chalk'; +import uuid from 'uuid'; +import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; import { - $TSContext, - $TSObject, - exitOnNextTick, - FeatureFlags, - open, - pathManager, ResourceAlreadyExistsError, ResourceDoesNotExistError, - stateManager, UnknownResourceTypeError, + exitOnNextTick, + stateManager, + FeatureFlags, + $TSContext, + open, } from 'amplify-cli-core'; -import { UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from '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 * as path from 'path'; -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 { Duration, Expiration } from '@aws-cdk/core'; 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'; @@ -154,11 +151,11 @@ export const openConsole = async (context: $TSContext) => { url = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); 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.`); + context.print.warning(`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; @@ -193,24 +190,26 @@ export const openConsole = async (context: $TSContext) => { } else if (selectedConsole === codePipeline) { url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; } else { - printer.error('Option not available'); + context.print.error('Option not available'); return; } } open(url, { wait: false }); } else { - printer.error('AppSync API is not pushed in the cloud.'); + context.print.error('AppSync API is not pushed in the cloud.'); } }; -const serviceApiInputWalkthrough = async (context: $TSContext, serviceMetadata) => { +const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { let continuePrompt = false; let authConfig; let defaultAuthType; let resolverConfig; const { amplify } = context; const { inputs } = serviceMetadata; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); let resourceAnswers = {}; @@ -337,7 +336,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, serviceMetadata) }; }; -const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject, resolverConfig, modelTypes) => { +const updateApiInputWalkthrough = async (context, project, resolverConfig, modelTypes) => { let authConfig; let defaultAuthType; const updateChoices = [ @@ -389,16 +388,15 @@ const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject }; }; -export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $TSObject) => { - const resourceName = resourceAlreadyExists(); - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); +export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { + const resourceName = resourceAlreadyExists(context); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); const transformerVersion = providerPlugin.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); + context.print.warning(errMessage); await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); exitOnNextTick(0); } @@ -406,7 +404,7 @@ export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $ const { amplify } = context; const { inputs } = serviceMetadata; - const basicInfoAnswers = await serviceApiInputWalkthrough(context, serviceMetadata); + const basicInfoAnswers = await serviceApiInputWalkthrough(context, defaultValuesFilename, serviceMetadata); let schemaContent = ''; let askToEdit = true; @@ -433,7 +431,7 @@ export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $ }; }; -export const updateWalkthrough = async (context: $TSContext): Promise => { +export const updateWalkthrough = async (context): Promise => { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; @@ -452,10 +450,11 @@ export const updateWalkthrough = async (context: $TSContext): Promise printer.info(authMode)); - printer.info(''); + context.print.success('Authorization modes'); + authModes.forEach(authMode => context.print.info(authMode)); + context.print.info(''); - printer.success('Conflict detection (required for DataStore)'); + context.print.success('Conflict detection (required for DataStore)'); if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - printer.info( + context.print.info( `- Conflict resolution strategy: ${ conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name }`, ); } else { - printer.info('- Disabled'); + context.print.info('- Disabled'); } - printer.info(''); + context.print.info(''); } -async function displayAuthMode(context: $TSContext, resource: $TSObject, authMode: string) { - if (authMode === 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { +async function displayAuthMode(context, resource, authMode) { + if (authMode == 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getAppSyncApiKeys', { apiId: resource.output.GraphQLAPIIdOutput, }); @@ -547,13 +546,13 @@ async function displayAuthMode(context: $TSContext, resource: $TSObject, authMod return authProviderChoices.find(choice => choice.value === authMode).name; } -async function askAdditionalQuestions(context: $TSContext, authConfig, defaultAuthType, modelTypes?) { +async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); return { authConfig }; } -async function askResolverConflictQuestion(context: $TSContext, resolverConfig, modelTypes?) { - let resolverConfigResponse: $TSObject = {}; +async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) { + let resolverConfigResponse: any = {}; if (await context.prompt.confirm('Enable conflict detection?', !resolverConfig?.project)) { resolverConfigResponse = await askResolverConflictHandlerQuestion(context, modelTypes); @@ -562,8 +561,8 @@ async function askResolverConflictQuestion(context: $TSContext, resolverConfig, return resolverConfigResponse; } -async function askResolverConflictHandlerQuestion(context: $TSContext, modelTypes?) { - let resolverConfig: $TSObject = {}; +async function askResolverConflictHandlerQuestion(context, modelTypes?) { + let resolverConfig: any = {}; const askConflictResolutionStrategy = async msg => { let conflictResolutionStrategy; @@ -581,13 +580,13 @@ async function askResolverConflictHandlerQuestion(context: $TSContext, modelType ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); - let syncConfig: $TSObject = { + let syncConfig: any = { ConflictHandler: conflictResolutionStrategy, ConflictDetection: 'VERSION', }; if (conflictResolutionStrategy === 'LAMBDA') { - const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(); + const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); syncConfig.LambdaConflictHandler = { name: lambdaFunctionName, new: newFunction, @@ -614,8 +613,10 @@ async function askResolverConflictHandlerQuestion(context: $TSContext, modelType if (selectedModelTypes.length > 0) { resolverConfig.models = {}; - for (const modelType of selectedModelTypes) { - resolverConfig.models[modelType] = await askConflictResolutionStrategy(`Select the resolution strategy for ${modelType} model`); + for (let i = 0; i < selectedModelTypes.length; i += 1) { + resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( + `Select the resolution strategy for ${selectedModelTypes[i]} model`, + ); } } } @@ -624,7 +625,7 @@ async function askResolverConflictHandlerQuestion(context: $TSContext, modelType return resolverConfig; } -async function askSyncFunctionQuestion() { +async function askSyncFunctionQuestion(context) { const syncLambdaQuestion = { type: 'list', name: 'syncLambdaAnswer', @@ -659,8 +660,8 @@ async function askSyncFunctionQuestion() { return { newFunction, lambdaFunctionName }; } -async function addLambdaAuthorizerChoice(context: $TSContext) { - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); +async function addLambdaAuthorizerChoice(context) { + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); const transformerVersion = providerPlugin.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ @@ -670,9 +671,9 @@ async function addLambdaAuthorizerChoice(context: $TSContext) { } } -async function askDefaultAuthQuestion(context: $TSContext) { +async function askDefaultAuthQuestion(context) { await addLambdaAuthorizerChoice(context); - const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); + const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); const currentDefaultAuth = currentAuthConfig && currentAuthConfig.defaultAuthentication ? currentAuthConfig.defaultAuthentication.authenticationType : undefined; @@ -697,8 +698,8 @@ async function askDefaultAuthQuestion(context: $TSContext) { }; } -export async function askAdditionalAuthQuestions(context: $TSContext, authConfig: $TSObject, defaultAuthType) { - const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); +export async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { + const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); authConfig.additionalAuthenticationProviders = []; if (await context.prompt.confirm('Configure additional auth types?')) { // Get additional auth configured @@ -719,7 +720,9 @@ export async function askAdditionalAuthQuestions(context: $TSContext, authConfig const additionalProvidersAnswer = await inquirer.prompt([additionalProvidersQuestion]); - for (const authProvider of additionalProvidersAnswer.authType) { + for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { + const authProvider = additionalProvidersAnswer.authType[i]; + const config = await askAuthQuestions( authProvider, context, @@ -737,10 +740,10 @@ export async function askAdditionalAuthQuestions(context: $TSContext, authConfig return authConfig; } -export async function askAuthQuestions(authType: string, context: $TSContext, printLeadText = false, authSettings) { +export async function askAuthQuestions(authType, context, printLeadText = false, authSettings) { if (authType === 'AMAZON_COGNITO_USER_POOLS') { if (printLeadText) { - printer.info('Cognito UserPool configuration'); + context.print.info('Cognito UserPool configuration'); } const userPoolConfig = await askUserPoolQuestions(context); @@ -750,7 +753,7 @@ export async function askAuthQuestions(authType: string, context: $TSContext, pr if (authType === 'API_KEY') { if (printLeadText) { - printer.info('API key configuration'); + context.print.info('API key configuration'); } const apiKeyConfig = await askApiKeyQuestions(authSettings); @@ -766,7 +769,7 @@ export async function askAuthQuestions(authType: string, context: $TSContext, pr if (authType === 'OPENID_CONNECT') { if (printLeadText) { - printer.info('OpenID Connect configuration'); + context.print.info('OpenID Connect configuration'); } const openIDConnectConfig = await askOpenIDConnectQuestions(authSettings); @@ -785,17 +788,17 @@ export async function askAuthQuestions(authType: string, context: $TSContext, pr } const errMessage = `Unknown authType: ${authType}`; - printer.error(errMessage); + context.print.error(errMessage); await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); exitOnNextTick(1); } -async function askUserPoolQuestions(context: $TSContext) { - let authResourceName = checkIfAuthExists(); +async function askUserPoolQuestions(context) { + let authResourceName = checkIfAuthExists(context); 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.'); + context.print.info('Use a Cognito user pool configured as a part of this project.'); } // Added resources are prefixed with auth @@ -809,7 +812,7 @@ async function askUserPoolQuestions(context: $TSContext) { }; } -export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { +export async function askApiKeyQuestions(authSettings = undefined) { let defaultValues = { apiKeyExpirationDays: 7, description: undefined, @@ -850,7 +853,7 @@ export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { }; } -async function askOpenIDConnectQuestions(authSettings: $TSObject) { +async function askOpenIDConnectQuestions(authSettings) { let defaultValues = { authTTL: undefined, clientId: undefined, @@ -904,7 +907,7 @@ async function askOpenIDConnectQuestions(authSettings: $TSObject) { }; } -async function validateDays(input: string) { +async function validateDays(input) { const isValid = /^\d{0,3}$/.test(input); const days = isValid ? parseInt(input, 10) : 0; if (!isValid || days < 1 || days > 365) { @@ -914,7 +917,7 @@ async function validateDays(input: string) { return true; } -function validateIssuerUrl(input: string) { +function validateIssuerUrl(input) { const isValid = /^(((?!http:\/\/(?!localhost))([a-zA-Z0-9.]{1,}):\/\/([a-zA-Z0-9-._~:?#@!$&'()*+,;=/]{1,})\/)|(?!http)(?!https)([a-zA-Z0-9.]{1,}):\/\/)$/.test( input, @@ -927,7 +930,7 @@ function validateIssuerUrl(input: string) { return true; } -function validateTTL(input: string) { +function validateTTL(input) { const isValid = /^\d+$/.test(input); if (!isValid) { @@ -937,32 +940,32 @@ function validateTTL(input: string) { return true; } -function resourceAlreadyExists() { - const meta = stateManager.getMeta(); +function resourceAlreadyExists(context) { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); let resourceName; - if (meta[category]) { - const categoryResources = meta[category]; - for (const resource of Object.keys(categoryResources)) { + if (amplifyMeta[category]) { + const categoryResources = amplifyMeta[category]; + Object.keys(categoryResources).forEach(resource => { if (categoryResources[resource].service === serviceName) { resourceName = resource; - break; } - } + }); } return resourceName; } -export const migrate = async (context: $TSContext) => { +export const migrate = async context => { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true, }); }; -export const getIAMPolicies = (resourceName: string, operations: string[]) => { - let policy: $TSObject = {}; +export const getIAMPolicies = (resourceName: string, operations: string[], context: any) => { + let policy: any = {}; const resources = []; const actions = []; if (!FeatureFlags.getBoolean('appSync.generateGraphQLPermissions')) { @@ -982,7 +985,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[]) => { actions.push('appsync:Delete*'); break; default: - printer.info(`${crudOption} not supported`); + console.log(`${crudOption} not supported`); } }); resources.push(buildPolicyResource(resourceName, null)); @@ -998,7 +1001,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[]) => { }; const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; - if (authConfigHasApiKey(getAppSyncAuthConfig(stateManager.getMeta()))) { + if (authConfigHasApiKey(getAppSyncAuthConfig(context.amplify.getProjectMeta()))) { attributes.push('GraphQLAPIKeyOutput'); } @@ -1174,7 +1177,7 @@ async function createLambdaAuthorizerFunction(context: $TSContext) { const backendConfigs = { service: FunctionServiceNameLambdaFunction, - providerPlugin: providerName, + providerPlugin: provider, build: true, }; 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 index 5ba0df021b..9b38fb744f 100644 --- 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 @@ -1,10 +1,8 @@ -import { $TSAny, $TSContext, $TSObject, exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; +import { exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; 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'; @@ -46,8 +44,11 @@ export type ServiceConfiguration = { gitHubInfo?: GitHubSourceActionInfo; }; -export async function serviceWalkthrough(context: $TSContext, apiType: API_TYPE): Promise> { - const allDefaultValues = getAllDefaults(); +export async function serviceWalkthrough(context, defaultValuesFilename, apiType: API_TYPE): Promise> { + const { amplify } = context; + const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; + const { getAllDefaults } = await import(defaultValuesSrc); + const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); const resourceName = await askResourceName(context, allDefaultValues); @@ -56,7 +57,7 @@ export async function serviceWalkthrough(context: $TSContext, apiType: API_TYPE) return { resourceName, ...containerInfo }; } -async function askResourceName(context: $TSContext, allDefaultValues: $TSObject) { +async function askResourceName(context, allDefaultValues) { const { amplify } = context; const { resourceName } = await inquirer.prompt([ @@ -79,7 +80,7 @@ async function askResourceName(context: $TSContext, allDefaultValues: $TSObject) return resourceName; } -async function askContainerSource(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { +async function askContainerSource(context, resourceName: string, apiType: API_TYPE): Promise> { return newContainer(context, resourceName, apiType); } @@ -88,7 +89,7 @@ export enum IMAGE_SOURCE_TYPE { CUSTOM = 'CUSTOM', } -async function newContainer(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { +async function newContainer(context, resourceName: string, apiType: API_TYPE): Promise> { let imageSource: { type: IMAGE_SOURCE_TYPE; template?: string }; let choices = []; @@ -170,8 +171,8 @@ async function newContainer(context: $TSContext, resourceName: string, apiType: 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( + context.print.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); + context.print.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', ); @@ -233,7 +234,7 @@ async function newContainer(context: $TSContext, resourceName: string, apiType: }; } -export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) { +export async function updateWalkthrough(context, defaultValuesFilename, apiType: API_TYPE) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources @@ -246,7 +247,7 @@ export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) // 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); + context.print.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; @@ -301,7 +302,7 @@ export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) const hasAccessableResources = ['storage', 'function'].some(categoryName => { return Object.keys(meta[categoryName] ?? {}).length > 0; }); - let rolePermissions: $TSAny = {}; + let rolePermissions: any = {}; if ( hasAccessableResources && (await context.amplify.confirmPrompt('Do you want to access other resources in this project from your api?')) 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 index e3385279de..d920a8d9c9 100644 --- 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 @@ -1,7 +1,6 @@ -import { $TSAny, $TSMeta, $TSObject, AmplifyCategories, AmplifySupportedService, stateManager } from 'amplify-cli-core'; import _ from 'lodash'; -export const authConfigHasApiKey = (authConfig?: $TSAny) => { +export const authConfigHasApiKey = authConfig => { if (!authConfig) { return false; } @@ -14,11 +13,12 @@ export const authConfigHasApiKey = (authConfig?: $TSAny) => { ); }; -export const checkIfAuthExists = () => { - const amplifyMeta = stateManager.getMeta(); +export const checkIfAuthExists = context => { + const { amplify } = context; + const { amplifyMeta } = amplify.getProjectDetails(); let authResourceName; - const authServiceName = AmplifySupportedService.COGNITO; - const authCategoryName = AmplifyCategories.AUTH; + const authServiceName = 'Cognito'; + const authCategoryName = 'auth'; if (amplifyMeta[authCategoryName] && Object.keys(amplifyMeta[authCategoryName]).length > 0) { const categoryResources = amplifyMeta[authCategoryName]; @@ -34,15 +34,15 @@ export const checkIfAuthExists = () => { // some utility functions to extract the AppSync API name and config from amplify-meta -export const getAppSyncAuthConfig = (projectMeta: $TSMeta) => { +export const getAppSyncAuthConfig = projectMeta => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { - const value = entry[1] as $TSAny; + const value = entry[1] as any; return value && value.output ? value.output.authConfig : {}; } }; -export const getAppSyncResourceName = (projectMeta: $TSMeta): string | undefined => { +export const getAppSyncResourceName = (projectMeta: any): string | undefined => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { return entry[0]; @@ -51,8 +51,6 @@ export const getAppSyncResourceName = (projectMeta: $TSMeta): string | undefined // 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 $TSObject).service === AmplifySupportedService.APPSYNC, - ); +const getAppSyncAmplifyMetaEntry = (projectMeta: any) => { + return Object.entries(projectMeta.api || {}).find(([, value]) => (value as any).service === 'AppSync'); }; 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 index 5a1368cfa8..51da9da2da 100644 --- 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 @@ -2,14 +2,14 @@ import { Octokit } from '@octokit/rest'; import * as fs from 'fs-extra'; import inquirer from 'inquirer'; import * as path from 'path'; -import { v4 as uuid } from 'uuid'; +import uuid from 'uuid'; 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 { $TSAny, $TSContext, JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; +import { JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; import { setExistingSecretArns } from './containers/set-existing-secret-arns'; import { category } from '../../../category-constants'; @@ -28,9 +28,9 @@ export type ApiResource = { restrictAccess: boolean; dependsOn: ResourceDependency[]; environmentMap: Record; - categoryPolicies: $TSAny[]; - mutableParametersState: $TSAny; - output?: Record; + categoryPolicies: any[]; + mutableParametersState: any; + output?: Record; apiType?: API_TYPE; exposedContainer?: { name: string; port: number }; }; @@ -46,7 +46,7 @@ type ContainerArtifactsMetadata = { }; export async function generateContainersArtifacts( - context: $TSContext, + context: any, resource: ApiResource, askForExposedContainer: boolean = false, ): Promise { @@ -116,12 +116,7 @@ export async function generateContainersArtifacts( }; } -export async function processDockerConfig( - context: $TSContext, - resource: ApiResource, - srcPath: string, - askForExposedContainer: boolean = false, -) { +export async function processDockerConfig(context: any, resource: ApiResource, srcPath: string, askForExposedContainer: boolean = false) { const { providers: { [cloudformationProviderName]: provider }, } = context.amplify.getProjectMeta(); @@ -311,7 +306,7 @@ export async function processDockerConfig( }; } -async function shouldUpdateSecrets(context: $TSContext, secrets: Record): Promise { +async function shouldUpdateSecrets(context: any, secrets: Record): Promise { const hasSecrets = Object.keys(secrets).length > 0; if (!hasSecrets || context.exeInfo.inputParams.yes) { 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 index 2c7adced53..05b3688da0 100644 --- 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 @@ -1,10 +1,4 @@ -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; +export const serviceMetadataFor = async service => (await import('../../supported-services')).supportedServices[service]; +export const datasourceMetadataFor = async datasource => (await import('../../supported-datasources')).supportedDatasources[datasource]; +export const getServiceWalkthrough = async walkthroughFilename => + (await import(`../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 index 3d339aecd0..1196423873 100644 --- 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 @@ -1,14 +1,18 @@ -import { $TSContext, pathManager } from 'amplify-cli-core'; -import { prompter } from 'amplify-prompts'; -import * as path from 'path'; +import inquirer, { ConfirmQuestion } from 'inquirer'; +import path from 'path'; 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; - } +export const editSchemaFlow = async (context: any, apiName: string) => { + const prompt: ConfirmQuestion = { + type: 'confirm', + name: 'editNow', + message: 'Do you want to edit the schema now?', + default: true, + }; - const schemaPath = path.join(pathManager.getResourceDirectoryPath(undefined, category, apiName), gqlSchemaFilename); + if (!(await inquirer.prompt(prompt)).editNow) return; + + const schemaPath = path.join(context.amplify.pathManager.getBackendDirPath(), category, apiName, gqlSchemaFilename); await context.amplify.openEditor(context, schemaPath, false); }; 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 index 14eeb6a933..f98601878b 100644 --- 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 @@ -1,18 +1,16 @@ -import { printer } from '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) => { +export const printApiKeyWarnings = (context, oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { if (oldConfigHadApiKey && !newConfigHasApiKey) { - printer.warn('The API_KEY auth type has been removed from the API.'); - printer.warn( + context.print.warning('The API_KEY auth type has been removed from the API.'); + context.print.warning( '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'); + context.print.warning('⚠️ 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( + context.print.warning('The API_KEY auth type has been added to the API.'); + context.print.warning( '⚠️ 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/rest-api-path-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts index 2893bfe9a9..37370c2dea 100644 --- 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 @@ -37,7 +37,7 @@ export const validatePathName = (name: string) => { // } // // checkForPathOverlap assumes that all provided paths have previously been run through validatePathName(). -export const checkForPathOverlap = (name: string, paths: string[]) => { +export const checkForPathOverlap = (name: string, paths: { name: 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 @@ -59,7 +59,7 @@ export const checkForPathOverlap = (name: string, paths: string[]) => { 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); + overlappingPath = paths.map(path => path.name).find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); return overlappingPath !== undefined; }); if (subMatch) { diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index b0e2a08bf6..65b5b01910 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -27,6 +27,7 @@ export const supportedDatasources = { }, ], alias: 'Aurora Serverless', + defaultValuesFilename: 'appSync-rds-defaults.js', serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index 70734fee70..99cc2e128b 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -122,6 +122,7 @@ export const supportedServices = { }, ], alias: 'GraphQL', + defaultValuesFilename: 'appSync-defaults.js', serviceWalkthroughFilename: 'appSync-walkthrough.js', cfnFilename: 'appSync-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', @@ -147,7 +148,9 @@ export const supportedServices = { }, ], alias: 'REST', + defaultValuesFilename: 'apigw-defaults.js', serviceWalkthroughFilename: 'apigw-walkthrough.js', + cfnFilename: 'apigw-cloudformation-template-default.json.ejs', provider: 'awscloudformation', }, }; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 30baf56b86..5a69dbb23d 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -4,7 +4,7 @@ "outDir": "lib", "rootDir": "src", "strict": false, // because package has been converted from js - "allowJs": false + "allowJs": true }, "exclude": [ "coverage", @@ -12,8 +12,6 @@ "resources/awscloudformation/lambdas", "resources/awscloudformation/container-templates", "resources/awscloudformation/graphql-lambda-authorizer", - "resources/awscloudformation/overrides-resource", - "scripts", "src/__tests__" ], "references": [ From a72103c6ca9eeafef1a29f356e238a1b18ecfe3a Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Fri, 5 Nov 2021 12:07:51 -0700 Subject: [PATCH 492/587] fix: asana bug fixes (#8692) * fix: asana bug fixes * chore: removes commmented code --- packages/amplify-category-api/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 4ada1ab74d..96ce70e2d7 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -6,7 +6,6 @@ import { getCfnApiArtifactHandler } from './provider-utils/awscloudformation/cfn import { askAuthQuestions } from './provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; import { authConfigToAppSyncAuthType } from './provider-utils/awscloudformation/utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; - export { NETWORK_STACK_LOGICAL_ID } from './category-constants'; export { DEPLOYMENT_MECHANISM } from './provider-utils/awscloudformation/base-api-stack'; export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; From 759903bf0178bf5ec818fde378e5db77a2928c4b Mon Sep 17 00:00:00 2001 From: AmmarKarachi Date: Wed, 10 Nov 2021 19:34:01 -0800 Subject: [PATCH 493/587] chore: minor version bump --- packages/amplify-category-api/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ed50de180e..832b27344f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.33.2", + "version": "2.34.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "0.2.0", + "@aws-amplify/graphql-transformer-migrator": "0.3.0", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,7 +64,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.32.0", + "amplify-cli-core": "1.33.0", "amplify-headless-interface": "1.11.0", "amplify-prompts": "1.3.0", "amplify-provider-awscloudformation": "4.61.1", @@ -74,7 +74,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.8", - "graphql-transformer-core": "6.31.0", + "graphql-transformer-core": "6.32.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From c47e11978ed40fd6dfd724ff44946226ed0857fb Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Fri, 12 Nov 2021 21:19:34 -0800 Subject: [PATCH 494/587] chore: major version bump (#8847) --- packages/amplify-category-api/CHANGELOG.md | 47 ++++++++++++++++++++++ packages/amplify-category-api/package.json | 8 ++-- 2 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4985ac44f1..ee225afd34 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,53 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 832b27344f..830677117f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "2.34.0", + "version": "3.0.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "0.3.0", + "@aws-amplify/graphql-transformer-migrator": "1.0.0", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,7 +64,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "1.33.0", + "amplify-cli-core": "2.0.0", "amplify-headless-interface": "1.11.0", "amplify-prompts": "1.3.0", "amplify-provider-awscloudformation": "4.61.1", @@ -74,7 +74,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.18.8", - "graphql-transformer-core": "6.32.0", + "graphql-transformer-core": "7.0.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From b2a5601925d707ee9e6d5535dfa759aa4c355334 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Sun, 14 Nov 2021 13:12:10 -0800 Subject: [PATCH 495/587] chore: 2 minor version bumps (#8862) --- packages/amplify-category-api/package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 830677117f..403a793f02 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.0.0", + "version": "3.2.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.0.0", + "@aws-amplify/graphql-transformer-migrator": "1.2.0", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,17 +64,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.0.0", - "amplify-headless-interface": "1.11.0", - "amplify-prompts": "1.3.0", + "amplify-cli-core": "2.2.0", + "amplify-headless-interface": "1.13.0", + "amplify-prompts": "1.5.0", "amplify-provider-awscloudformation": "4.61.1", - "amplify-util-headless-input": "1.6.0", + "amplify-util-headless-input": "1.8.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.18.8", - "graphql-transformer-core": "7.0.0", + "graphql-relational-schema-transformer": "2.20.0", + "graphql-transformer-core": "7.2.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 7c0398cbf0dba9513ce37c838f197c34b8da40a3 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 15 Nov 2021 02:43:53 +0000 Subject: [PATCH 496/587] chore(release): Publish [ci skip] - amplify-app@4.2.1 - amplify-appsync-simulator@2.2.1 - amplify-category-analytics@3.2.1 - amplify-category-api@3.3.0 - @aws-amplify/amplify-category-auth@2.3.0 - @aws-amplify/amplify-category-custom@2.3.0 - amplify-category-function@3.3.0 - amplify-category-geo@2.2.1 - amplify-category-hosting@3.2.1 - amplify-category-interactions@3.2.1 - amplify-category-predictions@3.2.1 - @aws-amplify/amplify-category-storage@3.0.0 - amplify-category-xr@3.2.1 - amplify-cli-core@2.3.0 - @aws-amplify/cli-extensibility-helper@2.2.1 - @aws-amplify/cli@7.3.0 - amplify-codegen-appsync-model-plugin@1.24.1 - amplify-console-hosting@2.2.1 - amplify-console-integration-tests@2.2.1 - amplify-container-hosting@2.3.0 - amplify-dotnet-function-template-provider@2.2.1 - amplify-dynamodb-simulator@2.2.1 - amplify-e2e-core@2.3.0 - amplify-e2e-tests@3.3.0 - amplify-frontend-android@3.3.0 - amplify-frontend-flutter@1.3.0 - amplify-frontend-ios@3.3.0 - amplify-frontend-javascript@3.3.0 - amplify-go-function-runtime-provider@2.2.1 - amplify-graphiql-explorer@2.3.0 - @aws-amplify/graphql-auth-transformer@0.4.1 - @aws-amplify/graphql-default-value-transformer@0.5.1 - @aws-amplify/graphql-function-transformer@0.6.1 - @aws-amplify/graphql-http-transformer@0.7.1 - @aws-amplify/graphql-index-transformer@0.7.1 - amplify-graphql-migration-tests@2.2.1 - @aws-amplify/graphql-model-transformer@0.9.1 - @aws-amplify/graphql-predictions-transformer@0.5.1 - @aws-amplify/graphql-relational-transformer@0.6.1 - @aws-amplify/graphql-searchable-transformer@0.9.1 - @aws-amplify/graphql-transformer-core@0.12.1 - @aws-amplify/graphql-transformer-interfaces@1.12.1 - @aws-amplify/graphql-transformer-migrator@1.2.1 - amplify-headless-interface@1.13.1 - amplify-java-function-runtime-provider@2.2.1 - amplify-migration-tests@4.3.0 - amplify-nodejs-function-runtime-provider@2.2.1 - amplify-nodejs-function-template-provider@2.2.1 - amplify-prompts@1.5.1 - amplify-provider-awscloudformation@5.3.0 - amplify-python-function-runtime-provider@2.2.1 - amplify-util-headless-input@1.8.1 - amplify-util-import@2.2.1 - amplify-util-mock@4.2.1 - graphql-auth-transformer@7.2.1 - graphql-connection-transformer@5.2.1 - graphql-dynamodb-transformer@7.2.1 - graphql-elasticsearch-transformer@5.2.1 - graphql-function-transformer@3.2.1 - graphql-http-transformer@5.2.1 - graphql-key-transformer@3.2.1 - graphql-mapping-template@4.20.1 - graphql-predictions-transformer@3.2.1 - graphql-relational-schema-transformer@2.20.1 - graphql-transformer-common@4.22.1 - graphql-transformer-core@7.2.1 - graphql-transformers-e2e-tests@7.2.1 - graphql-versioned-transformer@5.2.1 --- packages/amplify-category-api/CHANGELOG.md | 20 ++++++++++++++++++++ packages/amplify-category-api/package.json | 16 ++++++++-------- 2 files changed, 28 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ee225afd34..7c90d836a8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,26 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 403a793f02..a39806e571 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.2.0", + "version": "3.3.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.0", + "@aws-amplify/graphql-transformer-migrator": "1.2.1", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,17 +64,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.2.0", - "amplify-headless-interface": "1.13.0", - "amplify-prompts": "1.5.0", + "amplify-cli-core": "2.3.0", + "amplify-headless-interface": "1.13.1", + "amplify-prompts": "1.5.1", "amplify-provider-awscloudformation": "4.61.1", - "amplify-util-headless-input": "1.8.0", + "amplify-util-headless-input": "1.8.1", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.20.0", - "graphql-transformer-core": "7.2.0", + "graphql-relational-schema-transformer": "2.20.1", + "graphql-transformer-core": "7.2.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 5a4fc2ee16a4848b3ac699ea3caf719a1765148c Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Thu, 11 Nov 2021 11:53:28 -0800 Subject: [PATCH 497/587] fix(graphql): refactor lambda authorizer code to use function category to create authorizer function (#8784) * initial commit * add template to provider * use function category to create lambda auth function * improve condition for default defined scenario * fix(function): codereview comments on skipAdvancedSection and skipNextSteps * lint fixes --- .../graphql-lambda-authorizer-index.js | 25 --- ...graphql-lambda-authorizer-package.json.ejs | 6 - ...raphql-lambda-authorizer-template.json.ejs | 208 ------------------ .../appSync-walkthrough.ts | 53 ++--- 4 files changed, 16 insertions(+), 276 deletions(-) delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs delete mode 100644 packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js deleted file mode 100644 index 20f0971452..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-index.js +++ /dev/null @@ -1,25 +0,0 @@ -// This is sample code. Please update this to suite your schema - -exports.handler = async (event) => { - console.log(`event >`, JSON.stringify(event, null, 2)); - const { - authorizationToken, - requestContext: { apiId, accountId }, - } = event; - const response = { - isAuthorized: authorizationToken === 'custom-authorized', - resolverContext: { - userid: 'user-id', - info: 'contextual information A', - more_info: 'contextual information B', - }, - deniedFields: [ - `arn:aws:appsync:${process.env.AWS_REGION}:${accountId}:apis/${apiId}/types/Event/fields/comments`, - `Mutation.createEvent`, - ], - ttlOverride: 300, - }; - console.log(`response >`, JSON.stringify(response, null, 2)); - return response; -}; - diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs deleted file mode 100644 index e2f9e8b41d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-package.json.ejs +++ /dev/null @@ -1,6 +0,0 @@ -{ - "name": "<%= props.functionName %>", - "version": "1.0.0", - "description": "Lambda function generated by Amplify for AppSync Lambda authorizer", - "main": "index.js" -} diff --git a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs b/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs deleted file mode 100644 index acd908246d..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/graphql-lambda-authorizer/graphql-lambda-authorizer-template.json.ejs +++ /dev/null @@ -1,208 +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": "nodejs14.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/*" - ] - ] - } - <% } %> - ] - } - <% } %> - ] - } - } - } - ,"PermissionForAppSyncToInvokeLambda": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "FunctionName": { - "Ref": "LambdaFunction" - }, - "Action": "lambda:InvokeFunction", - "Principal": "appsync.amazonaws.com" - } - } - <% 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/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index 933134e813..52de5b0701 100644 --- 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 @@ -1143,46 +1143,25 @@ async function askLambdaFromProject(context: $TSContext) { } async function createLambdaAuthorizerFunction(context: $TSContext) { - const targetDir = context.amplify.pathManager.getBackendDirPath(); - const assetDir = path.normalize(path.join(rootAssetDir, 'graphql-lambda-authorizer')); const [shortId] = uuid().split('-'); - const functionName = `graphQlLambdaAuthorizer${shortId}`; - - const functionProps = { - functionName: `${functionName}`, - roleName: `${functionName}LambdaRole`, - }; - - const copyJobs = [ - { - dir: assetDir, - template: 'graphql-lambda-authorizer-index.js', - target: `${targetDir}/function/${functionName}/src/index.js`, - }, - { - dir: assetDir, - template: 'graphql-lambda-authorizer-package.json.ejs', - target: `${targetDir}/function/${functionName}/src/package.json`, - }, + const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ + context, + 'awscloudformation', + FunctionServiceNameLambdaFunction, { - dir: assetDir, - template: 'graphql-lambda-authorizer-template.json.ejs', - target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + functionName, + defaultRuntime: 'nodejs', + providerContext: { + provider: 'awscloudformation', + }, + template: 'lambda-auth', + skipAdvancedSection: true, + skipNextSteps: true, }, - ]; + ]); - // copy over the files - await context.amplify.copyBatch(context, copyJobs, functionProps, true); - - const backendConfigs = { - service: FunctionServiceNameLambdaFunction, - providerPlugin: provider, - build: true, - }; - - await context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - context.print.success(`Successfully added ${functionName} function locally`); - - return functionName; + context.print.success(`Successfully added ${resourceName} function locally`); + await context.amplify.invokePluginMethod(context, 'function', undefined, 'addAppSyncInvokeMethodPermission', [resourceName]); + return resourceName; } From 1e9ee8618d1c9a954cf7bbf6f8f617077357e27f Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Fri, 12 Nov 2021 08:54:56 -0800 Subject: [PATCH 498/587] fix(graphql): detect resource update on graphql api auth mode change (#8782) * fix(graphql): detect resource update on graphql api auth mode change * reuse auth mode update function * compare complete auth config except api expiration date * move auth mode compare to a separate file; * change clone logic for previous auth config --- .../awscloudformation/cfn-api-artifact-handler.ts | 3 +++ 1 file changed, 3 insertions(+) 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 index f06fc27941..d18bbae607 100644 --- 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 @@ -111,6 +111,8 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await writeResolverConfig(updates.conflictResolution, resourceDir); } const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); + const previousAuthConfig = _.cloneDeep(authConfig); + const oldConfigHadApiKey = authConfigHasApiKey(authConfig); if (updates.defaultAuthType) { authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); @@ -124,6 +126,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { resourceDir, parameters: this.getCfnParameters(apiName, authConfig, resourceDir), authConfig, + previousAuthConfig, }); } From 60e334de9bac17e3a6321b3252e299faebcb98bf Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 17 Nov 2021 07:56:44 +0000 Subject: [PATCH 499/587] chore(release): Publish [ci skip] - amplify-app@4.2.2 - amplify-appsync-simulator@2.2.2 - amplify-category-analytics@3.2.2 - amplify-category-api@3.3.1 - @aws-amplify/amplify-category-auth@2.3.3 - @aws-amplify/amplify-category-custom@2.3.1 - amplify-category-function@3.3.1 - amplify-category-geo@2.2.2 - amplify-category-hosting@3.2.2 - amplify-category-interactions@3.2.2 - amplify-category-predictions@3.2.2 - @aws-amplify/amplify-category-storage@3.0.3 - amplify-category-xr@3.2.2 - amplify-cli-core@2.3.1 - @aws-amplify/cli-extensibility-helper@2.2.2 - @aws-amplify/cli@7.3.6 - amplify-console-hosting@2.2.2 - amplify-console-integration-tests@2.2.3 - amplify-container-hosting@2.3.1 - amplify-dotnet-function-runtime-provider@1.6.4 - amplify-dotnet-function-template-provider@2.2.2 - amplify-dynamodb-simulator@2.2.2 - amplify-e2e-core@2.3.2 - amplify-e2e-tests@3.4.0 - amplify-frontend-ios@3.3.1 - amplify-frontend-javascript@3.3.1 - amplify-function-plugin-interface@1.9.2 - amplify-go-function-runtime-provider@2.2.2 - amplify-go-function-template-provider@1.3.11 - @aws-amplify/graphql-auth-transformer@0.4.2 - @aws-amplify/graphql-default-value-transformer@0.5.2 - @aws-amplify/graphql-function-transformer@0.6.2 - @aws-amplify/graphql-http-transformer@0.7.2 - @aws-amplify/graphql-index-transformer@0.7.2 - amplify-graphql-migration-tests@2.2.2 - @aws-amplify/graphql-model-transformer@0.9.2 - @aws-amplify/graphql-predictions-transformer@0.5.2 - @aws-amplify/graphql-relational-transformer@0.6.2 - @aws-amplify/graphql-searchable-transformer@0.9.2 - @aws-amplify/graphql-transformer-core@0.13.0 - @aws-amplify/graphql-transformer-interfaces@1.12.2 - @aws-amplify/graphql-transformer-migrator@1.2.2 - amplify-java-function-runtime-provider@2.2.2 - amplify-java-function-template-provider@1.5.10 - amplify-migration-tests@4.3.2 - amplify-nodejs-function-runtime-provider@2.2.2 - amplify-nodejs-function-template-provider@2.2.2 - amplify-provider-awscloudformation@5.4.0 - amplify-python-function-runtime-provider@2.2.2 - amplify-python-function-template-provider@1.3.13 - amplify-util-import@2.2.2 - amplify-util-mock@4.2.5 - graphql-auth-transformer@7.2.2 - graphql-connection-transformer@5.2.2 - graphql-dynamodb-transformer@7.2.2 - graphql-elasticsearch-transformer@5.2.2 - graphql-function-transformer@3.2.2 - graphql-http-transformer@5.2.2 - graphql-key-transformer@3.2.2 - graphql-predictions-transformer@3.2.2 - graphql-relational-schema-transformer@2.20.2 - graphql-transformer-common@4.22.2 - graphql-transformer-core@7.2.2 - graphql-transformers-e2e-tests@7.3.0 - graphql-versioned-transformer@5.2.2 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7c90d836a8..849bc29b03 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a39806e571..332b1ce0c8 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.3.0", + "version": "3.3.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.1", + "@aws-amplify/graphql-transformer-migrator": "1.2.2", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,7 +64,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.3.0", + "amplify-cli-core": "2.3.1", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.5.1", "amplify-provider-awscloudformation": "4.61.1", @@ -73,8 +73,8 @@ "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.20.1", - "graphql-transformer-core": "7.2.1", + "graphql-relational-schema-transformer": "2.20.2", + "graphql-transformer-core": "7.2.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 16f327536d9cdd551a0a1a62c93f82a242eb0a59 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Thu, 18 Nov 2021 18:30:14 -0800 Subject: [PATCH 500/587] chore(release): Publish [ci skip] (#8955) - amplify-category-api@3.3.2 - @aws-amplify/cli@7.4.2 - amplify-container-hosting@2.3.2 - @aws-amplify/graphql-auth-transformer@0.4.3 - amplify-graphql-migration-tests@2.2.3 - @aws-amplify/graphql-relational-transformer@0.6.3 - @aws-amplify/graphql-searchable-transformer@0.9.3 - @aws-amplify/graphql-transformer-migrator@1.2.3 - amplify-provider-awscloudformation@5.4.2 - amplify-util-mock@4.2.7 Co-authored-by: aws-amplify-bot --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 849bc29b03..d1aa8409c8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 332b1ce0c8..eac6e35fa2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.3.1", + "version": "3.3.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.2", + "@aws-amplify/graphql-transformer-migrator": "1.2.3", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", From edb776b60f860484c0d4f2bd45867f8b59473af8 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 19 Nov 2021 21:42:43 +0000 Subject: [PATCH 501/587] chore(release): Publish [ci skip] - amplify-category-api@3.3.3 - @aws-amplify/amplify-category-auth@2.3.6 - @aws-amplify/cli@7.4.3 - amplify-container-hosting@2.3.3 - @aws-amplify/graphql-auth-transformer@0.4.4 - @aws-amplify/graphql-default-value-transformer@0.5.3 - @aws-amplify/graphql-function-transformer@0.6.3 - @aws-amplify/graphql-http-transformer@0.7.3 - @aws-amplify/graphql-index-transformer@0.7.3 - amplify-graphql-migration-tests@2.2.4 - @aws-amplify/graphql-model-transformer@0.9.3 - @aws-amplify/graphql-predictions-transformer@0.5.3 - @aws-amplify/graphql-relational-transformer@0.6.4 - @aws-amplify/graphql-searchable-transformer@0.9.4 - @aws-amplify/graphql-transformer-core@0.13.1 - @aws-amplify/graphql-transformer-migrator@1.2.4 - amplify-provider-awscloudformation@5.4.3 - amplify-util-mock@4.2.8 - graphql-transformers-e2e-tests@7.3.1 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index d1aa8409c8..c07af7475f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index eac6e35fa2..31a7eaa7ef 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.3.2", + "version": "3.3.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.3", + "@aws-amplify/graphql-transformer-migrator": "1.2.4", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", From 452fece5eb75445e8f6ce8f2450eff7e251b403e Mon Sep 17 00:00:00 2001 From: Kaustav Ghosh Date: Fri, 19 Nov 2021 16:24:44 -0800 Subject: [PATCH 502/587] fix: remove await from sync read cfn calls (#8977) Co-authored-by: Ghosh --- .../awscloudformation/utils/containers-artifacts.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 index 51da9da2da..dbce76b2fa 100644 --- 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 @@ -288,9 +288,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s secretsArns.set(secretName, secretArn); } } else { - const { cfnTemplate } = await readCFNTemplate( - path.join(pathManager.getBackendDirPath(), category, resourceName, cfnFileName(resourceName)), - ); + const { cfnTemplate } = readCFNTemplate(path.join(pathManager.getBackendDirPath(), category, resourceName, cfnFileName(resourceName))); setExistingSecretArns(secretsArns, cfnTemplate); } From 6e797a4fde1c4ae243604ba27b85e1520c660e3c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sat, 20 Nov 2021 01:57:07 +0000 Subject: [PATCH 503/587] chore(release): Publish [ci skip] - amplify-app@4.2.3 - amplify-category-analytics@3.2.3 - amplify-category-api@3.3.4 - @aws-amplify/amplify-category-auth@2.3.7 - @aws-amplify/amplify-category-custom@2.3.2 - amplify-category-function@3.3.2 - amplify-category-geo@2.2.3 - amplify-category-hosting@3.2.3 - amplify-category-interactions@3.2.3 - amplify-category-predictions@3.2.3 - @aws-amplify/amplify-category-storage@3.0.4 - amplify-category-xr@3.2.3 - amplify-cli-core@2.3.2 - @aws-amplify/cli-extensibility-helper@2.2.3 - @aws-amplify/cli@7.4.4 - amplify-console-hosting@2.2.3 - amplify-console-integration-tests@2.2.4 - amplify-container-hosting@2.3.4 - amplify-dotnet-function-template-provider@2.2.3 - amplify-dynamodb-simulator@2.2.3 - amplify-e2e-core@2.3.3 - amplify-e2e-tests@3.4.1 - amplify-frontend-ios@3.3.2 - amplify-frontend-javascript@3.3.2 - amplify-go-function-runtime-provider@2.2.3 - @aws-amplify/graphql-auth-transformer@0.4.5 - amplify-graphql-migration-tests@2.2.5 - @aws-amplify/graphql-relational-transformer@0.6.5 - @aws-amplify/graphql-transformer-migrator@1.2.5 - amplify-java-function-runtime-provider@2.2.3 - amplify-migration-tests@4.3.3 - amplify-nodejs-function-runtime-provider@2.2.3 - amplify-nodejs-function-template-provider@2.2.3 - amplify-provider-awscloudformation@5.5.0 - amplify-python-function-runtime-provider@2.2.3 - amplify-util-import@2.2.3 - amplify-util-mock@4.2.9 - graphql-auth-transformer@7.2.3 - graphql-connection-transformer@5.2.3 - graphql-dynamodb-transformer@7.2.3 - graphql-elasticsearch-transformer@5.2.3 - graphql-function-transformer@3.2.3 - graphql-http-transformer@5.2.3 - graphql-key-transformer@3.2.3 - graphql-predictions-transformer@3.2.3 - graphql-transformer-core@7.2.3 - graphql-transformers-e2e-tests@7.3.2 - graphql-versioned-transformer@5.2.3 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index c07af7475f..ab87181a07 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 31a7eaa7ef..0c30f844b4 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.3.3", + "version": "3.3.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.4", + "@aws-amplify/graphql-transformer-migrator": "1.2.5", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,7 +64,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.3.1", + "amplify-cli-core": "2.3.2", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.5.1", "amplify-provider-awscloudformation": "4.61.1", @@ -74,7 +74,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.20.2", - "graphql-transformer-core": "7.2.2", + "graphql-transformer-core": "7.2.3", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 9c649cb1692a880fe879287f94dbc628a48ed097 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 21 Nov 2021 18:13:32 +0000 Subject: [PATCH 504/587] chore(release): Publish [ci skip] - amplify-app@4.2.4 - amplify-category-analytics@3.2.4 - amplify-category-api@3.3.5 - @aws-amplify/amplify-category-auth@2.3.8 - @aws-amplify/amplify-category-custom@2.3.3 - amplify-category-function@3.3.3 - amplify-category-geo@2.2.4 - amplify-category-hosting@3.2.4 - amplify-category-interactions@3.2.4 - amplify-category-predictions@3.2.4 - @aws-amplify/amplify-category-storage@3.0.5 - amplify-category-xr@3.2.4 - amplify-cli-core@2.3.3 - @aws-amplify/cli-extensibility-helper@2.2.4 - @aws-amplify/cli@7.4.5 - amplify-console-hosting@2.2.4 - amplify-console-integration-tests@2.2.5 - amplify-container-hosting@2.3.5 - amplify-dotnet-function-template-provider@2.2.4 - amplify-dynamodb-simulator@2.2.4 - amplify-e2e-core@2.3.4 - amplify-e2e-tests@3.4.2 - amplify-frontend-ios@3.3.3 - amplify-frontend-javascript@3.3.3 - amplify-go-function-runtime-provider@2.2.4 - @aws-amplify/graphql-auth-transformer@0.4.6 - @aws-amplify/graphql-default-value-transformer@0.5.4 - @aws-amplify/graphql-function-transformer@0.6.4 - @aws-amplify/graphql-http-transformer@0.7.4 - @aws-amplify/graphql-index-transformer@0.7.4 - amplify-graphql-migration-tests@2.2.6 - @aws-amplify/graphql-model-transformer@0.9.4 - @aws-amplify/graphql-predictions-transformer@0.5.4 - @aws-amplify/graphql-relational-transformer@0.6.6 - @aws-amplify/graphql-searchable-transformer@0.9.5 - @aws-amplify/graphql-transformer-core@0.13.2 - @aws-amplify/graphql-transformer-interfaces@1.12.3 - @aws-amplify/graphql-transformer-migrator@1.2.6 - amplify-java-function-runtime-provider@2.2.4 - amplify-migration-tests@4.3.4 - amplify-nodejs-function-runtime-provider@2.2.4 - amplify-nodejs-function-template-provider@2.2.4 - amplify-provider-awscloudformation@5.5.1 - amplify-python-function-runtime-provider@2.2.4 - amplify-util-import@2.2.4 - amplify-util-mock@4.2.10 - graphql-auth-transformer@7.2.4 - graphql-connection-transformer@5.2.4 - graphql-dynamodb-transformer@7.2.4 - graphql-elasticsearch-transformer@5.2.4 - graphql-function-transformer@3.2.4 - graphql-http-transformer@5.2.4 - graphql-key-transformer@3.2.4 - graphql-predictions-transformer@3.2.4 - graphql-transformer-core@7.2.4 - graphql-transformers-e2e-tests@7.3.3 - graphql-versioned-transformer@5.2.4 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ab87181a07..42a4403117 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0c30f844b4..6bf484d6bf 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "amplify-category-api", - "version": "3.3.4", + "version": "3.3.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -17,7 +17,7 @@ "test": "jest" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.5", + "@aws-amplify/graphql-transformer-migrator": "1.2.6", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -64,7 +64,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.3.2", + "amplify-cli-core": "2.3.3", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.5.1", "amplify-provider-awscloudformation": "4.61.1", @@ -74,7 +74,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.20.2", - "graphql-transformer-core": "7.2.3", + "graphql-transformer-core": "7.2.4", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 02c0ea106d1101cf9eb30b725dde3e99a48986d4 Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Mon, 22 Nov 2021 17:03:34 -0800 Subject: [PATCH 505/587] feat: override support for api category (#9013) * Api ext rebase 3 (#9001) * feat: extensibility for Amplify API (#8954) * feat: REST API extensibility (#8958) * fix: rebase fixes and bugs (#8960) * fix: rebase fixes and bugs * fix: service walkthrough call for appsync * fix: enable skeleton generation transformerFF is false (#8967) * feat: add min / max selection to prompter.pick (#8971) * fix: error handling, various bugs (#8976) * fix: tsconfig changes and renames (#8975) * fix: asana bug fixes * chore: allow js to false * fix: migration flow and cfn params when user pool groups are present, types (#8981) * fix: cfn parameters when user pool groups are present * fix: policy generation for user pool groups * fix: update types * test: fix project deletion even if meta validation fails * fix: rest iam policy roles array, bump ext helper types version (#8983) * fix: headless api migration (#8992) * fix: schema path inconsistencies, guest permissions, e2e * fix: api migration version e2es (#9000) Co-authored-by: John Hockett Co-authored-by: Edward Foyle Co-authored-by: jhockett * fix: add missing ref call during rest stack generation, path casing (#9002) * fix: updates schema path on update api (#9005) * fix: api7 and api-migration tests (#9006) * fix: updates resource to resources and remove green ticks (#9007) * fix: overriding multiple userPoolGroups, ext helper type, lambda cfn (#9008) * fix: multiple userPoolGroups overwriting eachother * chore: update exported ext helper type * fix: lambda permissions not being generated * test: moved migration test and fixed the workflow (#9010) * test: moved migration test and fixed the workflow * test: remove jest settimeout Co-authored-by: AmmarKarachi * fix: add missing property on path in cfn (#9011) * test: fixed integ test walkthrough (#9012) Co-authored-by: AmmarKarachi * test: separate migration test helper from e2e (#9014) * fix: prediction migration test fix (#9015) * test: fix api_5.test.ts (#9017) * fix: single userpoolgroup name is iterated instead of being used (#9020) Co-authored-by: Sachin Panemangalore * test: add missing option to e2e test (#9024) * fix: bucket parameters fetch logic (#9027) * fix: bucket parameters fetch logic * fix: address comments * fix: bucket parameters fetch logic (#9028) * fix: multiselect returns array when autoselecting (#9029) * fix: APIGW overrides package.json (#9032) * fix: package json dependencies * chore: new line at end of package.json * fix: migration of Admin Queries on override command (#9031) * fix: migration of Admin Queries on override command * fix: address feedback * feat: descoped http and functions override (#9035) * fix: address feedback (#9038) * fix: addressed comments (#9039) * fix: addressed comments * Update packages/amplify-provider-awscloudformation/src/download-api-models.ts Co-authored-by: Ammar <56042290+ammarkarachi@users.noreply.github.com> Co-authored-by: Ammar <56042290+ammarkarachi@users.noreply.github.com> Co-authored-by: akshbhu <39866697+akshbhu@users.noreply.github.com> Co-authored-by: John Hockett Co-authored-by: Edward Foyle Co-authored-by: jhockett Co-authored-by: AmmarKarachi Co-authored-by: Sachin Panemangalore <83682223+sachscode@users.noreply.github.com> Co-authored-by: Sachin Panemangalore --- packages/amplify-category-api/.npmignore | 2 + .../amplify-category-api/amplify-plugin.json | 14 +- packages/amplify-category-api/package.json | 12 +- ...w-cloudformation-template-default.json.ejs | 512 ------------- .../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 + .../APIGatewayCLIInputs.schema.json | 65 ++ .../appsync/AppSyncCLIInputs.schema.json | 289 ++++++++ .../scripts/generateApiSchemas.ts | 17 + ...test.js => add-graphql-datasource.test.ts} | 4 +- .../appsync-api-input-state.test.ts | 48 ++ .../apigw-input-state.test.ts | 240 +++++++ .../cfn-api-artifact-handler.test.ts | 149 +++- .../legacy-add-resource.test.ts | 20 +- .../legacy-update-resource.test.ts | 16 +- .../appSync-walkthrough.test.ts | 40 +- .../get-appsync-auth-config.test.ts.snap | 28 + .../utils/get-appsync-auth-config.test.ts | 55 ++ .../migrate-api-override-resource.test.ts | 79 ++ .../utils/rest-api-path-utils.test.ts | 8 +- .../src/category-constants.ts | 5 +- .../amplify-category-api/src/commands/api.js | 59 -- .../amplify-category-api/src/commands/api.ts | 64 ++ .../commands/api/add-graphql-datasource.ts | 252 ++++--- .../src/commands/api/add.js | 75 -- .../src/commands/api/add.ts | 62 ++ .../src/commands/api/console.js | 25 - .../src/commands/api/console.ts | 22 + .../src/commands/api/gql-compile.js | 20 - .../src/commands/api/gql-compile.ts | 15 + .../src/commands/api/migrate.ts | 10 +- .../src/commands/api/override.ts | 99 +++ .../src/commands/api/push.js | 17 - .../src/commands/api/push.ts | 11 + .../src/commands/api/rebuild.ts | 5 +- .../src/commands/api/remove.js | 31 - .../src/commands/api/remove.ts | 30 + .../src/commands/api/update.js | 29 - .../src/commands/api/update.ts | 24 + packages/amplify-category-api/src/index.ts | 171 +++-- .../appsync-api-input-state.ts | 42 ++ .../awscloudformation/apigw-input-state.ts | 247 +++++++ .../awscloudformation/aws-constants.ts | 4 +- .../cdk-stack-builder/apigw-stack-builder.ts | 471 ++++++++++++ .../apigw-stack-transform.ts | 251 +++++++ .../cdk-stack-builder/index.ts | 3 + .../cdk-stack-builder/types.ts | 53 ++ .../cfn-api-artifact-handler.ts | 109 ++- .../awscloudformation/containers-handler.ts | 45 +- .../{apigw-defaults.js => apigw-defaults.ts} | 8 +- ...ppSync-defaults.js => appSync-defaults.ts} | 9 +- .../default-values/containers-defaults.ts | 8 +- .../awscloudformation/docker-compose/index.ts | 4 +- .../awscloudformation/ecs-alb-stack.ts | 2 +- .../provider-utils/awscloudformation/index.ts | 176 +++-- .../awscloudformation/legacy-add-resource.ts | 20 +- .../legacy-update-resource.ts | 19 +- .../aPIGateway-user-input-types.ts | 37 + .../service-walkthrough-types/apigw-types.ts | 28 + .../appsync-user-input-types.ts | 175 +++++ .../service-walkthroughs/apigw-walkthrough.ts | 679 +++++++----------- .../appSync-rds-walkthrough.ts | 33 +- .../appSync-walkthrough.ts | 204 +++--- .../containers-walkthrough.ts | 27 +- .../utils/amplify-meta-utils.ts | 24 +- .../utils/check-appsync-api-migration.ts | 19 + .../utils/containers-artifacts.ts | 21 +- .../utils/dynamic-imports.ts | 14 +- .../utils/edit-schema-flow.ts | 20 +- .../utils/get-appsync-auth-config.ts | 18 + .../utils/get-appsync-resolver-config.ts | 15 + .../utils/getAppSyncApiName.ts | 15 + .../utils/migrate-api-override-resource.ts | 120 ++++ .../utils/print-api-key-warnings.ts | 16 +- .../utils/rest-api-path-utils.ts | 4 +- .../provider-utils/supported-datasources.ts | 1 - .../src/provider-utils/supported-services.ts | 3 - packages/amplify-category-api/tsconfig.json | 5 +- 84 files changed, 3860 insertions(+), 1801 deletions(-) delete mode 100644 packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json create mode 100644 packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json create mode 100644 packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json create mode 100644 packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json create mode 100644 packages/amplify-category-api/scripts/generateApiSchemas.ts rename packages/amplify-category-api/src/__tests__/commands/api/{add-graphql-datasource.test.js => add-graphql-datasource.test.ts} (87%) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts create 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/commands/api.js create mode 100644 packages/amplify-category-api/src/commands/api.ts delete mode 100644 packages/amplify-category-api/src/commands/api/add.js create mode 100644 packages/amplify-category-api/src/commands/api/add.ts delete mode 100644 packages/amplify-category-api/src/commands/api/console.js create mode 100644 packages/amplify-category-api/src/commands/api/console.ts delete mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.js create mode 100644 packages/amplify-category-api/src/commands/api/gql-compile.ts create mode 100644 packages/amplify-category-api/src/commands/api/override.ts delete mode 100644 packages/amplify-category-api/src/commands/api/push.js create mode 100644 packages/amplify-category-api/src/commands/api/push.ts delete mode 100644 packages/amplify-category-api/src/commands/api/remove.js create mode 100644 packages/amplify-category-api/src/commands/api/remove.ts delete mode 100644 packages/amplify-category-api/src/commands/api/update.js create mode 100644 packages/amplify-category-api/src/commands/api/update.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{apigw-defaults.js => apigw-defaults.ts} (68%) rename packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/{appSync-defaults.js => appSync-defaults.ts} (71%) create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/aPIGateway-user-input-types.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/apigw-types.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts diff --git a/packages/amplify-category-api/.npmignore b/packages/amplify-category-api/.npmignore index 89eeb1ee92..a1f3bf2a32 100644 --- a/packages/amplify-category-api/.npmignore +++ b/packages/amplify-category-api/.npmignore @@ -3,3 +3,5 @@ ./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/amplify-plugin.json b/packages/amplify-category-api/amplify-plugin.json index 21548e0f39..f9ee43e924 100644 --- a/packages/amplify-category-api/amplify-plugin.json +++ b/packages/amplify-category-api/amplify-plugin.json @@ -1,7 +1,19 @@ { "name": "api", "type": "category", - "commands": ["add-graphql-datasource", "add", "console", "gql-compile", "migrate", "push", "rebuild", "remove", "update", "help"], + "commands": [ + "add-graphql-datasource", + "add", + "console", + "gql-compile", + "migrate", + "override", + "push", + "rebuild", + "remove", + "update", + "help" + ], "commandAliases": { "configure": "update" }, diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 6bf484d6bf..aefe311abc 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { - "name": "amplify-category-api", - "version": "3.3.5", + "name": "@aws-amplify/amplify-category-api", + "version": "1.0.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -14,7 +14,11 @@ "build": "tsc", "watch": "tsc -w", "clean": "rimraf lib tsconfig.tsbuildinfo", - "test": "jest" + "test": "jest", + "generateSchemas": "ts-node ./scripts/generateApiSchemas.ts" + }, + "publishConfig": { + "access": "public" }, "dependencies": { "@aws-amplify/graphql-transformer-migrator": "1.2.6", @@ -79,7 +83,7 @@ "js-yaml": "^4.0.0", "lodash": "^4.17.21", "ora": "^4.0.3", - "uuid": "^3.4.0" + "uuid": "^8.3.2" }, "devDependencies": { "@types/js-yaml": "^4.0.0" diff --git a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs b/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs deleted file mode 100644 index 959fb43c00..0000000000 --- a/packages/amplify-category-api/resources/awscloudformation/cloudformation-templates/apigw-cloudformation-template-default.json.ejs +++ /dev/null @@ -1,512 +0,0 @@ -{ - "AWSTemplateFormatVersion": "2010-09-09", - "Description": "API Gateway resource stack creation using Amplify CLI", - <% if (props.dependsOn) { %> - "Parameters": { - "env": { - "Type": "String" - }<%if (props.dependsOn && props.dependsOn.length > 0) { %>,<% } %> - <% 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": { - <% for(var i=0; i < props.paths.length; i++) { %> - <%if (props.paths[i].privacy && props.paths[i].privacy.userPoolGroups) { %> - <% let selectedUserPoolGroupList = Object.keys(props.paths[i].privacy.userPoolGroups); %> - <% for(var j=0; j < selectedUserPoolGroupList.length; j++) { %> - "<%=selectedUserPoolGroupList[j]%>Group<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>Policy": { - "DependsOn": [ - "<%= props.apiName %>" - ], - "Type": "AWS::IAM::Policy", - "Properties": { - "PolicyName": "<%= props.apiName %>-<%= props.paths[i].name.replace(/[^-a-z0-9]/g, '')%>-<%=selectedUserPoolGroupList[j]%>-group-policy", - "Roles": [ - { - "Fn::Join": [ - "", - [ - { - "Ref": "auth<%= props.authResourceName%>UserPoolId" - }, - "-<%=selectedUserPoolGroupList[j]%>GroupRole" - ] - ] - } - ], - "PolicyDocument": { - "Version": "2012-10-17", - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "execute-api:Invoke" - ], - "Resource": [ - - <% for(var x=0; x < props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length; x++) { %> - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].policyResourceName %>/*" - ] - ] - }, - { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/", - { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "<%= props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]][x] %>", - "<%= props.paths[i].policyResourceName %>" - ] - ] - } - <% if (x !== props.paths[i].privacy.userPoolGroups[selectedUserPoolGroupList[j]].length - 1) { %> - , - <% } %> - <% } %> - ] - } - ] - } - } - }, - <% } %> - <% } %> - <% } %> - "<%= props.apiName %>": { - "Type": "AWS::ApiGateway::RestApi", - "Properties": { - "Description": "", - "Name": "<%= props.apiName %>", - "Body": { - "swagger": "2.0", - "info": { - "version": "2018-05-24T17:52:00Z", - "title": "<%= props.apiName %>" - }, - "host": { - "Fn::Join": [ - "", - [ - "apigateway.", - { - "Ref": "AWS::Region" - }, - ".amazonaws.com" - ] - ] - }, - "basePath": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "/Prod", - { - "Fn::Join": [ - "", - [ - "/", - { - "Ref": "env" - } - ] - ] - } - ] - }, - "schemes": [ - "https" - ], - "paths": { - <% for(var i=0; i < props.paths.length; i++) { %> - "<%= props.paths[i].name %>": { - "options": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "200 response", - "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,X-Amz-User-Agent'", - "method.response.header.Access-Control-Allow-Origin": "'*'" - } - } - }, - "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" - } - } - }, - <%if (!props.paths[i].privacy.open) { %> - "security": [ - { - "sigv4": [] - } - ], - <% } %> - "x-amazon-apigateway-integration": { - "responses": { - "default": { - "statusCode": "200" - } - }, - "uri": { - "Fn::Join": [ - "", - [ - "arn:aws:apigateway:", - { - "Ref": "AWS::Region" - }, - ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn ) { %> - "<%= props.paths[i].lambdaArn %>", - <% } else { %> - { - - "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" - }, - <% } %> - "/invocations" - ] - ] - }, - "passthroughBehavior": "when_no_match", - "httpMethod": "POST", - "type": "aws_proxy" - } - } - }, - "<%= props.paths[i].name %>/{proxy+}": { - "options": { - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], - "responses": { - "200": { - "description": "200 response", - "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,X-Amz-User-Agent'", - "method.response.header.Access-Control-Allow-Origin": "'*'" - } - } - }, - "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" - } - } - }, - <%if (!props.paths[i].privacy.open) { %> - "security": [ - { - "sigv4": [] - } - ], - <% } %> - "x-amazon-apigateway-integration": { - "responses": { - "default": { - "statusCode": "200" - } - }, - "uri": { - "Fn::Join": [ - "", - [ - "arn:aws:apigateway:", - { - "Ref": "AWS::Region" - }, - ":lambda:path/2015-03-31/functions/", - <% if (props.paths[i].lambdaArn) { %> - "<%= props.paths[i].lambdaArn %>", - <% } else { %> - { - - "Ref": "function<%= props.paths[i].lambdaFunction %>Arn" - }, - <% } %> - "/invocations" - ] - ] - }, - "passthroughBehavior": "when_no_match", - "httpMethod": "POST", - "type": "aws_proxy" - } - } - }<% if (i !== props.paths.length - 1) { %>,<% } %> - <% } %> - }, - "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" - } - } - }, - "FailOnWarnings": true - } - }, - - <%if (props.functionArns) { %> - <% for (var i=0; i < props.functionArns.length; i++) { %> - - "function<%= props.functionArns[i].lambdaFunction.replace(/[^0-9a-zA-Z]/gi, '') %>Permission<%= props.apiName %>": { - "Type": "AWS::Lambda::Permission", - "Properties": { - "FunctionName": <% if (props.functionArns[i].lambdaArn) {%> "<%= props.functionArns[i].lambdaArn %>", <% } else { %> - { - "Ref": "function<%= props.functionArns[i].lambdaFunction %>Name" - }, - <% } %> - "Action": "lambda:InvokeFunction", - "Principal": "apigateway.amazonaws.com", - "SourceArn": { - "Fn::Join": [ - "", - [ - "arn:aws:execute-api:", - { - "Ref": "AWS::Region" - }, - ":", - { - "Ref": "AWS::AccountId" - }, - ":", - { - "Ref": "<%= props.apiName %>" - }, - "/*/*/*" - ] - ] - } - } - }, - <% } %> - <% } %> - - "DeploymentAPIGW<%= props.apiName %><%= props.uuid %>": { - "Type": "AWS::ApiGateway::Deployment", - "Properties": { - "Description": "The Development stage deployment of your API.", - "StageName": { - "Fn::If": [ - "ShouldNotCreateEnvResources", - "Prod", - { - "Ref": "env" - } - ] - }, - "RestApiId": { - "Ref": "<%= props.apiName %>" - } - } - } - }, - "Outputs": { - "RootUrl": { - "Description": "Root URL of the API gateway", - "Value": {"Fn::Join": ["", ["https://", {"Ref": "<%= props.apiName %>"}, ".execute-api.", {"Ref": "AWS::Region"}, ".amazonaws.com/", {"Fn::If": ["ShouldNotCreateEnvResources","Prod", {"Ref": "env"} ]}]]} - }, - "ApiName": { - "Description": "API Friendly name", - "Value": "<%= props.resourceName %>" - }, - "ApiId": { - "Description": "API ID (prefix of API URL)", - "Value": {"Ref": "<%= props.apiName %>"} - } - } - } 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 new file mode 100644 index 0000000000..e0bc1fca53 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/override.ts.sample @@ -0,0 +1,6 @@ +// This file is used to override the REST API resources configuration +import { AmplifyApiRestResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper'; + +export function override(resources: AmplifyApiRestResourceStackTemplate) { + +} 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 new file mode 100644 index 0000000000..6715c04ecd --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json @@ -0,0 +1,15 @@ +{ + "name": "overrides", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "tsc", + "watch": "tsc -w" + }, + "dependencies": { + "@aws-amplify/cli-extensibility-helper": "2.3.0" + }, + "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 new file mode 100644 index 0000000000..c6f1a33b4d --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.json @@ -0,0 +1,11 @@ +{ + "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 new file mode 100644 index 0000000000..6504da8028 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/tsconfig.resource.json @@ -0,0 +1,13 @@ +{ + "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 new file mode 100644 index 0000000000..936014b287 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/override.ts.sample @@ -0,0 +1,5 @@ +import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper'; + +export function override(resources: AmplifyApiGraphQlResourceStackTemplate) { + +} 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 new file mode 100644 index 0000000000..6715c04ecd --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json @@ -0,0 +1,15 @@ +{ + "name": "overrides", + "version": "1.0.0", + "description": "", + "scripts": { + "build": "tsc", + "watch": "tsc -w" + }, + "dependencies": { + "@aws-amplify/cli-extensibility-helper": "2.3.0" + }, + "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 new file mode 100644 index 0000000000..9a070be831 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.json @@ -0,0 +1,10 @@ +{ + "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 new file mode 100644 index 0000000000..6504da8028 --- /dev/null +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/tsconfig.resource.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "es6", + "module": "commonjs", + "strict": false, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./", + "rootDir": "../" + }, + "include": ["../**/*"] +} diff --git a/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json new file mode 100644 index 0000000000..30f1827ea5 --- /dev/null +++ b/packages/amplify-category-api/resources/schemas/aPIGateway/APIGatewayCLIInputs.schema.json @@ -0,0 +1,65 @@ +{ + "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#" +} diff --git a/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json b/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json new file mode 100644 index 0000000000..cb286b6dd0 --- /dev/null +++ b/packages/amplify-category-api/resources/schemas/appsync/AppSyncCLIInputs.schema.json @@ -0,0 +1,289 @@ +{ + "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" + }, + "gqlSchemaPath": { + "description": "Path to GraphQL schema that defines the AppSync API.", + "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", "gqlSchemaPath", "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#" +} diff --git a/packages/amplify-category-api/scripts/generateApiSchemas.ts b/packages/amplify-category-api/scripts/generateApiSchemas.ts new file mode 100644 index 0000000000..8a79b9d65d --- /dev/null +++ b/packages/amplify-category-api/scripts/generateApiSchemas.ts @@ -0,0 +1,17 @@ +import { AmplifySupportedService, CLIInputSchemaGenerator, TypeDef } from '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__/commands/api/add-graphql-datasource.test.js b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts similarity index 87% rename from packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js rename to packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts index 701aadaa8c..b0acae414d 100644 --- a/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.js +++ b/packages/amplify-category-api/src/__tests__/commands/api/add-graphql-datasource.test.ts @@ -1,5 +1,5 @@ -const { readSchema } = require('../../../commands/api/add-graphql-datasource'); -const path = require('path'); +import { readSchema } from '../../../commands/api/add-graphql-datasource'; +import * as path from 'path'; describe('read schema', () => { it('Valid schema present in folder', async () => { 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 new file mode 100644 index 0000000000..97269c82e9 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.test.ts @@ -0,0 +1,48 @@ +import { AppsyncApiInputState } from '../../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; + +jest.mock('fs-extra'); + +jest.mock('amplify-cli-core', () => ({ + ...(jest.requireActual('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', + gqlSchemaPath: 'mock/schema.graphql', + defaultAuthType: { + mode: 'AWS_IAM', + }, + conflictResolution: {}, + additionalAuthTypes: [ + { + mode: 'API_KEY', + expirationTime: 7, + keyDescription: '', + }, + ], + }, + }) + .mockReturnValueOnce({}), + }, +})); + +test('Api Input State -> validate cli payload manual payload', async () => { + const resourceName = 'mockResource'; + const apiState = new AppsyncApiInputState(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(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 new file mode 100644 index 0000000000..58057f9179 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/apigw-input-state.test.ts @@ -0,0 +1,240 @@ +import { $TSContext, getMigrateResourceMessageForOverride, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { prompter } from 'amplify-prompts'; +import { ApigwInputState } from '../../../provider-utils/awscloudformation/apigw-input-state'; + +jest.mock('amplify-cli-core'); +jest.mock('fs-extra'); +jest.mock('path'); +jest.mock('../../../provider-utils/awscloudformation/cdk-stack-builder'); + +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(), + }, + filesystem: { + remove: 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(context_mock.filesystem.remove).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(context_mock.filesystem.remove).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(context_mock.filesystem.remove).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(context_mock.filesystem.remove).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/cfn-api-artifact-handler.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cfn-api-artifact-handler.test.ts index e8dfa51770..e2f66dce43 100644 --- 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 @@ -1,19 +1,26 @@ -import path from 'path'; -import fs from 'fs-extra'; -import { ApiArtifactHandler } from '../../../provider-utils/api-artifact-handler'; -import { getCfnApiArtifactHandler } from '../../../provider-utils/awscloudformation/cfn-api-artifact-handler'; +import { AppsyncApiInputState } from '../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; +import { $TSContext, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; -import { category } from '../../../category-constants'; +import { printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; import { writeTransformerConfiguration } from 'graphql-transformer-core'; +import _ from 'lodash'; +import * as path from 'path'; +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 { - getAppSyncResourceName, - getAppSyncAuthConfig, authConfigHasApiKey, + getAppSyncAuthConfig, + getAppSyncResourceName, } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import _ from 'lodash'; jest.mock('fs-extra'); +const printer_mock = printer as jest.Mocked; +printer_mock.warn = jest.fn(); + +jest.mock('../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'); jest.mock('graphql-transformer-core', () => ({ readTransformerConfiguration: jest.fn(async () => ({})), @@ -28,7 +35,33 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', getImportedAuthUserPoolId: jest.fn(() => undefined), })); -jest.mock('amplify-cli-core'); +jest.mock('amplify-cli-core', () => ({ + pathManager: { + getBackendDirPath: jest.fn().mockReturnValue('mockbackendDirPath'), + findProjectRoot: jest.fn().mockReturnValue('mockProject'), + }, + stateManager: { + getMeta: jest.fn().mockReturnValue({}), + }, + AmplifyCategories: { + API: 'api', + }, + AmplifySupportedService: { + APPSYNC: 'Appsync', + }, + JSONUtilities: { + readJson: jest.fn(), + writeJson: jest.fn(), + }, + isResourceNameUnique: jest.fn(), +})); + +const backendDirPathStub = 'backendDirPath'; +const testApiName = 'testApiName'; + +const pathManager_mock = pathManager as jest.Mocked; +pathManager_mock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); +const stateManager_mock = stateManager as jest.Mocked; const fs_mock = fs as unknown as jest.Mocked; const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; @@ -36,26 +69,13 @@ const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunctio const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; -const backendDirPathStub = 'backendDirPath'; - -const testApiName = 'testApiName'; - const context_stub = { - print: { - success: jest.fn(), - warning: jest.fn(), - }, amplify: { updateamplifyMetaAfterResourceAdd: jest.fn(), updateamplifyMetaAfterResourceUpdate: jest.fn(), updateBackendConfigAfterResourceUpdate: jest.fn(), executeProviderUtils: jest.fn(), copyBatch: jest.fn(), - getProjectMeta: jest.fn(), - readJsonFile: jest.fn(), - pathManager: { - getBackendDirPath: jest.fn(() => backendDirPathStub), - }, }, }; @@ -80,7 +100,7 @@ describe('create artifacts', () => { }); beforeEach(() => { jest.clearAllMocks(); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); }); it('does not create a second API if one already exists', async () => { @@ -114,6 +134,20 @@ describe('create artifacts', () => { ]); }); + 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' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + serviceName: 'AppSync', + }, + version: 1, + }); + }); + it('writes the selected template schema to project', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); @@ -180,7 +214,7 @@ describe('update artifacts', () => { beforeEach(() => { jest.clearAllMocks(); updateRequestStub = _.cloneDeep(updateRequestStubBase); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub); + cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); }); it('throws error if no GQL API in project', () => { @@ -193,30 +227,73 @@ describe('update artifacts', () => { 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' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + serviceName: 'AppSync', + }, + version: 1, + }); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); expect(fs_mock.writeFileSync.mock.calls[0][1]).toBe(newSchemaContents); }); - it('updates resolver config if not empty', async () => { - updateRequestStub.serviceModification.conflictResolution = { - defaultResolutionStrategy: { - type: 'OPTIMISTIC_CONCURRENCY', - }, - }; - await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(writeTransformerConfiguration_mock.mock.calls.length).toBe(1); - }); - 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' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + serviceName: 'AppSync', + }, + version: 1, + }); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); expect(context_stub.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, 'getCLIInputPayload').mockReturnValue({ + serviceConfiguration: { + apiName: 'testApiName', + defaultAuthType: { expirationTime: 10, keyDescription: 'api key description', mode: 'API_KEY' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + 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' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + 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' }, + gqlSchemaPath: 'backendDirPath/api/testApiName/schema.graphql', + serviceName: 'AppSync', + }, + version: 1, + }); + await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); expect(context_stub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); @@ -236,12 +313,12 @@ describe('update artifacts', () => { it('prints warning when adding API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.print.warning.mock.calls.length).toBe(2); + expect(printer_mock.warn.mock.calls.length).toBe(2); }); it('prints warning when removing API key auth', async () => { authConfigHasApiKey_mock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.print.warning.mock.calls.length).toBe(3); + expect(printer_mock.warn.mock.calls.length).toBe(3); }); }); 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 index 4dc7ed152f..efb5f999e0 100644 --- 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 @@ -1,22 +1,30 @@ import { legacyAddResource } from '../../../provider-utils/awscloudformation/legacy-add-resource'; import { category } from '../../../category-constants'; +import { $TSAny, $TSContext } from 'amplify-cli-core'; jest.mock('fs-extra'); -jest.mock('amplify-cli-core'); +jest.mock('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: { - pathManager: { - getBackendDirPath: jest.fn(_ => 'mock/backend/path'), - }, updateamplifyMetaAfterResourceAdd: jest.fn(), copyBatch: jest.fn(), }, }; it('sets policy resource name in paths object before copying template', async () => { - const stubWalkthroughPromise: Promise = Promise.resolve({ + const stubWalkthroughPromise: Promise<$TSAny> = Promise.resolve({ answers: { resourceName: 'mockResourceName', paths: [ @@ -29,7 +37,7 @@ describe('legacy add resource', () => { ], }, }); - await legacyAddResource(stubWalkthroughPromise, contextStub, category, 'API Gateway', {}); + 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 index 135f62250f..2945ad4def 100644 --- 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 @@ -1,14 +1,22 @@ +import { $TSContext } from 'amplify-cli-core'; import { legacyUpdateResource } from '../../../provider-utils/awscloudformation/legacy-update-resource'; import { category } from '../../../category-constants'; jest.mock('fs-extra'); +jest.mock('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: { - pathManager: { - getBackendDirPath: jest.fn(_ => 'mock/backend/path'), - }, updateamplifyMetaAfterResourceUpdate: jest.fn(), copyBatch: jest.fn(), }, @@ -28,7 +36,7 @@ describe('legacy update resource', () => { ], }, }); - await legacyUpdateResource(stubWalkthroughPromise, contextStub, category, 'API Gateway'); + 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/service-walkthroughs/appSync-walkthrough.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.test.ts index 6e6a75c8d8..9b2db83f7b 100644 --- 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 @@ -1,42 +1,51 @@ +import { $TSAny, $TSContext, FeatureFlags, pathManager, stateManager } from 'amplify-cli-core'; import { - getIAMPolicies, askAdditionalAuthQuestions, + getIAMPolicies, } from '../../../../provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough'; import { authConfigHasApiKey, getAppSyncAuthConfig } from '../../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; -import { FeatureFlags } from 'amplify-cli-core'; + jest.mock('../../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ getAppSyncAuthConfig: jest.fn(), authConfigHasApiKey: jest.fn(), })); jest.mock('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(), - }, -}); +const context_stub = (prompt: jest.Mock) => + ({ + prompt: { + confirm: prompt, + }, + amplify: { + getProjectMeta: jest.fn(), + }, + } as unknown as $TSContext); type IAMArtifact = { attributes: string[]; - policy: any; + policy: $TSAny; }; 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -49,7 +58,7 @@ describe('get IAM policies', () => { it('includes API key if it exists', async () => { mockGetBoolean.mockImplementationOnce(() => true); authConfigHasApiKey_mock.mockImplementationOnce(() => true); - const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -63,7 +72,7 @@ describe('get IAM policies', () => { 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['Query', 'Mutate']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", @@ -73,10 +82,11 @@ describe('get IAM policies', () => { 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'], context_stub(confirmPromptFalse_mock)); + const iamArtifact: IAMArtifact = getIAMPolicies('testResourceName', ['create', 'update']); expect(iamArtifact.attributes).toMatchInlineSnapshot(` Array [ "GraphQLAPIIdOutput", 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 new file mode 100644 index 0000000000..438e5b8a64 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/get-appsync-auth-config.test.ts.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`test 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[`test 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/get-appsync-auth-config.test.ts b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts new file mode 100644 index 0000000000..3441f4df77 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/get-appsync-auth-config.test.ts @@ -0,0 +1,55 @@ +import { getAuthConfig } from '../../../../provider-utils/awscloudformation/utils/get-appsync-auth-config'; + +const getCLIInputPayload_mock = jest + .fn() + .mockReturnValueOnce({ + version: 1, + serviceConfiguration: { + apiName: 'authv2migration1', + serviceName: 'AppSync', + gqlSchemaPath: 'mock/schema.graphql', + defaultAuthType: { + mode: 'AWS_IAM', + }, + conflictResolution: {}, + additionalAuthTypes: [], + }, + }) + .mockReturnValueOnce({ + version: 1, + serviceConfiguration: { + apiName: 'authv2migration1', + serviceName: 'AppSync', + gqlSchemaPath: 'mock/schema.graphql', + 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), + }; + }), + }; +}); + +test('test function with default auth config', async () => { + expect(await getAuthConfig('mockapiResource')).toMatchSnapshot(); +}); + +test('test function with default and additional auth config', async () => { + expect(await getAuthConfig('mockapiResource')).toMatchSnapshot(); +}); 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 new file mode 100644 index 0000000000..b91d4049f3 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/utils/migrate-api-override-resource.test.ts @@ -0,0 +1,79 @@ +import { JSONUtilities } from 'amplify-cli-core'; +import { migrateResourceToSupportOverride } from '../../../../provider-utils/awscloudformation/utils/migrate-api-override-resource'; +import * as path from 'path'; + +jest.mock('amplify-prompts'); +jest.mock('fs-extra'); + +jest.mock('amplify-cli-core', () => ({ + ...(jest.requireActual('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', + gqlSchemaPath: 'mockProjectPath/schema.graphql', + }, + }; + expect(JSONUtilities.writeJson).toBeCalledWith(expectedPath, expectedPayload); +}); 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 index 7c82402f42..6facce6d56 100644 --- 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 @@ -4,7 +4,7 @@ import { formatCFNPathParamsForExpressJs, } from '../../../../provider-utils/awscloudformation/utils/rest-api-path-utils'; -const stubOtherPaths = [{ name: '/other/path' }, { name: '/sub/path' }, { name: '/path/{with}/{params}' }]; +const stubOtherPaths = ['/other/path', '/sub/path', '/path/{with}/{params}']; test('validatePathName_validPath', () => { expect(validatePathName('/some/path')).toBe(true); @@ -56,9 +56,9 @@ test('checkForPathOverlap_subPathParamsNoMatch', () => { }); test('checkForPathOverlap_pathMatch', () => { - expect(checkForPathOverlap(stubOtherPaths[0].name, stubOtherPaths)).toEqual({ - higherOrderPath: stubOtherPaths[0].name, - lowerOrderPath: stubOtherPaths[0].name, + expect(checkForPathOverlap(stubOtherPaths[0], stubOtherPaths)).toEqual({ + higherOrderPath: stubOtherPaths[0], + lowerOrderPath: stubOtherPaths[0], }); }); diff --git a/packages/amplify-category-api/src/category-constants.ts b/packages/amplify-category-api/src/category-constants.ts index 5851dbb6a0..1b460621d7 100644 --- a/packages/amplify-category-api/src/category-constants.ts +++ b/packages/amplify-category-api/src/category-constants.ts @@ -1,2 +1,5 @@ -export const category = 'api'; +import { AmplifyCategories } from 'amplify-cli-core'; + +export const ADMIN_QUERIES_NAME = 'AdminQueries'; export const NETWORK_STACK_LOGICAL_ID = 'NetworkStack'; +export const category = AmplifyCategories.API; diff --git a/packages/amplify-category-api/src/commands/api.js b/packages/amplify-category-api/src/commands/api.js deleted file mode 100644 index 2ea6c65e5a..0000000000 --- a/packages/amplify-category-api/src/commands/api.js +++ /dev/null @@ -1,59 +0,0 @@ -const featureName = 'api'; - -module.exports = { - name: featureName, - run: async context => { - if (/^win/.test(process.platform)) { - try { - const { run } = require(`./${featureName}/${context.parameters.first}`); - return run(context); - } catch (e) { - context.print.error('Command not found'); - } - } - const header = `amplify ${featureName} `; - const commands = [ - { - name: 'add', - description: `Takes you through a CLI flow to add a ${featureName} resource to your local backend`, - }, - { - name: 'push', - description: `Provisions ${featureName} cloud resources and its dependencies with the latest local developments`, - }, - { - name: 'remove', - description: `Removes ${featureName} 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 ${featureName} 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', - }, - ]; - - context.amplify.showHelp(header, commands); - - context.print.info(''); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api.ts b/packages/amplify-category-api/src/commands/api.ts new file mode 100644 index 0000000000..5eab38a325 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api.ts @@ -0,0 +1,64 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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', + }, + ]; + + 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 index d4bd9be8d8..f2c14ca785 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -1,171 +1,165 @@ +import { mergeTypeDefs } from '@graphql-tools/merge'; +import { $TSAny, $TSContext, exitOnNextTick, FeatureFlags, pathManager, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; -import * as path from 'path'; import * as graphql from 'graphql'; -import _ from 'lodash'; -import inquirer from 'inquirer'; import { + AuroraServerlessMySQLDatabaseReader, RelationalDBSchemaTransformer, RelationalDBTemplateGenerator, - AuroraServerlessMySQLDatabaseReader, } from 'graphql-relational-schema-transformer'; -import { mergeTypeDefs } from '@graphql-tools/merge'; -import { FeatureFlags, ResourceDoesNotExistError, exitOnNextTick, $TSAny, $TSContext, stateManager, pathManager } from 'amplify-cli-core'; +import inquirer from 'inquirer'; +import _ from 'lodash'; +import * as path from 'path'; const subcommand = 'add-graphql-datasource'; const categories = 'categories'; const category = 'api'; const providerName = 'awscloudformation'; -module.exports = { - name: subcommand, - run: async (context: $TSContext) => { - try { - const servicesMetadata = (await import('../../provider-utils/supported-datasources')).supportedDatasources; +export const name = subcommand; + +export const run = async (context: $TSContext) => { + try { + const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; + const AWS = await getAwsClient(context, 'list'); - const AWS = await getAwsClient(context, 'list'); + const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); - const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); + const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); - const providerController = await import(`../../provider-utils/${result.providerName}/index`); + if (!providerController) { + printer.error('Provider not configured for this category'); + return; + } - if (!providerController) { - context.print.error('Provider not configured for this category'); - return; - } + const { datasource } = result; + const answers = await providerController.addDatasource(context, category, datasource); - const { datasource } = result; - const answers = await providerController.addDatasource(context, category, datasource); - - const { resourceName, databaseName } = answers; - - /** - * Write the new env specific datasource information into - * the team-provider-info file - */ - const currEnv = context.amplify.getEnvInfo().envName; - const teamProviderInfo = stateManager.getTeamProviderInfo(); - - _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { - rdsRegion: answers.region, - rdsClusterIdentifier: answers.dbClusterArn, - rdsSecretStoreArn: answers.secretStoreArn, - rdsDatabaseName: answers.databaseName, - }); - - stateManager.setTeamProviderInfo(undefined, teamProviderInfo); - - 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 instrospection to get the GraphQL Schema and Template Context - */ - const improvePluralizationFlag = FeatureFlags.getBoolean('graphqltransformer.improvePluralization'); - const relationalSchemaTransformer = new RelationalDBSchemaTransformer(dbReader, answers.databaseName, improvePluralizationFlag); - const graphqlSchemaContext = await relationalSchemaTransformer.introspectDatabaseSchema(); - - if (graphqlSchemaContext === null) { - context.print.warning('No importable tables were found in the selected Database.'); - context.print.info(''); - return; - } + const { resourceName, databaseName } = answers; - /** - * Merge the GraphQL Schema with the existing schema.graphql in the projects stack - * - */ - const apiDirPath = path.join(pathManager.getBackendDirPath(), category, resourceName); + /** + * Write the new env specific datasource information into + * the team-provider-info file + */ + const currEnv = context.amplify.getEnvInfo().envName; + const teamProviderInfo = stateManager.getTeamProviderInfo(); - fs.ensureDirSync(apiDirPath); + _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { + rdsRegion: answers.region, + rdsClusterIdentifier: answers.dbClusterArn, + rdsSecretStoreArn: answers.secretStoreArn, + rdsDatabaseName: answers.databaseName, + }); - const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); - const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; - const schemaDirectoryPath = path.join(apiDirPath, 'schema'); + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); + + 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 instrospection to get the GraphQL Schema and Template Context + */ + 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; + } - if (fs.existsSync(graphqlSchemaFilePath)) { - const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + /** + * Merge the GraphQL Schema with the existing schema.graphql in the projects stack + * + */ + const apiDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); - if (currGraphQLSchemaDoc) { - typesToBeMerged.unshift(currGraphQLSchemaDoc); - } else { - context.print.warning(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); - context.print.info(''); - } + fs.ensureDirSync(apiDirPath); - const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); + const graphqlSchemaFilePath = path.join(apiDirPath, 'schema.graphql'); + const rdsGraphQLSchemaDoc = graphqlSchemaContext.schemaDoc; + const schemaDirectoryPath = path.join(apiDirPath, 'schema'); - fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); - } else if (fs.existsSync(schemaDirectoryPath)) { - const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); + if (fs.existsSync(graphqlSchemaFilePath)) { + const typesToBeMerged = [rdsGraphQLSchemaDoc]; + const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); + if (currGraphQLSchemaDoc) { + typesToBeMerged.unshift(currGraphQLSchemaDoc); } else { - throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); + printer.warn(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); + printer.blankLine(); } - const resolversDir = path.join(apiDirPath, 'resolvers'); + const concatGraphQLSchemaDoc = mergeTypeDefs(typesToBeMerged); - /** - * Instantiate a new Relational Template Generator and create - * the template and relational resolvers - */ + fs.writeFileSync(graphqlSchemaFilePath, graphql.print(concatGraphQLSchemaDoc), 'utf8'); + } else if (fs.existsSync(schemaDirectoryPath)) { + const rdsSchemaFilePath = path.join(schemaDirectoryPath, 'rds.graphql'); - const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); + fs.writeFileSync(rdsSchemaFilePath, graphql.print(rdsGraphQLSchemaDoc), 'utf8'); + } else { + throw new Error(`Could not find a schema in either ${graphqlSchemaFilePath} or schema directory at ${schemaDirectoryPath}`); + } - let template = templateGenerator.createTemplate(context); + const resolversDir = path.join(apiDirPath, 'resolvers'); - template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); + /** + * Instantiate a new Relational Template Generator and create + * the template and relational resolvers + */ - const cfn = templateGenerator.printCloudformationTemplate(template); + const templateGenerator = new RelationalDBTemplateGenerator(graphqlSchemaContext); - /** - * Add the generated the CFN to the appropriate nested stacks directory - */ + let template = templateGenerator.createTemplate(context); - const stacksDir = path.join(apiDirPath, 'stacks'); - const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); + template = templateGenerator.addRelationalResolvers(template, resolversDir, improvePluralizationFlag); - fs.writeFileSync(writeToPath, cfn, 'utf8'); + const cfn = templateGenerator.printCloudformationTemplate(template); - context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); + /** + * Add the generated the CFN to the appropriate nested stacks directory + */ - context.print.success(`Successfully added the ${datasource} datasource locally`); - context.print.info(''); - context.print.success('Some next steps:'); - context.print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - context.print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - context.print.info(''); - } catch (error) { - context.print.info(error.stack); - context.print.error('There was an error adding the datasource'); + const stacksDir = path.join(apiDirPath, 'stacks'); + const writeToPath = path.join(stacksDir, `${resourceName}-${databaseName}-rds.json`); - await context.usageData.emitError(error); + fs.writeFileSync(writeToPath, cfn, 'utf8'); - process.exitCode = 1; - } - }, - readSchema, + 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; + } }; -async function datasourceSelectionPrompt(context, supportedDatasources) { +async function datasourceSelectionPrompt(context: $TSContext, supportedDatasources) { const options = []; Object.keys(supportedDatasources).forEach(datasource => { const optionName = @@ -184,7 +178,7 @@ async function datasourceSelectionPrompt(context, supportedDatasources) { if (options.length === 0) { const errMessage = `No datasources defined by configured providers for category: ${category}`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -193,7 +187,7 @@ async function datasourceSelectionPrompt(context, supportedDatasources) { if (options.length === 1) { // No need to ask questions - context.print.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); + printer.info(`Using datasource: ${options[0].value.datasource}, provided by: ${options[0].value.providerName}`); return new Promise(resolve => { resolve(options[0].value); @@ -219,7 +213,7 @@ async function getAwsClient(context: $TSContext, action: string) { return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); } -function readSchema(graphqlSchemaFilePath) { +export function readSchema(graphqlSchemaFilePath: string) { const graphqlSchemaRaw = fs.readFileSync(graphqlSchemaFilePath).toString(); if (graphqlSchemaRaw.trim().length === 0) { diff --git a/packages/amplify-category-api/src/commands/api/add.js b/packages/amplify-category-api/src/commands/api/add.js deleted file mode 100644 index d883208b45..0000000000 --- a/packages/amplify-category-api/src/commands/api/add.js +++ /dev/null @@ -1,75 +0,0 @@ -const inquirer = require('inquirer'); -const subcommand = 'add'; -const category = 'api'; -const apiGatewayService = 'API Gateway'; - -let options; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(async result => { - options = { - service: result.service, - providerPlugin: result.providerName, - }; - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - context.print.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, category, result.service, options); - }) - .then(resourceName => { - const { print } = context; - print.success(`Successfully added resource ${resourceName} locally`); - print.info(''); - print.success('Some next steps:'); - print.info('"amplify push" will build all your local backend resources and provision it in the cloud'); - print.info( - '"amplify publish" will build all your local backend and frontend resources (if you have hosting category added) and provision it in the cloud', - ); - print.info(''); - }) - .catch(err => { - context.print.info(err.stack); - context.print.error('There was an error adding the API resource'); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; - -async function shouldUpdateExistingRestApi(context, selectedService) { - if (selectedService !== apiGatewayService) { - return false; - } - - const { allResources } = await context.amplify.getResourceStatus(); - const hasRestApis = allResources.some(resource => resource.service === apiGatewayService && resource.mobileHubMigrated !== true); - - if (!hasRestApis) { - return false; - } - - const question = [ - { - name: 'update', - message: 'Would you like to add a new path to an existing REST API:', - type: 'confirm', - default: true, - }, - ]; - const answer = await inquirer.prompt(question); - - return answer.update; -} diff --git a/packages/amplify-category-api/src/commands/api/add.ts b/packages/amplify-category-api/src/commands/api/add.ts new file mode 100644 index 0000000000..53eaa40181 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/add.ts @@ -0,0 +1,62 @@ +import { $TSContext, $TSObject, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as path from 'path'; + +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: $TSObject) => 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.js b/packages/amplify-category-api/src/commands/api/console.js deleted file mode 100644 index a8bc4d57bc..0000000000 --- a/packages/amplify-category-api/src/commands/api/console.js +++ /dev/null @@ -1,25 +0,0 @@ -const subcommand = 'console'; -const category = 'api'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(async result => { - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - throw new Error(`Provider "${result.providerName}" is not configured for this category`); - } - return await providerController.console(context, result.service); - }) - .catch(err => { - context.print.error('Error opening console.'); - context.print.info(err.message); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/console.ts b/packages/amplify-category-api/src/commands/api/console.ts new file mode 100644 index 0000000000..3840cc4366 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/console.ts @@ -0,0 +1,22 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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/gql-compile.js b/packages/amplify-category-api/src/commands/api/gql-compile.js deleted file mode 100644 index a53e64d0fe..0000000000 --- a/packages/amplify-category-api/src/commands/api/gql-compile.js +++ /dev/null @@ -1,20 +0,0 @@ -const subcommand = 'gql-compile'; - -module.exports = { - name: subcommand, - run: async context => { - try { - const { - parameters: { options }, - } = context; - await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { - forceCompile: true, - minify: options['minify'], - }); - } catch (err) { - context.print.error(err.toString()); - context.usageData.emitError(err); - process.exitCode = 1; - } - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/gql-compile.ts b/packages/amplify-category-api/src/commands/api/gql-compile.ts new file mode 100644 index 0000000000..32ef55c489 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/gql-compile.ts @@ -0,0 +1,15 @@ +import { $TSContext } from 'amplify-cli-core'; + +const subcommand = 'gql-compile'; + +export const name = subcommand; + +export const run = async (context: $TSContext) => { + const { + parameters: { options }, + } = context; + return context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { + forceCompile: true, + minify: options['minify'], + }); +}; diff --git a/packages/amplify-category-api/src/commands/api/migrate.ts b/packages/amplify-category-api/src/commands/api/migrate.ts index f5ea2857a1..3389023cad 100644 --- a/packages/amplify-category-api/src/commands/api/migrate.ts +++ b/packages/amplify-category-api/src/commands/api/migrate.ts @@ -1,8 +1,8 @@ -import { $TSAny, $TSContext, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, AmplifyCategories, pathManager, stateManager } from 'amplify-cli-core'; import { printer } from 'amplify-prompts'; import { attemptV2TransformerMigration, revertV2Migration } from '@aws-amplify/graphql-transformer-migrator'; import * as path from 'path'; -import { category } from '../../category-constants'; +import { checkAppsyncApiResourceMigration } from '../../provider-utils/awscloudformation/utils/check-appsync-api-migration'; const subcommand = 'migrate'; @@ -26,7 +26,11 @@ export const run = async (context: $TSContext) => { return; } const apiName = apiNames[0]; - const apiResourceDir = path.join(pathManager.getBackendDirPath(), category, apiName); + 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()); diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts new file mode 100644 index 0000000000..3dbbe3830f --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/override.ts @@ -0,0 +1,99 @@ +import { + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + generateOverrideSkeleton, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as path from 'path'; +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 context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, '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: $TSObject[] } = 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: $TSObject[]) => + 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); + stackGenerator.transform(); + } + } + await generateOverrideSkeleton(context, srcPath, destPath); + } +}; diff --git a/packages/amplify-category-api/src/commands/api/push.js b/packages/amplify-category-api/src/commands/api/push.js deleted file mode 100644 index 8a0da0bb5a..0000000000 --- a/packages/amplify-category-api/src/commands/api/push.js +++ /dev/null @@ -1,17 +0,0 @@ -const subcommand = 'push'; -const category = 'api'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify, parameters } = context; - const resourceName = parameters.first; - context.amplify.constructExeInfo(context); - return amplify.pushResources(context, category, resourceName).catch(err => { - context.print.error('There was an error pushing the API resource'); - context.print.error(err.toString()); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/push.ts b/packages/amplify-category-api/src/commands/api/push.ts new file mode 100644 index 0000000000..0defd33099 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/push.ts @@ -0,0 +1,11 @@ +import { $TSContext, AmplifyCategories } from '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 index 26b8ead364..55c269da95 100644 --- a/packages/amplify-category-api/src/commands/api/rebuild.ts +++ b/packages/amplify-category-api/src/commands/api/rebuild.ts @@ -1,8 +1,7 @@ -import { $TSAny, $TSContext, FeatureFlags, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, AmplifyCategories, FeatureFlags, stateManager } from 'amplify-cli-core'; import { printer, prompter, exact } from 'amplify-prompts'; const subcommand = 'rebuild'; -const category = 'api'; export const name = subcommand; @@ -36,5 +35,5 @@ export const run = async (context: $TSContext) => { const { amplify, parameters } = context; const resourceName = parameters.first; amplify.constructExeInfo(context); - return amplify.pushResources(context, category, resourceName, undefined, rebuild); + return amplify.pushResources(context, AmplifyCategories.API, resourceName, undefined, rebuild); }; diff --git a/packages/amplify-category-api/src/commands/api/remove.js b/packages/amplify-category-api/src/commands/api/remove.js deleted file mode 100644 index 8c334611a5..0000000000 --- a/packages/amplify-category-api/src/commands/api/remove.js +++ /dev/null @@ -1,31 +0,0 @@ -const path = require('path'); - -const subcommand = 'remove'; -const category = 'api'; -const gqlConfigFilename = '.graphqlconfig.yml'; - -module.exports = { - name: subcommand, - run: async context => { - const { amplify, parameters } = context; - const resourceName = parameters.first; - - return amplify - .removeResource(context, category, resourceName) - .then(resourceValues => { - if (!resourceValues) return; // indicates that the customer selected "no" at the confirmation prompt - if (resourceValues.service === 'AppSync') { - const { projectPath } = amplify.getEnvInfo(); - - const gqlConfigFile = path.normalize(path.join(projectPath, gqlConfigFilename)); - context.filesystem.remove(gqlConfigFile); - } - }) - .catch(err => { - context.print.info(err.stack); - context.print.error('There was an error removing the api resource'); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/remove.ts b/packages/amplify-category-api/src/commands/api/remove.ts new file mode 100644 index 0000000000..e6a78c9323 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/remove.ts @@ -0,0 +1,30 @@ +import { $TSContext, AmplifyCategories, AmplifySupportedService } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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.js b/packages/amplify-category-api/src/commands/api/update.js deleted file mode 100644 index 03dbb328f1..0000000000 --- a/packages/amplify-category-api/src/commands/api/update.js +++ /dev/null @@ -1,29 +0,0 @@ -const subcommand = 'update'; -const category = 'api'; - -module.exports = { - name: subcommand, - alias: ['configure'], - run: async context => { - const { amplify } = context; - const servicesMetadata = require('../../provider-utils/supported-services').supportedServices; - - return amplify - .serviceSelectionPrompt(context, category, servicesMetadata) - .then(result => { - const providerController = require(`../../provider-utils/${result.providerName}/index`); - if (!providerController) { - context.print.error('Provider not configured for this category'); - return; - } - return providerController.updateResource(context, category, result.service); - }) - .then(() => context.print.success('Successfully updated resource')) - .catch(err => { - context.print.error(err.message); - console.log(err.stack); - context.usageData.emitError(err); - process.exitCode = 1; - }); - }, -}; diff --git a/packages/amplify-category-api/src/commands/api/update.ts b/packages/amplify-category-api/src/commands/api/update.ts new file mode 100644 index 0000000000..ce3490f7f7 --- /dev/null +++ b/packages/amplify-category-api/src/commands/api/update.ts @@ -0,0 +1,24 @@ +import { $TSContext, AmplifyCategories } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as path from 'path'; + +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/index.ts b/packages/amplify-category-api/src/index.ts index 96ce70e2d7..156259d1e3 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -1,41 +1,61 @@ +import { + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + buildOverrideDir, + exitOnNextTick, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-headless-input'; -import fs from 'fs-extra'; -import path from 'path'; +import * as fs from 'fs-extra'; +import * as path from 'path'; import { run } from './commands/api/console'; +import { getAppSyncAuthConfig, getAppSyncResourceName } 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 { getAppSyncResourceName, getAppSyncAuthConfig } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; 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'; 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'; -export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; +export { getContainers } from './provider-utils/awscloudformation/docker-compose'; export { EcsAlbStack } from './provider-utils/awscloudformation/ecs-alb-stack'; -export { getGitHubOwnerRepoFromPath } from './provider-utils/awscloudformation/utils/github'; +export { EcsStack } from './provider-utils/awscloudformation/ecs-apigw-stack'; +export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; export { - generateContainersArtifacts, ApiResource, + generateContainersArtifacts, processDockerConfig, } from './provider-utils/awscloudformation/utils/containers-artifacts'; -export { getContainers } from './provider-utils/awscloudformation/docker-compose'; -export { promptToAddApiKey } from './provider-utils/awscloudformation/prompt-to-add-api-key'; - -const category = 'api'; +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'; +const category = AmplifyCategories.API; const categories = 'categories'; -export async function console(context) { +export async function console(context: $TSContext) { await run(context); } -export async function migrate(context, serviceName) { - const { projectPath, amplifyMeta } = context.migrationInfo; +export async function migrate(context: $TSContext, serviceName?: string) { + const { projectPath } = context.migrationInfo; + const amplifyMeta = stateManager.getMeta(); const migrateResourcePromises = []; - Object.keys(amplifyMeta).forEach(categoryName => { + for (const categoryName of Object.keys(amplifyMeta)) { if (categoryName === category) { - Object.keys(amplifyMeta[category]).forEach(resourceName => { + for (const resourceName of Object.keys(amplifyMeta[category])) { try { if (amplifyMeta[category][resourceName].providerPlugin) { - const providerController = require(`./provider-utils/${amplifyMeta[category][resourceName].providerPlugin}/index`); + const providerController = await import( + path.join('.', 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') + ); if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { migrateResourcePromises.push( @@ -44,20 +64,20 @@ export async function migrate(context, serviceName) { } } } else { - context.print.error(`Provider not configured for ${category}: ${resourceName}`); + printer.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - context.print.warning(`Could not run migration for ${category}: ${resourceName}`); + printer.warn(`Could not run migration for ${category}: ${resourceName}`); throw e; } - }); + } } - }); + } await Promise.all(migrateResourcePromises); } -export async function initEnv(context) { +export async function initEnv(context: $TSContext) { const datasource = 'Aurora Serverless'; const service = 'service'; const rdsInit = 'rdsInit'; @@ -72,7 +92,7 @@ export async function initEnv(context) { * Check if we need to do the walkthrough, by looking to see if previous environments have * configured an RDS datasource */ - const backendConfigFilePath = amplify.pathManager.getBackendConfigFilePath(); + const backendConfigFilePath = pathManager.getBackendConfigFilePath(); // If this is a mobile hub migrated project without locally added resources then there is no // backend config exists yet. @@ -80,7 +100,7 @@ export async function initEnv(context) { return; } - const backendConfig = amplify.readJsonFile(backendConfigFilePath); + const backendConfig = stateManager.getBackendConfig(); if (!backendConfig[category]) { return; @@ -88,9 +108,9 @@ export async function initEnv(context) { let resourceName; const apis = Object.keys(backendConfig[category]); - for (let i = 0; i < apis.length; i += 1) { - if (backendConfig[category][apis[i]][service] === 'AppSync') { - resourceName = apis[i]; + for (const api of apis) { + if (backendConfig[category][api][service] === AmplifySupportedService.APPSYNC) { + resourceName = api; break; } } @@ -105,10 +125,10 @@ export async function initEnv(context) { return; } - const providerController = require('./provider-utils/awscloudformation/index'); + const providerController = await import(path.join('.', 'provider-utils', provider, 'index')); if (!providerController) { - context.print.error('Provider not configured for this category'); + printer.error('Provider not configured for this category'); return; } @@ -116,8 +136,7 @@ export async function initEnv(context) { * Check team provider info to ensure it hasn't already been created for current env */ const currEnv = amplify.getEnvInfo().envName; - const teamProviderInfoFilePath = amplify.pathManager.getProviderInfoFilePath(); - const teamProviderInfo = amplify.readJsonFile(teamProviderInfoFilePath); + const teamProviderInfo = stateManager.getTeamProviderInfo(); if ( teamProviderInfo[currEnv][categories] && teamProviderInfo[currEnv][categories][category] && @@ -152,16 +171,15 @@ export async function initEnv(context) { teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; - fs.writeFileSync(teamProviderInfoFilePath, JSON.stringify(teamProviderInfo, null, 4)); + stateManager.setTeamProviderInfo(undefined, teamProviderInfo); }) .then(() => { context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); }); } -export async function getPermissionPolicies(context, resourceOpsMapping) { - const amplifyMetaFilePath = context.amplify.pathManager.getAmplifyMetaFilePath(); - const amplifyMeta = context.amplify.readJsonFile(amplifyMetaFilePath); +export async function getPermissionPolicies(context: $TSContext, resourceOpsMapping: $TSObject) { + const amplifyMeta = stateManager.getMeta(); const permissionPolicies = []; const resourceAttributes = []; @@ -170,7 +188,7 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { try { const providerName = amplifyMeta[category][resourceName].providerPlugin; if (providerName) { - const providerController = require(`./provider-utils/${providerName}/index`); + const providerController = await import(path.join(__dirname, 'provider-utils', providerName, 'index')); const { policy, attributes } = await providerController.getPermissionPolicies( context, amplifyMeta[category][resourceName].service, @@ -180,10 +198,10 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { permissionPolicies.push(policy); resourceAttributes.push({ resourceName, attributes, category }); } else { - context.print.error(`Provider not configured for ${category}: ${resourceName}`); + printer.error(`Provider not configured for ${category}: ${resourceName}`); } } catch (e) { - context.print.warning(`Could not get policies for ${category}: ${resourceName}`); + printer.warn(`Could not get policies for ${category}: ${resourceName}`); throw e; } }), @@ -191,7 +209,7 @@ export async function getPermissionPolicies(context, resourceOpsMapping) { return { permissionPolicies, resourceAttributes }; } -export async function executeAmplifyCommand(context) { +export async function executeAmplifyCommand(context: $TSContext) { let commandPath = path.normalize(path.join(__dirname, 'commands')); if (context.input.command === 'help') { commandPath = path.join(commandPath, category); @@ -199,36 +217,53 @@ export async function executeAmplifyCommand(context) { commandPath = path.join(commandPath, category, context.input.command); } - const commandModule = require(commandPath); - await commandModule.run(context); + const commandModule = await import(commandPath); + try { + await commandModule.run(context); + } catch (error) { + if (error) { + printer.error(error.message || error); + if (error.stack) { + printer.info(error.stack); + } + await context.usageData.emitError(error); + } + process.exitCode = 1; + } } -export const executeAmplifyHeadlessCommand = async (context, headlessPayload: string) => { +export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => { switch (context.input.command) { case 'add': await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); break; case 'update': + const resourceName = await getAppSyncApiResourceName(context); + if (!(await checkAppsyncApiResourceMigration(context, resourceName, true))) { + printer.error('Update operations only work on migrated projects. Run "amplify update api" and opt for migration.'); + exitOnNextTick(0); + } await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); break; default: - context.print.error(`Headless mode for ${context.input.command} api is not implemented yet`); + printer.error(`Headless mode for ${context.input.command} api is not implemented yet`); } }; -export async function handleAmplifyEvent(context, args) { - context.print.info(`${category} handleAmplifyEvent to be implemented`); - context.print.info(`Received event args ${args}`); +export async function handleAmplifyEvent(context: $TSContext, args) { + printer.info(`${category} handleAmplifyEvent to be implemented`); + printer.info(`Received event args ${args}`); } -export async function addGraphQLAuthorizationMode(context, args) { +export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TSObject) { const { authType, printLeadText, authSettings } = args; - const apiName = getAppSyncResourceName(context.amplify.getProjectMeta()); + const meta = stateManager.getMeta(); + const apiName = getAppSyncResourceName(meta); if (!apiName) { return; } - const authConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + const authConfig = getAppSyncAuthConfig(meta); const addAuthConfig = await askAuthQuestions(authType, context, printLeadText, authSettings); authConfig.additionalAuthenticationProviders.push(addAuthConfig); await context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); @@ -249,3 +284,43 @@ export async function addGraphQLAuthorizationMode(context, args) { return addAuthConfig; } + +export async function transformCategoryStack(context: $TSContext, resource: $TSObject) { + 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 => { + printer.debug(`Skipping build due to ${error.message}`); + return false; + }); + await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [ + context, + { + forceCompile: true, + overrideConfig: { + overrideFlag: isBuild, + overrideDir: overrideDir, + resourceName: resource.resourceName, + }, + }, + ]); + } + } else if (resource.service === AmplifySupportedService.APIGW) { + if (canResourceBeTransformed(resource.resourceName)) { + const backendDir = pathManager.getBackendDirPath(); + const overrideDir = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, resource.resourceName); + await buildOverrideDir(backendDir, overrideDir).catch(error => { + printer.debug(`Skipping build as ${error.message}`); + return false; + }); + // Rebuild CFN + const apigwStack = new ApigwStackTransform(context, resource.resourceName); + apigwStack.transform(); + } + } +} + +function canResourceBeTransformed(resourceName: string) { + return stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); +} 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 new file mode 100644 index 0000000000..1d0af5e205 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/api-input-manager/appsync-api-input-state.ts @@ -0,0 +1,42 @@ +import { AmplifyCategories, AmplifySupportedService, CLIInputSchemaValidator, JSONUtilities, pathManager } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +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(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('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 new file mode 100644 index 0000000000..3a20074f6b --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/apigw-input-state.ts @@ -0,0 +1,247 @@ +import { + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + CLIInputSchemaValidator, + getMigrateResourceMessageForOverride, + isResourceNameUnique, + JSONUtilities, + PathConstants, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer, prompter } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import { join } from 'path'; +import { ApigwInputs, ApigwStackTransform, CrudOperation, Path, PermissionSetting } from './cdk-stack-builder'; +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, + }; + + await 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(); + + await this.context.amplify.updateamplifyMetaAfterResourceUpdate( + AmplifyCategories.API, + adminQueriesProps.apiName, + 'dependsOn', + adminQueriesProps.dependsOn, + ); + }; + + public addApigwResource = async (serviceWalkthroughPromise: ApigwWalkthroughReturnPromise, options: $TSObject) => { + 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<$TSObject>) => { + 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); + + this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + this.context.filesystem.remove(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); + let deprecatedParameters: $TSObject; + try { + deprecatedParameters = JSONUtilities.readJson<$TSObject>(deprecatedParametersFilePath); + } catch (e) { + printer.error(`Error reading ${deprecatedParametersFileName} file for ${this.resourceName} resource`); + throw e; + } + + this.paths = {}; + + function _convertDeprecatedPermissionStringToCRUD(deprecatedPrivacy: string) { + let privacyList: string[]; + 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]))); + } + + deprecatedParameters.paths.forEach((path: $TSObject) => { + 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); + } + } + } + + this.paths[path.name] = { + permissions: { + setting: pathPermissionSetting, + auth, + guest, + groups, + }, + lambdaFunction: path.lambdaFunction, + }; + }); + + this.context.filesystem.remove(deprecatedParametersFilePath); + this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + this.context.filesystem.remove(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 isCLIInputsValid(cliInputs?: ApigwInputs) { + if (!cliInputs) { + cliInputs = this.getCliInputPayload(); + } + + const schemaValidator = new CLIInputSchemaValidator(AmplifySupportedService.APIGW, AmplifyCategories.API, 'APIGatewayCLIInputs'); + 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: $TSObject[]; +}; 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 index 824a2cafef..418b53b47f 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/aws-constants.ts @@ -1,8 +1,8 @@ -import path from 'path'; +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')); +export const rootAssetDir = path.resolve(path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation')); 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 new file mode 100644 index 0000000000..338f77bac4 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.ts @@ -0,0 +1,471 @@ +import * as apigw from '@aws-cdk/aws-apigateway'; +import * as iam from '@aws-cdk/aws-iam'; +import * as lambda from '@aws-cdk/aws-lambda'; +import * as cdk from '@aws-cdk/core'; +import { $TSObject, JSONUtilities } from 'amplify-cli-core'; +import _ from 'lodash'; +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 { + _scope: cdk.Construct; + restApi!: apigw.CfnRestApi; + deploymentResource: apigw.CfnDeployment; + _lambdaPermission: lambda.CfnPermission; + _props: ApigwInputs; + paths: $TSObject; + policies: { [pathName: string]: ApigwPathPolicy }; + _cfnParameterMap: Map = new Map(); + + constructor(scope: cdk.Construct, id: string, props: ApigwInputs) { + super(scope, id, undefined); + this._scope = scope; + this._props = props; + this.paths = {}; + this.policies = {}; + this.templateOptions.templateFormatVersion = CFN_TEMPLATE_FORMAT_VERSION; + this.templateOptions.description = ROOT_CFN_DESCRIPTION; + } + + /** + * + * @param props + * @param logicalId + */ + addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void { + new cdk.CfnOutput(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void { + new cdk.CfnMapping(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void { + new cdk.CfnCondition(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void { + new cdk.CfnResource(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addLambdaPermissionCfnResource(props: lambda.CfnPermissionProps, logicalId: string): void { + new lambda.CfnPermission(this, logicalId, props); + } + + /** + * + * @param props + * @param logicalId + */ + addCfnParameter(props: cdk.CfnParameterProps, logicalId: string): void { + if (this._cfnParameterMap.has(logicalId)) { + throw new Error(`logical id "${logicalId}" already exists`); + } + this._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); + } + + private _craftPolicyDocument(apiResourceName: string, pathName: string, supportedOperations: string[]) { + const resources = [pathName, `${pathName}/*`].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 => { + return 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', + }, + }, + }, + }); + + this._setDeploymentResource(resourceName); + }; + + 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[`${pathName}/{proxy+}`] = createPathObject(path); + lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; + } + + if (!addedFunctionPermissions.has(path.lambdaFunction)) { + addedFunctionPermissions.add(path.lambdaFunction); + this.addLambdaPermissionCfnResource( + { + 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 = (resourceName: string) => { + this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}`, { + description: 'The Development stage deployment of your API.', + stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), + restApiId: cdk.Fn.ref(resourceName), + }); + }; +} + +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: $TSObject = { + 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 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 new file mode 100644 index 0000000000..81eed824aa --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-transform.ts @@ -0,0 +1,251 @@ +import * as cdk from '@aws-cdk/core'; +import { + $TSAny, + $TSContext, + $TSObject, + AmplifyCategories, + buildOverrideDir, + getAmplifyResourceByCategories, + JSONUtilities, + PathConstants, + pathManager, + stateManager, + Template, + writeCFNTemplate, +} from 'amplify-cli-core'; +import { formatter, printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import * as vm from 'vm2'; +import { AmplifyApigwResourceStack, ApigwInputs, CrudOperation, Path } from '.'; +import { ApigwInputState } from '../apigw-input-state'; +import { ADMIN_QUERIES_NAME } from '../../../category-constants'; +export class ApigwStackTransform { + _app: cdk.App; + cliInputs: ApigwInputs; + resourceTemplateObj: AmplifyApigwResourceStack | undefined; + cliInputsState: ApigwInputState; + cfn!: Template; + cfnInputParams!: $TSObject; + resourceName: string; + + 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(); + 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); + + // Generate cloudformation stack input params from cli-inputs.json + this.generateCfnInputParameters(); + + // Modify cloudformation files based on overrides + await this.applyOverrides(); + + // Save generated cloudformation.json and parameters.json files + await this.saveBuildFiles(); + } + + generateCfnInputParameters() { + this.cfnInputParams = {}; + } + + 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() { + 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).catch(error => { + printer.debug(`Skipping build as ${error.message}`); + return false; + }); + + // skip if packageManager or override.ts not found + if (isBuild) { + const { override } = await import(overrideJSFilePath).catch(error => { + formatter.list(['No override file found', `To override ${this.resourceName} run "amplify override api"`]); + return undefined; + }); + + if (override && typeof override === 'function') { + const overrideCode: string = await fs.readFile(overrideJSFilePath, 'utf-8').catch(() => { + formatter.list(['No override File Found', `To override ${this.resourceName} run amplify override auth`]); + return ''; + }); + + const sandboxNode = new vm.NodeVM({ + console: 'inherit', + timeout: 5000, + sandbox: {}, + require: { + context: 'sandbox', + builtin: ['path'], + external: true, + }, + }); + + try { + await sandboxNode.run(overrideCode, overrideJSFilePath).override(this.resourceTemplateObj as AmplifyApigwResourceStack); + } catch (err: $TSAny) { + const error = new Error(`Skipping override due to ${err}.`); + printer.error(`${error}`); + throw error; + } + } + } + } + + 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); + } +} + +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 new file mode 100644 index 0000000000..7b96c26fd5 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/index.ts @@ -0,0 +1,3 @@ +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 new file mode 100644 index 0000000000..4a3a8e0b67 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/cdk-stack-builder/types.ts @@ -0,0 +1,53 @@ +import * as cdk from '@aws-cdk/core'; +import * as apigwCdk from '@aws-cdk/aws-apigateway'; +import * as iamCdk from '@aws-cdk/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): 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 index d18bbae607..097e974297 100644 --- 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 @@ -1,19 +1,23 @@ -import { isResourceNameUnique } from 'amplify-cli-core'; +import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, + AppSyncServiceModification, ConflictResolution, ResolutionStrategy, UpdateApiRequest, } from 'amplify-headless-interface'; +import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; import { readTransformerConfiguration, TRANSFORM_CURRENT_VERSION, writeTransformerConfiguration } from 'graphql-transformer-core'; import _ from 'lodash'; import * as path from 'path'; -import uuid from 'uuid'; +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'; @@ -22,7 +26,7 @@ import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-c // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; -export const getCfnApiArtifactHandler = (context): ApiArtifactHandler => { +export const getCfnApiArtifactHandler = (context: $TSContext): ApiArtifactHandler => { return new CfnApiArtifactHandler(context); }; const resolversDirName = 'resolvers'; @@ -35,16 +39,17 @@ const defaultCfnParameters = (apiName: string) => ({ DynamoDBEnableServerSideEncryption: false, }); class CfnApiArtifactHandler implements ApiArtifactHandler { - private readonly context: any; + private readonly context: $TSContext; - constructor(context) { + 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 existingApiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + const meta = stateManager.getMeta(); + const existingApiName = getAppSyncResourceName(meta); if (existingApiName) { throw new Error(`GraphQL API ${existingApiName} already exists in the project. Use 'amplify update api' to make modifications.`); } @@ -70,9 +75,10 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await this.updateTransformerConfigVersion(resourceDir); serviceConfig.conflictResolution = await this.createResolverResources(serviceConfig.conflictResolution); - await writeResolverConfig(serviceConfig.conflictResolution, resourceDir); + const appsyncCLIInputs = await this.generateAppsyncCLIInputs(serviceConfig, resourceDir); + // Write the default custom resources stack out to disk. fs.copyFileSync( path.join(rootAssetDir, 'cloudformation-templates', 'defaultCustomResources.json'), @@ -80,9 +86,9 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { ); // write the template buffer to the project folder - this.writeSchema(resourceDir, serviceConfig.transformSchema); + this.writeSchema(appsyncCLIInputs.serviceConfiguration.gqlSchemaPath, serviceConfig.transformSchema); - const authConfig = this.extractAuthConfig(serviceConfig); + const authConfig = this.extractAuthConfig(appsyncCLIInputs.serviceConfiguration); await this.context.amplify.executeProviderUtils(this.context, 'awscloudformation', 'compileSchema', { resourceDir, @@ -98,21 +104,23 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { // for each service and delegate to the correct one updateArtifacts = async (request: UpdateApiRequest, opts?: ApiArtifactHandlerOptions): Promise => { const updates = request.serviceModification; - const apiName = getAppSyncResourceName(this.context.amplify.getProjectMeta()); + const apiName = getAppSyncResourceName(stateManager.getMeta()); if (!apiName) { throw new Error(`No AppSync API configured in the project. Use 'amplify add api' to create an API.`); } const resourceDir = this.getResourceDir(apiName); + // update appsync cli-inputs + const appsyncCLIInputs = await this.updateAppsyncCLIInputs(updates, apiName); if (updates.transformSchema) { - this.writeSchema(resourceDir, updates.transformSchema); + this.writeSchema(appsyncCLIInputs.serviceConfiguration.gqlSchemaPath, updates.transformSchema); } if (updates.conflictResolution) { - updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); + updates.conflictResolution = await this.createResolverResources(appsyncCLIInputs.serviceConfiguration.conflictResolution); await writeResolverConfig(updates.conflictResolution, resourceDir); } - const authConfig = getAppSyncAuthConfig(this.context.amplify.getProjectMeta()); - const previousAuthConfig = _.cloneDeep(authConfig); + const authConfig = getAppSyncAuthConfig(stateManager.getMeta()); + const previousAuthConfig = _.cloneDeep(authConfig); const oldConfigHadApiKey = authConfigHasApiKey(authConfig); if (updates.defaultAuthType) { authConfig.defaultAuthentication = appSyncAuthTypeToAuthConfig(updates.defaultAuthType); @@ -132,14 +140,14 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - printApiKeyWarnings(this.context, oldConfigHadApiKey, authConfigHasApiKey(authConfig)); + printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; private writeSchema = (resourceDir: string, schema: string) => { - fs.writeFileSync(path.join(resourceDir, gqlSchemaFilename), schema); + fs.writeFileSync(resourceDir, schema); }; - private getResourceDir = (apiName: string) => path.join(this.context.amplify.pathManager.getBackendDirPath(), category, apiName); + private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); private createAmplifyMeta = authConfig => ({ service: 'AppSync', @@ -149,7 +157,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }, }); - private extractAuthConfig = (config: AppSyncServiceConfiguration) => ({ + private extractAuthConfig = (config: AppSyncServiceConfig) => ({ defaultAuthentication: appSyncAuthTypeToAuthConfig(config.defaultAuthType), additionalAuthenticationProviders: (config.additionalAuthTypes || []).map(appSyncAuthTypeToAuthConfig), }); @@ -183,8 +191,8 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private getCfnParameters = (apiName: string, authConfig, resourceDir: string) => { - const params = - this.context.amplify.readJsonFile(path.join(resourceDir, cfnParametersFilename), undefined, false) || defaultCfnParameters(apiName); + const cfnPath = path.join(resourceDir, cfnParametersFilename); + const params = JSONUtilities.readJson<$TSAny>(cfnPath, { throwIfNotExist: false }) || defaultCfnParameters(apiName); const cognitoPool = this.getCognitoUserPool(authConfig); if (cognitoPool) { params.AuthCognitoUserPoolId = cognitoPool; @@ -201,7 +209,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const defaultAuth = authConfig.defaultAuthentication || {}; if (defaultAuth.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { let userPoolId; - const configuredUserPoolName = checkIfAuthExists(this.context); + const configuredUserPoolName = checkIfAuthExists(); if (authConfig.userPoolConfig) { ({ userPoolId } = authConfig.userPoolConfig); @@ -220,7 +228,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; private createSyncFunction = async () => { - const targetDir = this.context.amplify.pathManager.getBackendDirPath(); + const targetDir = pathManager.getBackendDirPath(); const assetDir = path.normalize(path.join(rootAssetDir, 'sync-conflict-handler')); const [shortId] = uuid().split('-'); @@ -235,17 +243,17 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { { dir: assetDir, template: 'sync-conflict-handler-index.js.ejs', - target: `${targetDir}/function/${functionName}/src/index.js`, + target: path.join(targetDir, 'function', functionName, 'src', 'index.js'), }, { dir: assetDir, template: 'sync-conflict-handler-package.json.ejs', - target: `${targetDir}/function/${functionName}/src/package.json`, + target: path.join(targetDir, 'function', functionName, 'src', 'package.json'), }, { dir: assetDir, template: 'sync-conflict-handler-template.json.ejs', - target: `${targetDir}/function/${functionName}/${functionName}-cloudformation-template.json`, + target: path.join(targetDir, 'function', functionName, `${functionName}-cloudformation-template.json`), }, ]; @@ -259,10 +267,57 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); - this.context.print.success(`Successfully added ${functionName} function locally`); + printer.success(`Successfully added ${functionName} function locally`); return functionName + '-${env}'; }; + + private generateAppsyncCLIInputs = async (serviceConfig: AppSyncServiceConfiguration, resourceDir: string) => { + const appsyncCLIInputs: AppSyncCLIInputs = { + version: 1, + serviceConfiguration: { + apiName: serviceConfig.apiName, + serviceName: serviceConfig.serviceName, + gqlSchemaPath: path.join(resourceDir, gqlSchemaFilename), + 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(serviceConfig.apiName); + await cliState.saveCLIInputPayload(appsyncCLIInputs); + return appsyncCLIInputs; + }; + + private updateAppsyncCLIInputs = async (updates: AppSyncServiceModification, apiName: string) => { + const cliState = new AppsyncApiInputState(apiName); + const prevAppsyncInputs = cliState.getCLIInputPayload(); + + const appsyncInputs: AppSyncCLIInputs = prevAppsyncInputs; + if (!_.isEmpty(appsyncInputs.serviceConfiguration)) { + appsyncInputs.serviceConfiguration.gqlSchemaPath = path.join(this.getResourceDir(apiName), gqlSchemaFilename); + } + 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 appsyncInputs; + }; } /** @@ -271,7 +326,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { * * write to the transformer conf if the resolverConfig is valid */ -export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir) => { +export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir: string) => { const localTransformerConfig = await readTransformerConfiguration(resourceDir); localTransformerConfig.ResolverConfig = conflictResolutionToResolverConfig(conflictResolution); await writeTransformerConfiguration(resourceDir, localTransformerConfig); 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 index 0a402bd123..1bc866ab6c 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/containers-handler.ts @@ -1,22 +1,22 @@ -import fs from 'fs-extra'; -import path from 'path'; -import uuid from 'uuid'; +import { $TSContext, createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +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'; -import { createDefaultCustomPoliciesFile, pathManager } from 'amplify-cli-core'; export const addResource = async ( serviceWalkthroughPromise: Promise, - context, - category, + context: $TSContext, + category: string, service, options, apiType: API_TYPE, ) => { - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const walkthroughOptions = await serviceWalkthroughPromise; const { @@ -31,7 +31,7 @@ export const addResource = async ( dependsOn = [], mutableParametersState, } = walkthroughOptions; - const resourceDirPath = path.join(projectBackendDirPath, category, resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, resourceName); let [authName, updatedDependsOn] = await getResourceDependencies({ dependsOn, restrictAccess, category, resourceName, context }); @@ -88,36 +88,37 @@ export const addResource = async ( if (imageSource.type === IMAGE_SOURCE_TYPE.TEMPLATE) { fs.copySync( - path.join(__dirname, '../../../resources/awscloudformation/container-templates', imageSource.template), + path.join(__dirname, '..', '..', '..', 'resources', 'awscloudformation/container-templates', imageSource.template), path.join(resourceDirPath, 'src'), - { recursive: true } + { 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); - context.print.success(`Successfully added resource ${resourceName} locally.`); - context.print.info(''); - context.print.success('Next steps:'); + printer.success(`Successfully added resource ${resourceName} locally.`); + printer.info(''); + printer.success('Next steps:'); if (deploymentMechanism === DEPLOYMENT_MECHANISM.FULLY_MANAGED) { - context.print.info(`- Place your Dockerfile, docker-compose.yml and any related container source files in "amplify/backend/api/${resourceName}/src"`); + 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) { - context.print.info( + printer.info( `- Ensure you have the Dockerfile, docker-compose.yml and any related container source files in your Github path: ${gitHubInfo.path}`, ); } - context.print.info( + printer.info( `- Amplify CLI infers many configuration settings from the "docker-compose.yaml" file. Learn more: docs.amplify.aws/cli/usage/containers`, ); - context.print.info(`- To access AWS resources outside of this Amplify app, edit the ${customPoliciesPath}`); - context.print.info('- Run "amplify push" to build and deploy your image'); + 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; }; @@ -131,7 +132,7 @@ const getResourceDependencies = async ({ }: { restrictAccess: boolean; dependsOn: ResourceDependency[]; - context: any; + context: $TSContext; category: string; resourceName: string; }) => { @@ -165,7 +166,7 @@ const getResourceDependencies = async ({ apiRequirements, ]); } catch (e) { - context.print.error(e); + printer.error(e); throw e; } } else { @@ -192,7 +193,7 @@ const getResourceDependencies = async ({ return [authName, updatedDependsOn]; }; -export const updateResource = async (serviceWalkthroughPromise: Promise, context, category) => { +export const updateResource = async (serviceWalkthroughPromise: Promise, context: $TSContext, category: string) => { const options = await serviceWalkthroughPromise; const { diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts similarity index 68% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts index 7ab876f8fa..60dbcd9da4 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/apigw-defaults.ts @@ -1,6 +1,6 @@ -const uuid = require('uuid'); +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +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 = { @@ -11,7 +11,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts similarity index 71% rename from packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js rename to packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts index 0d5cb71570..8c48966c22 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.js +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/default-values/appSync-defaults.ts @@ -1,6 +1,7 @@ -const uuid = require('uuid'); +import { $TSMeta } from 'amplify-cli-core'; +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +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('-'); @@ -16,7 +17,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; 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 index da44caf946..0f77dee83e 100644 --- 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 @@ -1,6 +1,6 @@ -const uuid = require('uuid'); +import { v4 as uuid } from 'uuid'; -const getAllDefaults = project => { +export const getAllDefaults = () => { const [shortId] = uuid().split('-'); const defaults = { resourceName: `container${shortId}`, @@ -8,7 +8,3 @@ const getAllDefaults = project => { return defaults; }; - -module.exports = { - getAllDefaults, -}; 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 index 39f92df12e..a66729ca10 100644 --- 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 @@ -1,3 +1 @@ -import { getContainers } from "./converter"; - -export { getContainers }; \ No newline at end of file +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 index c66f371960..01ca720b38 100644 --- 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 @@ -7,8 +7,8 @@ import * as elb2 from '@aws-cdk/aws-elasticloadbalancingv2'; import * as route53 from '@aws-cdk/aws-route53'; import * as route53targets from '@aws-cdk/aws-route53-targets'; import * as cdk from '@aws-cdk/core'; -import { ContainersStack, ContainersStackProps } from './base-api-stack'; import { v4 as uuid } from 'uuid'; +import { ContainersStack, ContainersStackProps } from './base-api-stack'; type EcsStackProps = ContainersStackProps & Readonly<{ diff --git a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts index 4ee7ce6fee..65227effd0 100644 --- a/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/index.ts @@ -1,28 +1,52 @@ -import { serviceWalkthroughResultToAddApiRequest } from './utils/service-walkthrough-result-to-add-api-request'; -import { getCfnApiArtifactHandler } from './cfn-api-artifact-handler'; -import { serviceMetadataFor, getServiceWalkthrough, datasourceMetadataFor } from './utils/dynamic-imports'; -import { legacyAddResource } from './legacy-add-resource'; -import { legacyUpdateResource } from './legacy-update-resource'; +import { $TSAny, $TSContext, $TSObject, AmplifySupportedService, exitOnNextTick, NotImplementedError } from 'amplify-cli-core'; import { UpdateApiRequest } from 'amplify-headless-interface'; -import { editSchemaFlow } from './utils/edit-schema-flow'; -import { NotImplementedError, exitOnNextTick } from 'amplify-cli-core'; -import { addResource as addContainer, updateResource as updateContainer } from './containers-handler'; +import { printer } from 'amplify-prompts'; import inquirer from 'inquirer'; +import * as path from 'path'; +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, - ServiceConfiguration, getPermissionPolicies as getContainerPermissionPolicies, + ServiceConfiguration, } from './service-walkthroughs/containers-walkthrough'; -import { category } from '../../category-constants'; +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: $TSObject[] }, +) { + 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: $TSObject[] }, +) { + 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, service) { +export async function console(context: $TSContext, service: string) { const { serviceWalkthroughFilename } = await serviceMetadataFor(service); - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { openConsole } = require(serviceWalkthroughSrc); + 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'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -30,24 +54,23 @@ export async function console(context, service) { return openConsole(context); } -async function addContainerResource(context, category, service, options, apiType) { +async function addContainerResource(context: $TSContext, service: string, options, apiType: API_TYPE) { const serviceWalkthroughFilename = 'containers-walkthrough.js'; - const defaultValuesFilename = 'containers-defaults.js'; const serviceWalkthrough = await getServiceWalkthrough(serviceWalkthroughFilename); - const serviceWalkthroughPromise: Promise = serviceWalkthrough(context, defaultValuesFilename, apiType); + const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, apiType); return await addContainer(serviceWalkthroughPromise, context, category, service, options, apiType); } -async function addNonContainerResource(context, category, service, options) { +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, defaultValuesFilename, serviceMetadata); + const serviceWalkthroughPromise: Promise<$TSAny> = serviceWalkthrough(context, serviceMetadata); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: const walkthroughResult = await serviceWalkthroughPromise; const askToEdit = walkthroughResult.askToEdit; const apiName = await getCfnApiArtifactHandler(context).createArtifacts(serviceWalkthroughResultToAddApiRequest(walkthroughResult)); @@ -55,23 +78,26 @@ async function addNonContainerResource(context, category, service, options) { 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, 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 'AppSync': - useContainerResource = await isGraphQLContainer(context); + case AmplifySupportedService.APPSYNC: + useContainerResource = await isGraphQLContainer(); apiType = API_TYPE.GRAPHQL; break; - case 'API Gateway': - useContainerResource = await isRestContainer(context); + case AmplifySupportedService.APIGW: + useContainerResource = await isRestContainer(); apiType = API_TYPE.REST; break; default: @@ -80,11 +106,11 @@ export async function addResource(context, category, service, options) { } return useContainerResource - ? addContainerResource(context, category, service, options, apiType) - : addNonContainerResource(context, category, service, options); + ? addContainerResource(context, service, options, apiType) + : addNonContainerResource(context, service, options); } -function isContainersEnabled(context) { +function isContainersEnabled(context: $TSContext) { const { frontend } = context.amplify.getProjectConfig(); if (frontend) { const { config: { ServerlessContainers = false } = {} } = context.amplify.getProjectConfig()[frontend] || {}; @@ -95,14 +121,14 @@ function isContainersEnabled(context) { return false; } -async function isGraphQLContainer(context): Promise { +async function isGraphQLContainer(): Promise { const { graphqlSelection } = await inquirer.prompt({ name: 'graphqlSelection', message: 'Which service would you like to use', type: 'list', choices: [ { - name: 'AppSync', + name: AmplifySupportedService.APPSYNC, value: false, }, { @@ -115,7 +141,7 @@ async function isGraphQLContainer(context): Promise { return graphqlSelection; } -async function isRestContainer(context) { +async function isRestContainer() { const { restSelection } = await inquirer.prompt({ name: 'restSelection', message: 'Which service would you like to use', @@ -135,22 +161,18 @@ async function isRestContainer(context) { return restSelection; } -export async function updateResource(context, category, service, options) { +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); + const { hasAPIGatewayContainerResource, hasAPIGatewayLambdaResource, hasGraphQLAppSyncResource, hasGraphqlContainerResource } = + await describeApiResourcesBySubCategory(context); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: if (hasGraphQLAppSyncResource && hasGraphqlContainerResource) { - useContainerResource = await isGraphQLContainer(context); + useContainerResource = await isGraphQLContainer(); } else if (hasGraphqlContainerResource) { useContainerResource = true; } else { @@ -158,9 +180,9 @@ export async function updateResource(context, category, service, options) { } apiType = API_TYPE.GRAPHQL; break; - case 'API Gateway': + case AmplifySupportedService.APIGW: if (hasAPIGatewayContainerResource && hasAPIGatewayLambdaResource) { - useContainerResource = await isRestContainer(context); + useContainerResource = await isRestContainer(); } else if (hasAPIGatewayContainerResource) { useContainerResource = true; } else { @@ -173,12 +195,10 @@ export async function updateResource(context, category, service, options) { } } - return useContainerResource - ? updateContainerResource(context, category, service, apiType) - : updateNonContainerResource(context, category, service); + return useContainerResource ? updateContainerResource(context, category, service, apiType) : updateNonContainerResource(context, service); } -async function describeApiResourcesBySubCategory(context) { +async function describeApiResourcesBySubCategory(context: $TSContext) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources.filter(resource => resource.category === category && resource.mobileHubMigrated !== true); @@ -191,9 +211,9 @@ async function describeApiResourcesBySubCategory(context) { hasAPIGatewayContainerResource = hasAPIGatewayContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.REST); - hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === 'API Gateway'; + hasAPIGatewayLambdaResource = hasAPIGatewayLambdaResource || resource.service === AmplifySupportedService.APIGW; - hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === 'AppSync'; + hasGraphQLAppSyncResource = hasGraphQLAppSyncResource || resource.service === AmplifySupportedService.APPSYNC; hasGraphqlContainerResource = hasGraphqlContainerResource || (resource.service === 'ElasticContainer' && resource.apiType === API_TYPE.GRAPHQL); @@ -207,33 +227,32 @@ async function describeApiResourcesBySubCategory(context) { }; } -async function updateContainerResource(context, category, service, apiType: API_TYPE) { +async function updateContainerResource(context: $TSContext, category: string, service: string, apiType: API_TYPE) { const serviceWalkthroughFilename = 'containers-walkthrough'; - const defaultValuesFilename = 'containers-defaults.js'; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { updateWalkthrough } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { updateWalkthrough } = await import(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } - const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, apiType); + const updateWalkthroughPromise: Promise = updateWalkthrough(context, apiType); updateContainer(updateWalkthroughPromise, context, category); } -async function updateNonContainerResource(context, category, service) { +async function updateNonContainerResource(context: $TSContext, service: string) { const serviceMetadata = await serviceMetadataFor(service); const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { updateWalkthrough } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { updateWalkthrough } = await import(serviceWalkthroughSrc); if (!updateWalkthrough) { const errMessage = 'Update functionality not available for this option'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new NotImplementedError(errMessage)); exitOnNextTick(0); } @@ -241,14 +260,15 @@ async function updateNonContainerResource(context, category, service) { const updateWalkthroughPromise: Promise = updateWalkthrough(context, defaultValuesFilename, serviceMetadata); switch (service) { - case 'AppSync': + case AmplifySupportedService.APPSYNC: return updateWalkthroughPromise.then(getCfnApiArtifactHandler(context).updateArtifacts); default: - return legacyUpdateResource(updateWalkthroughPromise, context, category, service); + const apigwInputState = new ApigwInputState(context); + return apigwInputState.updateApigwResource(updateWalkthroughPromise); } } -export async function migrateResource(context, projectPath, service, resourceName) { +export async function migrateResource(context: $TSContext, projectPath: string, service: string, resourceName: string) { if (service === 'ElasticContainer') { return migrateResourceContainer(context, projectPath, service, resourceName); } else { @@ -256,53 +276,53 @@ export async function migrateResource(context, projectPath, service, resourceNam } } -async function migrateResourceContainer(context, projectPath, service, resourceName) { - context.print.info(`No migration required for ${resourceName}`); +async function migrateResourceContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { + printer.info(`No migration required for ${resourceName}`); return; } -async function migrateResourceNonContainer(context, projectPath, service, resourceName) { +async function migrateResourceNonContainer(context: $TSContext, projectPath: string, service: string, resourceName: string) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { migrate } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { migrate } = await import(serviceWalkthroughSrc); if (!migrate) { - context.print.info(`No migration required for ${resourceName}`); + printer.info(`No migration required for ${resourceName}`); return; } return await migrate(context, projectPath, resourceName); } -export async function addDatasource(context, category, datasource) { +export async function addDatasource(context: $TSContext, category, datasource) { const serviceMetadata = await datasourceMetadataFor(datasource); - const { defaultValuesFilename, serviceWalkthroughFilename } = serviceMetadata; - return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, defaultValuesFilename, serviceMetadata); + const { serviceWalkthroughFilename } = serviceMetadata; + return (await getServiceWalkthrough(serviceWalkthroughFilename))(context, serviceMetadata); } -export async function getPermissionPolicies(context, service, resourceName, crudOptions) { +export async function getPermissionPolicies(context: $TSContext, service: string, resourceName: string, crudOptions) { if (service === 'ElasticContainer') { return getPermissionPoliciesContainer(context, service, resourceName, crudOptions); } else { - return getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions); + return getPermissionPoliciesNonContainer(service, resourceName, crudOptions); } } -async function getPermissionPoliciesContainer(context, service, resourceName, crudOptions) { +async function getPermissionPoliciesContainer(context: $TSContext, service: string, resourceName: string, crudOptions) { return getContainerPermissionPolicies(context, service, resourceName, crudOptions); } -async function getPermissionPoliciesNonContainer(context, service, resourceName, crudOptions) { +async function getPermissionPoliciesNonContainer(service: string, resourceName: string, crudOptions: string[]) { const serviceMetadata = await serviceMetadataFor(service); const { serviceWalkthroughFilename } = serviceMetadata; - const serviceWalkthroughSrc = `${__dirname}/service-walkthroughs/${serviceWalkthroughFilename}`; - const { getIAMPolicies } = require(serviceWalkthroughSrc); + const serviceWalkthroughSrc = path.join(__dirname, 'service-walkthroughs', serviceWalkthroughFilename); + const { getIAMPolicies } = await import(serviceWalkthroughSrc); if (!getIAMPolicies) { - context.print.info(`No policies found for ${resourceName}`); + printer.info(`No policies found for ${resourceName}`); return; } - return getIAMPolicies(resourceName, crudOptions, context); + 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 index ff7e33a189..29ced6ba3b 100644 --- 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 @@ -1,4 +1,4 @@ -import { isResourceNameUnique, JSONUtilities } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, isResourceNameUnique, JSONUtilities, pathManager } from 'amplify-cli-core'; import * as fs from 'fs-extra'; import * as path from 'path'; import { cfnParametersFilename, parametersFileName, rootAssetDir } from './aws-constants'; @@ -6,10 +6,15 @@ 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, category, service, options) => { +export const legacyAddResource = async ( + serviceWalkthroughPromise: Promise<$TSAny>, + context: $TSContext, + category: string, + service: string, + options: $TSObject, +) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await serviceWalkthroughPromise; @@ -30,7 +35,7 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, copyCfnTemplate(context, category, answers, cfnFilename); const parameters = { ...answers }; - const resourceDirPath = path.join(projectBackendDirPath, category, parameters.resourceName); + const resourceDirPath = pathManager.getResourceDirectoryPath(undefined, category, parameters.resourceName); isResourceNameUnique(category, parameters.resourceName); @@ -47,15 +52,14 @@ export const legacyAddResource = async (serviceWalkthroughPromise: Promise, }; // exported because the update flow still uses this method directly for now -export const copyCfnTemplate = (context, category, options, cfnFilename) => { - const { amplify } = context; - const targetDir = amplify.pathManager.getBackendDirPath(); +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: `${targetDir}/${category}/${options.resourceName}/${options.resourceName}-cloudformation-template.json`, + target: path.join(resourceDirPath, `${options.resourceName}-cloudformation-template.json`), }, ]; 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 index 99a15a9365..930523a24a 100644 --- 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 @@ -1,15 +1,15 @@ -import { serviceMetadataFor } from './utils/dynamic-imports'; -import { copyCfnTemplate, addPolicyResourceNameToPaths } from './legacy-add-resource'; -import fs from 'fs-extra'; -import path from 'path'; +import { $TSAny, $TSContext, JSONUtilities, pathManager } from 'amplify-cli-core'; +import * as fs from 'fs-extra'; +import * as path from 'path'; 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, category, service) => { +export const legacyUpdateResource = async (updateWalkthroughPromise: Promise<$TSAny>, context: $TSContext, category: string, service) => { let answers; let { cfnFilename } = await serviceMetadataFor(service); - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); const result = await updateWalkthroughPromise; - const options: any = {}; + const options: $TSAny = {}; if (result) { if (result.answers) { ({ answers } = result); @@ -25,11 +25,10 @@ export const legacyUpdateResource = async (updateWalkthroughPromise: Promise; + +export type ApigwAnswers = { + paths: { [pathName: string]: ApigwPath }; + resourceName: string; + functionArns?: string[]; + dependsOn?: $TSObject[]; +}; 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 new file mode 100644 index 0000000000..81480d62d0 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthrough-types/appsync-user-input-types.ts @@ -0,0 +1,175 @@ +/** + * 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; + /** + * Path to GraphQL schema that defines the AppSync API. + */ + gqlSchemaPath: 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 index ac3390df3e..4a61ff3274 100644 --- 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 @@ -1,113 +1,95 @@ -import { $TSContext, exitOnNextTick, isResourceNameUnique, open, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; -import * as fs from 'fs-extra'; +import { + $TSAny, + $TSContext, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + exitOnNextTick, + isResourceNameUnique, + open, + pathManager, + ResourceDoesNotExistError, + stateManager, +} from 'amplify-cli-core'; +import { byValues, printer, prompter } from 'amplify-prompts'; import inquirer from 'inquirer'; import os from 'os'; -import * as path from 'path'; -import uuid from 'uuid'; -import { rootAssetDir } from '../aws-constants'; +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'; -// keep in sync with ServiceName in amplify-category-function, but probably it will not change -const FunctionServiceNameLambdaFunction = 'Lambda'; - -const category = 'api'; -const serviceName = 'API Gateway'; +const category = AmplifyCategories.API; +const serviceName = AmplifySupportedService.APIGW; const elasticContainerServiceName = 'ElasticContainer'; -const parametersFileName = 'api-params.json'; -const cfnParametersFilename = 'parameters.json'; - -export async function serviceWalkthrough(context, defaultValuesFilename) { - const { amplify } = context; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); - let answers = { - paths: [], - }; +export async function serviceWalkthrough(context: $TSContext): ApigwWalkthroughReturnPromise { + const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); - const apiNames = await askApiNames(context, allDefaultValues); - answers = { ...answers, ...apiNames }; + const resourceName = await askApiName(context, allDefaultValues.resourceName); + const answers = { paths: {}, resourceName, dependsOn: undefined }; return pathFlow(context, answers); } -export async function updateWalkthrough(context, defaultValuesFilename) { - const { amplify } = context; +export async function updateWalkthrough(context: $TSContext) { const { allResources } = await context.amplify.getResourceStatus(); - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); + const allDefaultValues = getAllDefaults(context.amplify.getProjectDetails()); const resources = allResources .filter(resource => resource.service === serviceName && resource.mobileHubMigrated !== true) .map(resource => resource.resourceName); - // There can only be one appsync resource if (resources.length === 0) { - const errMessage = 'No REST API resource to update. Please use "amplify add api" command to create a new REST API'; - context.print.error(errMessage); + 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 = { + let answers: $TSAny = { paths: [], }; - const question = [ - { - name: 'resourceName', - message: 'Please select the REST API you would want to update', - type: 'list', - choices: resources, - }, - { - name: 'operation', - message: 'What would you like to do', - type: 'list', - when: context.input.command !== 'add', - choices: [ - { name: 'Add another path', value: 'add' }, - { name: 'Update path', value: 'update' }, - { name: 'Remove path', value: 'remove' }, - ], - }, - ]; - - const updateApi = await inquirer.prompt(question); + 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') { - updateApi.operation = 'add'; + updateApiOperation = 'add'; } - if (updateApi.resourceName === 'AdminQueries') { + 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`; - context.print.warning(errMessage); + printer.warn(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } - const projectBackendDirPath = context.amplify.pathManager.getBackendDirPath(); - const resourceDirPath = path.join(projectBackendDirPath, category, updateApi.resourceName as string); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let parameters; - try { - parameters = context.amplify.readJsonFile(parametersFilePath); - } catch (e) { - parameters = {}; + const projRoot = pathManager.findProjectRoot(); + if (!stateManager.resourceInputsJsonExists(projRoot, category, selectedApiName)) { + // Not yet migrated + await migrate(context, projRoot, selectedApiName); } - parameters.resourceName = updateApi.resourceName; + + const parameters = stateManager.getResourceInputsJson(projRoot, category, selectedApiName); + parameters.resourceName = selectedApiName; Object.assign(allDefaultValues, parameters); answers = { ...answers, ...parameters }; [answers.uuid] = uuid().split('-'); - const pathList = answers.paths.map(path => path.name); + const pathNames = Object.keys(answers.paths); let updatedResult = {}; - switch (updateApi.operation) { + switch (updateApiOperation) { case 'add': { updatedResult = pathFlow(context, answers); break; @@ -115,76 +97,51 @@ export async function updateWalkthrough(context, defaultValuesFilename) { case 'remove': { const pathToRemove = await inquirer.prompt({ name: 'path', - message: 'Please select the path you would want to remove', + message: 'Select the path to remove', type: 'list', - choices: pathList, + choices: pathNames, }); - answers.paths = answers.paths.filter(path => path.name !== pathToRemove.path); + delete answers.paths[pathToRemove.path]; - const { dependsOn, functionArns } = await findDependsOn(answers.paths, context); + const { dependsOn, functionArns } = await findDependsOn(answers.paths); answers.dependsOn = dependsOn; answers.functionArns = functionArns; - updatedResult = { answers, dependsOn }; + updatedResult = { answers }; break; } case 'update': { const pathToEdit = await inquirer.prompt({ - name: 'path', - message: 'Please select the path you would want to edit', + name: 'pathName', + message: 'Select the path to edit', type: 'list', - choices: pathList, + choices: pathNames, }); // removing path from paths list - const currentPath = answers.paths.find(path => path.name === pathToEdit.path); - answers.paths = answers.paths.filter(path => path.name !== pathToEdit.path); + const currentPath: ApigwPath = answers.paths[pathToEdit.pathName]; + delete answers.paths[pathToEdit.pathName]; updatedResult = pathFlow(context, answers, currentPath); break; } default: { - updatedResult = {}; + throw new Error(`Unrecognized API update operation "${updateApiOperation}"`); } } return updatedResult; } -async function pathFlow(context, answers, currentPath?) { +async function pathFlow(context: $TSContext, answers: ApigwAnswers, currentPath?: ApigwPath): ApigwWalkthroughReturnPromise { const pathsAnswer = await askPaths(context, answers, currentPath); - answers = { ...answers, paths: pathsAnswer.paths, functionArns: pathsAnswer.functionArns }; - const { dependsOn } = pathsAnswer; - - const privacy = { - auth: pathsAnswer.paths.filter(path => path.privacy.auth && path.privacy.auth.length > 0).length, - unauth: pathsAnswer.paths.filter(path => path.privacy.unauth && path.privacy.unauth.length > 0).length, - }; - - answers = { ...answers, privacy, dependsOn }; - - if ( - context.amplify.getProjectDetails() && - context.amplify.getProjectDetails().amplifyMeta && - context.amplify.getProjectDetails().amplifyMeta.providers && - context.amplify.getProjectDetails().amplifyMeta.providers.awscloudformation - ) { - // TODO: read from utility functions (Dustin PR) - const { amplifyMeta } = context.amplify.getProjectDetails(); - const providerInfo = amplifyMeta.providers.awscloudformation; - - answers.privacy.authRoleName = providerInfo.AuthRoleName; - answers.privacy.unAuthRoleName = providerInfo.UnauthRoleName; - } - - return { answers, dependsOn }; + return { answers: pathsAnswer }; } -async function askApiNames(context, defaults) { - const { amplify } = context; +async function askApiName(context: $TSContext, defaultResourceName: string) { const apiNameValidator = (input: string) => { - const amplifyValidatorOutput = amplify.inputValidation({ + const amplifyValidatorOutput = context.amplify.inputValidation({ validation: { operator: 'regex', value: '^[a-zA-Z0-9]+$', @@ -193,6 +150,11 @@ async function askApiNames(context, defaults) { 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); @@ -202,111 +164,90 @@ async function askApiNames(context, defaults) { return typeof amplifyValidatorOutput === 'string' ? amplifyValidatorOutput : uniqueCheck; }; - const answer: { apiName?: string; resourceName: string } = 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: defaults.resourceName, - validate: apiNameValidator, - }, - ]); + 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 }, + ); - answer.apiName = answer.resourceName; - - return answer; + return resourceName; } -async function askPrivacy(context, answers, currentPath) { +async function askPermissions( + context: $TSContext, + answers: $TSObject, + currentPath?: ApigwPath, +): Promise<{ setting?: PermissionSetting; auth?: CrudOperation[]; open?: boolean; userPoolGroups?: $TSObject; guest?: CrudOperation[] }> { while (true) { - const apiAccess = await inquirer.prompt({ - name: 'restrict', - type: 'confirm', - default: !(currentPath && currentPath.open), - message: 'Restrict API access', - }); + const apiAccess = await prompter.yesOrNo('Restrict API access?', currentPath?.permissions?.setting !== PermissionSetting.OPEN); - if (!apiAccess.restrict) { - return { open: true }; + if (!apiAccess) { + return { setting: PermissionSetting.OPEN }; } - const userPoolGroupList = await context.amplify.getUserPoolGroupList(context); + const userPoolGroupList = context.amplify.getUserPoolGroupList(); let permissionSelected = 'Auth/Guest Users'; - const privacy: any = {}; + const permissions: $TSObject = {}; if (userPoolGroupList.length > 0) { do { if (permissionSelected === 'Learn more') { - context.print.info(''); - context.print.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(); + 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.', ); - context.print.info(''); + printer.blankLine(); } - const permissionSelection = await inquirer.prompt({ - name: 'selection', - type: 'list', - message: 'Restrict access by?', - choices: ['Auth/Guest Users', 'Individual Groups', 'Both', 'Learn more'], - default: 'Auth/Guest Users', - }); - - permissionSelected = permissionSelection.selection; + 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 answer = await inquirer.prompt({ - name: 'privacy', - type: 'list', - message: 'Who should have access?', - choices: [ + const permissionSetting = await prompter.pick<'one', string>( + 'Who should have access?', + [ { name: 'Authenticated users only', - value: 'private', + value: PermissionSetting.PRIVATE, }, { name: 'Authenticated and Guest users', - value: 'protected', + value: PermissionSetting.PROTECTED, }, ], - default: currentPath && currentPath.privacy && currentPath.privacy.protected ? 'protected' : 'private', - }); - - privacy[answer.privacy] = true; + { initial: currentPath?.permissions?.setting === PermissionSetting.PROTECTED ? 1 : 0 }, + ); - context.api = { - privacy: answer.privacy, - }; + permissions.setting = permissionSetting; let { - privacy: { auth: authPrivacy }, - } = currentPath || { privacy: {} }; + permissions: { auth: authPermissions }, + } = currentPath || { permissions: { auth: [] } }; let { - privacy: { unauth: unauthPrivacy }, - } = currentPath || { privacy: {} }; + permissions: { guest: unauthPermissions }, + } = currentPath || { permissions: { guest: [] } }; - // convert legacy permissions to CRUD structure - if (authPrivacy && ['r', 'rw'].includes(authPrivacy)) { - authPrivacy = convertToCRUD(authPrivacy); - } - if (unauthPrivacy && ['r', 'rw'].includes(unauthPrivacy)) { - unauthPrivacy = convertToCRUD(unauthPrivacy); - } - - if (answer.privacy === 'private') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); + if (permissionSetting === PermissionSetting.PRIVATE) { + permissions.auth = await askCRUD('Authenticated', authPermissions); - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); } - if (answer.privacy === 'protected') { - privacy.auth = await askReadWrite('Authenticated', context, authPrivacy); - privacy.unauth = await askReadWrite('Guest', context, unauthPrivacy); - const apiRequirements = { authSelections: 'identityPoolAndUserPool', allowUnauthenticatedIdentities: true }; + 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); } @@ -315,60 +256,52 @@ async function askPrivacy(context, answers, currentPath) { if (permissionSelected === 'Both' || permissionSelected === 'Individual Groups') { // Enable Auth if not enabled - const apiRequirements = { authSelections: 'identityPoolAndUserPool' }; + const apiRequirements: ApiRequirements = { authSelections: 'identityPoolAndUserPool' }; await ensureAuth(context, apiRequirements, answers.resourceName); // Get Auth resource name - const authResourceName = await getAuthResourceName(context); + const authResourceName = getAuthResourceName(); answers.authResourceName = authResourceName; - let defaultSelectedGroups = []; + let defaultSelectedGroups: string[] = []; - if (currentPath && currentPath.privacy && currentPath.privacy.userPoolGroups) { - defaultSelectedGroups = Object.keys(currentPath.privacy.userPoolGroups); + if (currentPath?.permissions?.groups) { + defaultSelectedGroups = Object.keys(currentPath.permissions.groups); } - const userPoolGroupSelection = await inquirer.prompt([ - { - name: 'userpoolGroups', - type: 'checkbox', - message: 'Select groups:', - choices: userPoolGroupList, - default: defaultSelectedGroups, - validate: inputs => { - if (inputs.length === 0) { - return 'Select at least one option'; - } - return true; - }, - }, - ]); + let selectedUserPoolGroupList = await prompter.pick<'many', string>('Select groups:', userPoolGroupList, { + initial: byValues(defaultSelectedGroups)(userPoolGroupList), + returnSize: 'many', + pickAtLeast: 1, + }); - const selectedUserPoolGroupList = userPoolGroupSelection.userpoolGroups; + //if single user pool group is selected, convert to array + if (selectedUserPoolGroupList && !Array.isArray(selectedUserPoolGroupList)) { + selectedUserPoolGroupList = [selectedUserPoolGroupList]; + } - for (let i = 0; i < selectedUserPoolGroupList.length; i += 1) { + for (const selectedUserPoolGroup of selectedUserPoolGroupList) { let defaults = []; - if ( - currentPath && - currentPath.privacy && - currentPath.privacy.userPoolGroups && - currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]] - ) { - defaults = currentPath.privacy.userPoolGroups[selectedUserPoolGroupList[i]]; + if (currentPath?.permissions?.groups?.[selectedUserPoolGroup]) { + defaults = currentPath.permissions.groups[selectedUserPoolGroup]; } - if (!privacy.userPoolGroups) { - privacy.userPoolGroups = {}; + if (!permissions.groups) { + permissions.groups = {}; } - privacy.userPoolGroups[selectedUserPoolGroupList[i]] = await askReadWrite(selectedUserPoolGroupList[i], context, defaults); + permissions.groups[selectedUserPoolGroup] = await askCRUD(selectedUserPoolGroup, defaults); + } + + if (!permissions.setting) { + permissions.setting = PermissionSetting.PRIVATE; } } - return privacy; + return permissions; } } -async function ensureAuth(context, apiRequirements, resourceName) { - const checkResult = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ +async function ensureAuth(context: $TSContext, apiRequirements: ApiRequirements, resourceName: string) { + const checkResult: $TSAny = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'checkRequirements', [ apiRequirements, context, 'api', @@ -382,7 +315,7 @@ async function ensureAuth(context, apiRequirements, resourceName) { } if (checkResult.errors && checkResult.errors.length > 0) { - context.print.warning(checkResult.errors.join(os.EOL)); + printer.warn(checkResult.errors.join(os.EOL)); } // If auth is not imported and there were errors, adjust or enable auth configuration @@ -390,61 +323,37 @@ async function ensureAuth(context, apiRequirements, resourceName) { try { await context.amplify.invokePluginMethod(context, 'auth', undefined, 'externalAuthEnable', [ context, - 'api', + AmplifyCategories.API, resourceName, apiRequirements, ]); } catch (error) { - context.print.error(error); + printer.error(error); throw error; } } } -async function askReadWrite(userType, context, privacy) { - const permissionMap = { - create: ['/POST'], - read: ['/GET'], - update: ['/PUT', '/PATCH'], - delete: ['/DELETE'], - }; - - const defaults = []; - if (privacy) { - Object.values(permissionMap).forEach((el, index) => { - if (el.every(i => privacy.includes(i))) { - defaults.push(Object.keys(permissionMap)[index]); - } - }); - } - - const crudAnswers = await context.amplify.crudFlow(userType, permissionMap, defaults); +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, answers, currentPath) { - // const existingLambdaArns = true; - - const existingFunctions = functionsExist(context); - - const choices = [ - { - name: 'Create a new Lambda function', - value: 'newFunction', - }, - ]; +async function askPaths(context: $TSContext, answers: $TSObject, currentPath?: ApigwPath): Promise { + const existingFunctions = functionsExist(); - /* - Removing this option for now in favor of multi-env support - - NOT CRITICAL - if (existingLambdaArns) { - choices.push({ - name: 'Use a Lambda function already deployed on AWS', - value: 'arn', - }); - } - */ + let defaultFunctionType = 'newFunction'; + const defaultChoice = { + name: 'Create a new Lambda function', + value: defaultFunctionType, + }; + const choices = [defaultChoice]; if (existingFunctions) { choices.push({ @@ -453,28 +362,19 @@ async function askPaths(context, answers, currentPath) { }); } - let defaultFunctionType = 'newFunction'; - if (currentPath) { - defaultFunctionType = currentPath.lambdaArn ? 'arn' : 'projectFunction'; - } - - const paths = [...answers.paths]; + const paths = answers.paths; - let addAnotherPath; + let addAnotherPath: boolean; do { - let pathName; - let isPathValid; + let pathName: string; + let isPathValid: boolean; do { - const pathAnswer = await inquirer.prompt({ - name: 'name', - type: 'input', - message: 'Provide a path (e.g., /book/{isbn}):', - default: currentPath ? currentPath.name : '/items', - validate: value => validatePathName(value), + pathName = await prompter.input('Provide a path (e.g., /book/{isbn}):', { + initial: currentPath ? currentPath.name : '/items', + validate: validatePathName, }); - pathName = pathAnswer.name; - const overlapCheckResult = checkForPathOverlap(pathName, paths); + 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; @@ -483,81 +383,66 @@ async function askPaths(context, answers, currentPath) { // 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 inquirer.prompt({ - name: 'isOverlappingPathOK', - type: 'confirm', - message: `The path ${lowerOrderPath} overlaps with ${higherOrderPath}. Users authorized to access ${higherOrderPath} will also have access to ${lowerOrderPath}. Are you sure you want to continue?`, - default: false, - }) - ).isOverlappingPathOK; + + 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 lambdaAnswer = await inquirer.prompt({ - name: 'functionType', - type: 'list', - message: 'Choose a Lambda source', - choices, - default: defaultFunctionType, - }); + const functionType = await prompter.pick<'one', string>('Choose a Lambda source', choices, { initial: choices.indexOf(defaultChoice) }); - // TODO: add path validation like awsmobile-cli does let path = { name: pathName }; let lambda; do { - lambda = await askLambdaSource(context, lambdaAnswer.functionType, path.name, currentPath); + lambda = await askLambdaSource(context, functionType, pathName, currentPath); } while (!lambda); - const privacy = await askPrivacy(context, answers, currentPath); - path = { ...path, ...lambda, privacy }; - paths.push(path); + const permissions = await askPermissions(context, answers, currentPath); + path = { ...path, ...lambda, permissions }; + paths[pathName] = path; if (currentPath) { break; } - addAnotherPath = ( - await inquirer.prompt({ - name: 'anotherPath', - type: 'confirm', - message: 'Do you want to add another path?', - default: false, - }) - ).anotherPath; + addAnotherPath = await prompter.confirmContinue('Do you want to add another path?'); } while (addAnotherPath); - const { dependsOn, functionArns } = await findDependsOn(paths, context); + const { dependsOn, functionArns } = await findDependsOn(paths); - return { paths, dependsOn, functionArns }; + return { paths, dependsOn, resourceName: answers.resourceName, functionArns }; } -async function findDependsOn(paths, context) { +async function findDependsOn(paths: $TSObject[]) { // go thru all paths and add lambdaFunctions to dependsOn and functionArns uniquely const dependsOn = []; const functionArns = []; - for (let i = 0; i < paths.length; i += 1) { - if (paths[i].lambdaFunction && !paths[i].lambdaArn) { - if (!dependsOn.find(func => func.resourceName === paths[i].lambdaFunction)) { + 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: paths[i].lambdaFunction, + resourceName: path.lambdaFunction, attributes: ['Name', 'Arn'], }); } } - if (!functionArns.find(func => func.lambdaFunction === paths[i].lambdaFunction)) { + + if (!functionArns.find(func => func.lambdaFunction === path.lambdaFunction)) { functionArns.push({ - lambdaFunction: paths[i].lambdaFunction, - lambdaArn: paths[i].lambdaArn, + lambdaFunction: path.lambdaFunction, + lambdaArn: path.lambdaArn, }); } - if (paths[i].privacy && paths[i].privacy.userPoolGroups) { - const userPoolGroups = Object.keys(paths[i].privacy.userPoolGroups); + + if (path?.permissions?.groups) { + const userPoolGroups = Object.keys(path.permissions.groups); if (userPoolGroups.length > 0) { // Get auth resource name - const authResourceName = await getAuthResourceName(context); + const authResourceName = getAuthResourceName(); if (!dependsOn.find(resource => resource.resourceName === authResourceName)) { dependsOn.push({ @@ -582,26 +467,29 @@ async function findDependsOn(paths, context) { return { dependsOn, functionArns }; } -async function getAuthResourceName(context) { - let authResources = (await context.amplify.getResourceStatus('auth')).allResources; - authResources = authResources.filter(resource => resource.service === 'Cognito'); +function getAuthResourceName(): string { + const meta = stateManager.getMeta(); + const authResources = (Object.entries(meta?.auth) || []).filter( + ([_, resource]: [key: string, resource: $TSObject]) => resource.service === AmplifySupportedService.COGNITO, + ); if (authResources.length === 0) { - throw new Error('No auth resource found. Please add it using amplify add auth'); + throw new Error('No auth resource found. Add it using amplify add auth'); } - const authResourceName = authResources[0].resourceName; + const [authResourceName] = authResources[0]; return authResourceName; } -function functionsExist(context) { - if (!context.amplify.getProjectDetails().amplifyMeta.function) { +function functionsExist() { + const meta = stateManager.getMeta(); + if (!meta.function) { return false; } - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; + const functionResources = meta.function; const lambdaFunctions = []; Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { + if (functionResources[resourceName].service === AmplifySupportedService.LAMBDA) { lambdaFunctions.push(resourceName); } }); @@ -613,26 +501,20 @@ function functionsExist(context) { return true; } -async function askLambdaSource(context, functionType, path, currentPath) { +async function askLambdaSource(context: $TSContext, functionType: string, path: string, currentPath?: ApigwPath) { switch (functionType) { case 'arn': return askLambdaArn(context, currentPath); case 'projectFunction': - return askLambdaFromProject(context, currentPath); + return askLambdaFromProject(currentPath); case 'newFunction': - return newLambdaFunction(context, path); + return newLambdaFunction(context as $TSAny, path); default: throw new Error('Type not supported'); } } -async function newLambdaFunction(context, path) { - context.api = { - path, - // ExpressJS represents path parameters as /:param instead of /{param}. This expression performs this replacement. - expressPath: formatCFNPathParamsForExpressJs(path), - functionTemplate: 'serverless', - }; +async function newLambdaFunction(context: $TSContext, path: string) { let params = { functionTemplate: { parameters: { @@ -642,39 +524,35 @@ async function newLambdaFunction(context, path) { }, }; - const resourceName = await context.amplify.invokePluginMethod(context, 'function', undefined, 'add', [ + const resourceName = await context.amplify.invokePluginMethod(context, AmplifyCategories.FUNCTION, undefined, 'add', [ context, 'awscloudformation', - FunctionServiceNameLambdaFunction, + AmplifySupportedService.LAMBDA, params, ]); - context.print.success('Succesfully added the Lambda function locally'); + printer.success('Succesfully added the Lambda function locally'); return { lambdaFunction: resourceName }; } -async function askLambdaFromProject(context, currentPath) { - const functionResources = context.amplify.getProjectDetails().amplifyMeta.function; +async function askLambdaFromProject(currentPath?: ApigwPath) { + const meta = stateManager.getMeta(); const lambdaFunctions = []; - Object.keys(functionResources).forEach(resourceName => { - if (functionResources[resourceName].service === FunctionServiceNameLambdaFunction) { + Object.keys(meta?.function || {}).forEach(resourceName => { + if (meta.function[resourceName].service === AmplifySupportedService.LAMBDA) { lambdaFunctions.push(resourceName); } }); - const answer = await inquirer.prompt({ - name: 'lambdaFunction', - type: 'list', - message: 'Choose the Lambda function to invoke by this path', - choices: lambdaFunctions, - default: currentPath ? currentPath.lambdaFunction : lambdaFunctions[0], + 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: answer.lambdaFunction }; + return { lambdaFunction }; } -async function askLambdaArn(context, currentPath) { +async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { const lambdaFunctions = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getLambdaFunctions'); const lambdaOptions = lambdaFunctions.map(lambdaFunction => ({ @@ -683,16 +561,16 @@ async function askLambdaArn(context, currentPath) { })); if (lambdaOptions.length === 0) { - context.print.error('You do not have any Lambda functions configured for the selected Region'); + printer.error('You do not have any Lambda functions configured for the selected Region'); return null; } const lambdaCloudOptionQuestion = { type: 'list', name: 'lambdaChoice', - message: 'Please select a Lambda function', + message: 'Select a Lambda function', choices: lambdaOptions, - default: currentPath && currentPath.lambdaArn ? `${currentPath.lambdaArn}` : `${lambdaOptions[0].value}`, + default: currentPath && currentPath.lambdaFunction ? `${currentPath.lambdaFunction}` : `${lambdaOptions[0].value}`, }; let lambdaOption; @@ -700,7 +578,7 @@ async function askLambdaArn(context, currentPath) { try { lambdaOption = await inquirer.prompt([lambdaCloudOptionQuestion]); } catch (err) { - context.print.error('Select a Lambda Function'); + printer.error('Select a Lambda Function'); } } @@ -712,75 +590,31 @@ async function askLambdaArn(context, currentPath) { }; } -export async function migrate(context, projectPath, resourceName) { - const { amplify } = context; - - const targetDir = amplify.pathManager.getBackendDirPath(); - const resourceDirPath = path.join(targetDir, category, resourceName); - const parametersFilePath = path.join(resourceDirPath, parametersFileName); - let parameters; - try { - parameters = amplify.readJsonFile(parametersFilePath); - } catch (e) { - context.print.error(`Error reading api-params.json file for ${resourceName} resource`); - throw e; - } - const copyJobs = [ - { - dir: path.join(rootAssetDir, 'cloudformation-templates'), - template: 'apigw-cloudformation-template-default.json.ejs', - target: `${targetDir}/${category}/${resourceName}/${resourceName}-cloudformation-template.json`, - }, - ]; - - // copy over the files - await context.amplify.copyBatch(context, copyJobs, parameters, true, false); - - // Create parameters.json file - const cfnParameters = { - authRoleName: { - Ref: 'AuthRoleName', - }, - unauthRoleName: { - Ref: 'UnauthRoleName', - }, - }; - - const cfnParametersFilePath = path.join(resourceDirPath, cfnParametersFilename); - const jsonString = JSON.stringify(cfnParameters, null, 4); - fs.writeFileSync(cfnParametersFilePath, jsonString, 'utf8'); +export async function migrate(context: $TSContext, projectPath: string, resourceName: string) { + const apigwInputState = new ApigwInputState(context, resourceName); + return apigwInputState.migrateApigwResource(resourceName); } -function convertToCRUD(privacy) { - if (privacy === 'r') { - privacy = ['/GET']; - } else if (privacy === 'rw') { - privacy = ['/POST', '/GET', '/PUT', '/PATCH', '/DELETE']; - } - - return privacy; -} - -export function getIAMPolicies(resourceName, crudOptions) { +export function getIAMPolicies(resourceName: string, crudOptions: string[]) { let policy = {}; const actions = []; crudOptions.forEach(crudOption => { switch (crudOption) { - case 'create': + case CrudOperation.CREATE: actions.push('apigateway:POST', 'apigateway:PUT'); break; - case 'update': + case CrudOperation.UPDATE: actions.push('apigateway:PATCH'); break; - case 'read': + case CrudOperation.READ: actions.push('apigateway:GET', 'apigateway:HEAD', 'apigateway:OPTIONS'); break; - case 'delete': + case CrudOperation.DELETE: actions.push('apigateway:DELETE'); break; default: - console.log(`${crudOption} not supported`); + printer.info(`${crudOption} not supported`); } }); @@ -812,7 +646,7 @@ export function getIAMPolicies(resourceName, crudOptions) { return { policy, attributes }; } -export const openConsole = async (context: $TSContext) => { +export const openConsole = async (context?: $TSContext) => { const amplifyMeta = stateManager.getMeta(); const categoryAmplifyMeta = amplifyMeta[category]; const { Region } = amplifyMeta.providers.awscloudformation; @@ -827,16 +661,8 @@ export const openConsole = async (context: $TSContext) => { if (restApis) { let url; - let selectedApi = restApis[0]; - if (restApis.length > 1) { - ({ selectedApi } = await inquirer.prompt({ - type: 'list', - name: 'selectedApi', - choices: restApis, - message: 'Please select the API', - })); - } + const selectedApi = await prompter.pick<'one', string>('Select the API', restApis); const selectedResource = categoryAmplifyMeta[selectedApi]; if (selectedResource.service === serviceName) { @@ -853,34 +679,29 @@ export const openConsole = async (context: $TSContext) => { 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, - }, - ], - }); + 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 { - context.print.error('Option not available'); + printer.error('Option not available'); return; } } open(url, { wait: false }); } else { - context.print.error('There are no REST APIs pushed to the cloud'); + 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-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-rds-walkthrough.ts index 1d0a92fb11..10d0b2eac0 100644 --- 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 @@ -1,21 +1,22 @@ -import inquirer from 'inquirer'; +import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; import chalk from 'chalk'; -import ora from 'ora'; import { DataApiParams } from 'graphql-relational-schema-transformer'; -import { ResourceDoesNotExistError, ResourceCredentialsNotFoundError, exitOnNextTick, $TSContext, $TSObject } from 'amplify-cli-core'; +import inquirer from 'inquirer'; +import ora from 'ora'; const spinner = ora(''); const category = 'api'; const providerName = 'awscloudformation'; -export async function serviceWalkthrough(context: $TSContext, defaultValuesFilename: string, datasourceMetadata: $TSObject) { +export async function serviceWalkthrough(context: $TSContext, datasourceMetadata: $TSObject) { 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -24,9 +25,9 @@ export async function serviceWalkthrough(context: $TSContext, defaultValuesFilen let appSyncApi: string; const apis = Object.keys(amplifyMeta[category]); - for (let i = 0; i < apis.length; i += 1) { - if (amplifyMeta[category][apis[i]].service === 'AppSync') { - appSyncApi = apis[i]; + for (const api of apis) { + if (amplifyMeta[category][api].service === 'AppSync') { + appSyncApi = api; break; } } @@ -35,7 +36,7 @@ export async function serviceWalkthrough(context: $TSContext, defaultValuesFilen 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } @@ -86,7 +87,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { if (serverlessClusters.length === 0) { const errMessage = 'No properly configured Aurora Serverless clusters found.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -110,7 +111,7 @@ async function selectCluster(context: $TSContext, inputs, AWS) { // Pick first and only value const firstCluster = Array.from(clusters.values())[0]; - context.print.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Cluster was found: '${firstCluster.DBClusterIdentifier}' was automatically selected.`); return { selectedClusterArn: firstCluster.DBClusterArn, @@ -148,7 +149,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, if (secretsForCluster.length === 0) { const errMessage = 'No RDS access credentials found in the AWS Secrect Manager.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceCredentialsNotFoundError(errMessage)); @@ -169,7 +170,7 @@ async function getSecretStoreArn(context: $TSContext, inputs, clusterResourceId, // Pick first and only value selectedSecretArn = Array.from(secrets.values())[0]; - context.print.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Secret was found for the cluster: '${selectedSecretArn}' was automatically selected.`); } return selectedSecretArn; @@ -206,14 +207,14 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn const msg = `Ensure that '${secretArn}' contains your database credentials. ` + 'Please note that Aurora Serverless does not support IAM database authentication.'; - context.print.error(msg); + printer.error(msg); } } if (databaseList.length === 0) { const errMessage = 'No database found in the selected cluster.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); @@ -224,7 +225,7 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn return await promptWalkthroughQuestion(inputs, 3, databaseList); } - context.print.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); + printer.info(`${chalk.green('✔')} Only one Database was found: '${databaseList[0]}' was automatically selected.`); return databaseList[0]; } 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 index 52de5b0701..cc9f30f0e5 100644 --- 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 @@ -1,30 +1,34 @@ -import { ListQuestion, CheckboxQuestion, ListChoiceOptions } from 'inquirer'; -import { dataStoreLearnMore } from '../sync-conflict-handler-assets/syncAssets'; -import inquirer from 'inquirer'; -import fs from 'fs-extra'; -import path from 'path'; -import { rootAssetDir, provider } from '../aws-constants'; -import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; -import { category } from '../../../category-constants'; -import { UpdateApiRequest } from '../../../../../amplify-headless-interface/lib/interface/api/update'; -import { authConfigToAppSyncAuthType } from '../utils/auth-config-to-app-sync-auth-type-bi-di-mapper'; -import { resolverConfigToConflictResolution } from '../utils/resolver-config-to-conflict-resolution-bi-di-mapper'; -import _ from 'lodash'; -import chalk from 'chalk'; -import uuid from 'uuid'; -import { getAppSyncAuthConfig, checkIfAuthExists, authConfigHasApiKey } from '../utils/amplify-meta-utils'; +import { Duration, Expiration } from '@aws-cdk/core'; import { - ResourceAlreadyExistsError, - ResourceDoesNotExistError, - UnknownResourceTypeError, + $TSContext, + $TSObject, exitOnNextTick, - stateManager, FeatureFlags, - $TSContext, open, + pathManager, + ResourceAlreadyExistsError, + ResourceDoesNotExistError, + stateManager, + UnknownResourceTypeError, } from 'amplify-cli-core'; -import { Duration, Expiration } from '@aws-cdk/core'; +import { UpdateApiRequest } from 'amplify-headless-interface'; +import { printer } from '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 * as path from 'path'; +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'; @@ -151,11 +155,11 @@ export const openConsole = async (context: $TSContext) => { url = `https://console.aws.amazon.com/appsync/home?region=${Region}#/${GraphQLAPIIdOutput}/v1/queries`; - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const { isAdminApp, region } = await providerPlugin.isAmplifyAdminApp(appId); if (isAdminApp) { if (region !== Region) { - context.print.warning(`Region mismatch: Amplify service returned '${region}', but found '${Region}' in amplify-meta.json.`); + 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; @@ -190,26 +194,24 @@ export const openConsole = async (context: $TSContext) => { } else if (selectedConsole === codePipeline) { url = `https://${Region}.console.aws.amazon.com/codesuite/codepipeline/pipelines/${PipelineName}/view`; } else { - context.print.error('Option not available'); + printer.error('Option not available'); return; } } open(url, { wait: false }); } else { - context.print.error('AppSync API is not pushed in the cloud.'); + printer.error('AppSync API is not pushed in the cloud.'); } }; -const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { +const serviceApiInputWalkthrough = async (context: $TSContext, serviceMetadata) => { let continuePrompt = false; let authConfig; let defaultAuthType; let resolverConfig; const { amplify } = context; const { inputs } = serviceMetadata; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = require(defaultValuesSrc); const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); let resourceAnswers = {}; @@ -336,7 +338,7 @@ const serviceApiInputWalkthrough = async (context: $TSContext, defaultValuesFile }; }; -const updateApiInputWalkthrough = async (context, project, resolverConfig, modelTypes) => { +const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject, resolverConfig, modelTypes) => { let authConfig; let defaultAuthType; const updateChoices = [ @@ -388,15 +390,16 @@ const updateApiInputWalkthrough = async (context, project, resolverConfig, model }; }; -export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilename, serviceMetadata) => { - const resourceName = resourceAlreadyExists(context); - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); +export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $TSObject) => { + const resourceName = resourceAlreadyExists(); + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const transformerVersion = providerPlugin.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.'; - context.print.warning(errMessage); + printer.warn(errMessage); await context.usageData.emitError(new ResourceAlreadyExistsError(errMessage)); exitOnNextTick(0); } @@ -404,7 +407,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen const { amplify } = context; const { inputs } = serviceMetadata; - const basicInfoAnswers = await serviceApiInputWalkthrough(context, defaultValuesFilename, serviceMetadata); + const basicInfoAnswers = await serviceApiInputWalkthrough(context, serviceMetadata); let schemaContent = ''; let askToEdit = true; @@ -431,7 +434,7 @@ export const serviceWalkthrough = async (context: $TSContext, defaultValuesFilen }; }; -export const updateWalkthrough = async (context): Promise => { +export const updateWalkthrough = async (context: $TSContext): Promise => { const { allResources } = await context.amplify.getResourceStatus(); let resourceDir; let resourceName; @@ -450,15 +453,20 @@ export const updateWalkthrough = async (context): Promise => { ); } ({ resourceName } = resource); - const backEndDir = context.amplify.pathManager.getBackendDirPath(); - resourceDir = path.normalize(path.join(backEndDir, category, resourceName)); + 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.'; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); } + // migrate API project + if (!(await checkAppsyncApiResourceMigration(context, resourceName, true))) { + printer.error('Update operations only work on migrated projects. Run "amplify update api" and opt for migration.'); + exitOnNextTick(0); + } + // Get models const project = await readProjectConfiguration(resourceDir); let resolverConfig = project.config.ResolverConfig; @@ -493,7 +501,7 @@ export const updateWalkthrough = async (context): Promise => { }; }; -async function displayApiInformation(context, resource, project) { +async function displayApiInformation(context: $TSContext, resource: $TSObject, project: $TSObject) { let authModes: string[] = []; authModes.push( `- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`, @@ -502,35 +510,35 @@ async function displayApiInformation(context, resource, project) { authModes.push(`- ${await displayAuthMode(context, resource, authMode.authenticationType)}`); }); - context.print.info(''); + printer.info(''); - context.print.success('General information'); - context.print.info('- Name: '.concat(resource.resourceName)); + printer.info('General information'); + printer.info('- Name: '.concat(resource.resourceName)); if (resource?.output?.GraphQLAPIEndpointOutput) { - context.print.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); + printer.info(`- API endpoint: ${resource?.output?.GraphQLAPIEndpointOutput}`); } - context.print.info(''); + printer.info(''); - context.print.success('Authorization modes'); - authModes.forEach(authMode => context.print.info(authMode)); - context.print.info(''); + printer.info('Authorization modes'); + authModes.forEach(authMode => printer.info(authMode)); + printer.info(''); - context.print.success('Conflict detection (required for DataStore)'); + printer.info('Conflict detection (required for DataStore)'); if (project.config && !_.isEmpty(project.config.ResolverConfig)) { - context.print.info( + printer.info( `- Conflict resolution strategy: ${ conflictResolutionHanlderChoices.find(choice => choice.value === project.config.ResolverConfig.project.ConflictHandler).name }`, ); } else { - context.print.info('- Disabled'); + printer.info('- Disabled'); } - context.print.info(''); + printer.info(''); } -async function displayAuthMode(context, resource, authMode) { - if (authMode == 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { +async function displayAuthMode(context: $TSContext, resource: $TSObject, authMode: string) { + if (authMode === 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getAppSyncApiKeys', { apiId: resource.output.GraphQLAPIIdOutput, }); @@ -546,13 +554,13 @@ async function displayAuthMode(context, resource, authMode) { return authProviderChoices.find(choice => choice.value === authMode).name; } -async function askAdditionalQuestions(context, authConfig, defaultAuthType, modelTypes?) { +async function askAdditionalQuestions(context: $TSContext, authConfig, defaultAuthType, modelTypes?) { authConfig = await askAdditionalAuthQuestions(context, authConfig, defaultAuthType); return { authConfig }; } -async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) { - let resolverConfigResponse: any = {}; +async function askResolverConflictQuestion(context: $TSContext, resolverConfig, modelTypes?) { + let resolverConfigResponse: $TSObject = {}; if (await context.prompt.confirm('Enable conflict detection?', !resolverConfig?.project)) { resolverConfigResponse = await askResolverConflictHandlerQuestion(context, modelTypes); @@ -561,8 +569,8 @@ async function askResolverConflictQuestion(context, resolverConfig, modelTypes?) return resolverConfigResponse; } -async function askResolverConflictHandlerQuestion(context, modelTypes?) { - let resolverConfig: any = {}; +async function askResolverConflictHandlerQuestion(context: $TSContext, modelTypes?) { + let resolverConfig: $TSObject = {}; const askConflictResolutionStrategy = async msg => { let conflictResolutionStrategy; @@ -580,13 +588,13 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { ({ conflictResolutionStrategy } = await inquirer.prompt([conflictResolutionQuestion])); } while (conflictResolutionStrategy === 'Learn More'); - let syncConfig: any = { + let syncConfig: $TSObject = { ConflictHandler: conflictResolutionStrategy, ConflictDetection: 'VERSION', }; if (conflictResolutionStrategy === 'LAMBDA') { - const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(context); + const { newFunction, lambdaFunctionName } = await askSyncFunctionQuestion(); syncConfig.LambdaConflictHandler = { name: lambdaFunctionName, new: newFunction, @@ -613,10 +621,8 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { if (selectedModelTypes.length > 0) { resolverConfig.models = {}; - for (let i = 0; i < selectedModelTypes.length; i += 1) { - resolverConfig.models[selectedModelTypes[i]] = await askConflictResolutionStrategy( - `Select the resolution strategy for ${selectedModelTypes[i]} model`, - ); + for (const modelType of selectedModelTypes) { + resolverConfig.models[modelType] = await askConflictResolutionStrategy(`Select the resolution strategy for ${modelType} model`); } } } @@ -625,7 +631,7 @@ async function askResolverConflictHandlerQuestion(context, modelTypes?) { return resolverConfig; } -async function askSyncFunctionQuestion(context) { +async function askSyncFunctionQuestion() { const syncLambdaQuestion = { type: 'list', name: 'syncLambdaAnswer', @@ -660,8 +666,8 @@ async function askSyncFunctionQuestion(context) { return { newFunction, lambdaFunctionName }; } -async function addLambdaAuthorizerChoice(context) { - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[provider]); +async function addLambdaAuthorizerChoice(context: $TSContext) { + const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); const transformerVersion = providerPlugin.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ @@ -671,9 +677,9 @@ async function addLambdaAuthorizerChoice(context) { } } -async function askDefaultAuthQuestion(context) { +async function askDefaultAuthQuestion(context: $TSContext) { await addLambdaAuthorizerChoice(context); - const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); + const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); const currentDefaultAuth = currentAuthConfig && currentAuthConfig.defaultAuthentication ? currentAuthConfig.defaultAuthentication.authenticationType : undefined; @@ -698,8 +704,8 @@ async function askDefaultAuthQuestion(context) { }; } -export async function askAdditionalAuthQuestions(context, authConfig, defaultAuthType) { - const currentAuthConfig = getAppSyncAuthConfig(context.amplify.getProjectMeta()); +export async function askAdditionalAuthQuestions(context: $TSContext, authConfig: $TSObject, defaultAuthType) { + const currentAuthConfig = getAppSyncAuthConfig(stateManager.getMeta()); authConfig.additionalAuthenticationProviders = []; if (await context.prompt.confirm('Configure additional auth types?')) { // Get additional auth configured @@ -720,9 +726,7 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut const additionalProvidersAnswer = await inquirer.prompt([additionalProvidersQuestion]); - for (let i = 0; i < additionalProvidersAnswer.authType.length; i += 1) { - const authProvider = additionalProvidersAnswer.authType[i]; - + for (const authProvider of additionalProvidersAnswer.authType) { const config = await askAuthQuestions( authProvider, context, @@ -740,10 +744,10 @@ export async function askAdditionalAuthQuestions(context, authConfig, defaultAut return authConfig; } -export async function askAuthQuestions(authType, context, printLeadText = false, authSettings) { +export async function askAuthQuestions(authType: string, context: $TSContext, printLeadText = false, authSettings) { if (authType === 'AMAZON_COGNITO_USER_POOLS') { if (printLeadText) { - context.print.info('Cognito UserPool configuration'); + printer.info('Cognito UserPool configuration'); } const userPoolConfig = await askUserPoolQuestions(context); @@ -753,7 +757,7 @@ export async function askAuthQuestions(authType, context, printLeadText = false, if (authType === 'API_KEY') { if (printLeadText) { - context.print.info('API key configuration'); + printer.info('API key configuration'); } const apiKeyConfig = await askApiKeyQuestions(authSettings); @@ -769,7 +773,7 @@ export async function askAuthQuestions(authType, context, printLeadText = false, if (authType === 'OPENID_CONNECT') { if (printLeadText) { - context.print.info('OpenID Connect configuration'); + printer.info('OpenID Connect configuration'); } const openIDConnectConfig = await askOpenIDConnectQuestions(authSettings); @@ -788,17 +792,17 @@ export async function askAuthQuestions(authType, context, printLeadText = false, } const errMessage = `Unknown authType: ${authType}`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new UnknownResourceTypeError(errMessage)); exitOnNextTick(1); } -async function askUserPoolQuestions(context) { - let authResourceName = checkIfAuthExists(context); +async function askUserPoolQuestions(context: $TSContext) { + let authResourceName = checkIfAuthExists(); if (!authResourceName) { authResourceName = await context.amplify.invokePluginMethod(context, 'auth', undefined, 'add', [context, true]); } else { - context.print.info('Use a Cognito user pool configured as a part of this project.'); + printer.info('Use a Cognito user pool configured as a part of this project.'); } // Added resources are prefixed with auth @@ -812,7 +816,7 @@ async function askUserPoolQuestions(context) { }; } -export async function askApiKeyQuestions(authSettings = undefined) { +export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { let defaultValues = { apiKeyExpirationDays: 7, description: undefined, @@ -853,7 +857,7 @@ export async function askApiKeyQuestions(authSettings = undefined) { }; } -async function askOpenIDConnectQuestions(authSettings) { +async function askOpenIDConnectQuestions(authSettings: $TSObject) { let defaultValues = { authTTL: undefined, clientId: undefined, @@ -907,7 +911,7 @@ async function askOpenIDConnectQuestions(authSettings) { }; } -async function validateDays(input) { +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) { @@ -917,7 +921,7 @@ async function validateDays(input) { return true; } -function validateIssuerUrl(input) { +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, @@ -930,7 +934,7 @@ function validateIssuerUrl(input) { return true; } -function validateTTL(input) { +function validateTTL(input: string) { const isValid = /^\d+$/.test(input); if (!isValid) { @@ -940,32 +944,32 @@ function validateTTL(input) { return true; } -function resourceAlreadyExists(context) { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); +function resourceAlreadyExists() { + const meta = stateManager.getMeta(); let resourceName; - if (amplifyMeta[category]) { - const categoryResources = amplifyMeta[category]; - Object.keys(categoryResources).forEach(resource => { + 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 => { +export const migrate = async (context: $TSContext) => { await context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true, migrate: true, }); }; -export const getIAMPolicies = (resourceName: string, operations: string[], context: any) => { - let policy: any = {}; +export const getIAMPolicies = (resourceName: string, operations: string[]) => { + let policy: $TSObject = {}; const resources = []; const actions = []; if (!FeatureFlags.getBoolean('appSync.generateGraphQLPermissions')) { @@ -985,7 +989,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[], conte actions.push('appsync:Delete*'); break; default: - console.log(`${crudOption} not supported`); + printer.info(`${crudOption} not supported`); } }); resources.push(buildPolicyResource(resourceName, null)); @@ -1001,7 +1005,7 @@ export const getIAMPolicies = (resourceName: string, operations: string[], conte }; const attributes = ['GraphQLAPIIdOutput', 'GraphQLAPIEndpointOutput']; - if (authConfigHasApiKey(getAppSyncAuthConfig(context.amplify.getProjectMeta()))) { + if (authConfigHasApiKey(getAppSyncAuthConfig(stateManager.getMeta()))) { attributes.push('GraphQLAPIKeyOutput'); } @@ -1074,7 +1078,7 @@ async function askLambdaQuestion(context) { name: 'ttlSeconds', message: 'How long should the authorization response be cached in seconds?', validate: validateTTL, - default: 300, + default: '300', }); const lambdaAuthorizerConfig = { 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 index 9b38fb744f..5ba0df021b 100644 --- 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 @@ -1,8 +1,10 @@ -import { exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, exitOnNextTick, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { printer } from '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'; @@ -44,11 +46,8 @@ export type ServiceConfiguration = { gitHubInfo?: GitHubSourceActionInfo; }; -export async function serviceWalkthrough(context, defaultValuesFilename, apiType: API_TYPE): Promise> { - const { amplify } = context; - const defaultValuesSrc = `${__dirname}/../default-values/${defaultValuesFilename}`; - const { getAllDefaults } = await import(defaultValuesSrc); - const allDefaultValues = getAllDefaults(amplify.getProjectDetails()); +export async function serviceWalkthrough(context: $TSContext, apiType: API_TYPE): Promise> { + const allDefaultValues = getAllDefaults(); const resourceName = await askResourceName(context, allDefaultValues); @@ -57,7 +56,7 @@ export async function serviceWalkthrough(context, defaultValuesFilename, apiType return { resourceName, ...containerInfo }; } -async function askResourceName(context, allDefaultValues) { +async function askResourceName(context: $TSContext, allDefaultValues: $TSObject) { const { amplify } = context; const { resourceName } = await inquirer.prompt([ @@ -80,7 +79,7 @@ async function askResourceName(context, allDefaultValues) { return resourceName; } -async function askContainerSource(context, resourceName: string, apiType: API_TYPE): Promise> { +async function askContainerSource(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { return newContainer(context, resourceName, apiType); } @@ -89,7 +88,7 @@ export enum IMAGE_SOURCE_TYPE { CUSTOM = 'CUSTOM', } -async function newContainer(context, resourceName: string, apiType: API_TYPE): Promise> { +async function newContainer(context: $TSContext, resourceName: string, apiType: API_TYPE): Promise> { let imageSource: { type: IMAGE_SOURCE_TYPE; template?: string }; let choices = []; @@ -171,8 +170,8 @@ async function newContainer(context, resourceName: string, apiType: API_TYPE): P let gitHubToken: string; if (deploymentMechanismQuestion.deploymentMechanism === DEPLOYMENT_MECHANISM.INDENPENDENTLY_MANAGED) { - context.print.info('We need a Github Personal Access Token to automatically build & deploy your Fargate task on every Github commit.'); - context.print.info( + 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', ); @@ -234,7 +233,7 @@ async function newContainer(context, resourceName: string, apiType: API_TYPE): P }; } -export async function updateWalkthrough(context, defaultValuesFilename, apiType: API_TYPE) { +export async function updateWalkthrough(context: $TSContext, apiType: API_TYPE) { const { allResources } = await context.amplify.getResourceStatus(); const resources = allResources @@ -247,7 +246,7 @@ export async function updateWalkthrough(context, defaultValuesFilename, apiType: // 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`; - context.print.error(errMessage); + printer.error(errMessage); await context.usageData.emitError(new ResourceDoesNotExistError(errMessage)); exitOnNextTick(0); return; @@ -302,7 +301,7 @@ export async function updateWalkthrough(context, defaultValuesFilename, apiType: const hasAccessableResources = ['storage', 'function'].some(categoryName => { return Object.keys(meta[categoryName] ?? {}).length > 0; }); - let rolePermissions: any = {}; + let rolePermissions: $TSAny = {}; if ( hasAccessableResources && (await context.amplify.confirmPrompt('Do you want to access other resources in this project from your api?')) 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 index d920a8d9c9..e3385279de 100644 --- 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 @@ -1,6 +1,7 @@ +import { $TSAny, $TSMeta, $TSObject, AmplifyCategories, AmplifySupportedService, stateManager } from 'amplify-cli-core'; import _ from 'lodash'; -export const authConfigHasApiKey = authConfig => { +export const authConfigHasApiKey = (authConfig?: $TSAny) => { if (!authConfig) { return false; } @@ -13,12 +14,11 @@ export const authConfigHasApiKey = authConfig => { ); }; -export const checkIfAuthExists = context => { - const { amplify } = context; - const { amplifyMeta } = amplify.getProjectDetails(); +export const checkIfAuthExists = () => { + const amplifyMeta = stateManager.getMeta(); let authResourceName; - const authServiceName = 'Cognito'; - const authCategoryName = 'auth'; + const authServiceName = AmplifySupportedService.COGNITO; + const authCategoryName = AmplifyCategories.AUTH; if (amplifyMeta[authCategoryName] && Object.keys(amplifyMeta[authCategoryName]).length > 0) { const categoryResources = amplifyMeta[authCategoryName]; @@ -34,15 +34,15 @@ export const checkIfAuthExists = context => { // some utility functions to extract the AppSync API name and config from amplify-meta -export const getAppSyncAuthConfig = projectMeta => { +export const getAppSyncAuthConfig = (projectMeta: $TSMeta) => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { - const value = entry[1] as any; + const value = entry[1] as $TSAny; return value && value.output ? value.output.authConfig : {}; } }; -export const getAppSyncResourceName = (projectMeta: any): string | undefined => { +export const getAppSyncResourceName = (projectMeta: $TSMeta): string | undefined => { const entry = getAppSyncAmplifyMetaEntry(projectMeta); if (entry) { return entry[0]; @@ -51,6 +51,8 @@ export const getAppSyncResourceName = (projectMeta: any): string | undefined => // project meta is the contents of amplify-meta.json // typically retreived using context.amplify.getProjectMeta() -const getAppSyncAmplifyMetaEntry = (projectMeta: any) => { - return Object.entries(projectMeta.api || {}).find(([, value]) => (value as any).service === 'AppSync'); +const getAppSyncAmplifyMetaEntry = (projectMeta: $TSMeta) => { + return Object.entries(projectMeta[AmplifyCategories.API] || {}).find( + ([, value]) => (value as $TSObject).service === AmplifySupportedService.APPSYNC, + ); }; 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 new file mode 100644 index 0000000000..576956442d --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/check-appsync-api-migration.ts @@ -0,0 +1,19 @@ +import { $TSContext, AmplifyCategories, getMigrateResourceMessageForOverride } from 'amplify-cli-core'; +import { printer, prompter } from '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(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 index dbce76b2fa..05de9ccea5 100644 --- 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 @@ -2,14 +2,14 @@ import { Octokit } from '@octokit/rest'; import * as fs from 'fs-extra'; import inquirer from 'inquirer'; import * as path from 'path'; -import uuid from 'uuid'; +import { v4 as uuid } from 'uuid'; 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 { JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; +import { $TSAny, $TSContext, JSONUtilities, pathManager, readCFNTemplate } from 'amplify-cli-core'; import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; import { setExistingSecretArns } from './containers/set-existing-secret-arns'; import { category } from '../../../category-constants'; @@ -28,9 +28,9 @@ export type ApiResource = { restrictAccess: boolean; dependsOn: ResourceDependency[]; environmentMap: Record; - categoryPolicies: any[]; - mutableParametersState: any; - output?: Record; + categoryPolicies: $TSAny[]; + mutableParametersState: $TSAny; + output?: Record; apiType?: API_TYPE; exposedContainer?: { name: string; port: number }; }; @@ -46,7 +46,7 @@ type ContainerArtifactsMetadata = { }; export async function generateContainersArtifacts( - context: any, + context: $TSContext, resource: ApiResource, askForExposedContainer: boolean = false, ): Promise { @@ -116,7 +116,12 @@ export async function generateContainersArtifacts( }; } -export async function processDockerConfig(context: any, resource: ApiResource, srcPath: string, askForExposedContainer: boolean = false) { +export async function processDockerConfig( + context: $TSContext, + resource: ApiResource, + srcPath: string, + askForExposedContainer: boolean = false, +) { const { providers: { [cloudformationProviderName]: provider }, } = context.amplify.getProjectMeta(); @@ -304,7 +309,7 @@ export async function processDockerConfig(context: any, resource: ApiResource, s }; } -async function shouldUpdateSecrets(context: any, secrets: Record): Promise { +async function shouldUpdateSecrets(context: $TSContext, secrets: Record): Promise { const hasSecrets = Object.keys(secrets).length > 0; if (!hasSecrets || context.exeInfo.inputParams.yes) { 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 index 05b3688da0..2c7adced53 100644 --- 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 @@ -1,4 +1,10 @@ -export const serviceMetadataFor = async service => (await import('../../supported-services')).supportedServices[service]; -export const datasourceMetadataFor = async datasource => (await import('../../supported-datasources')).supportedDatasources[datasource]; -export const getServiceWalkthrough = async walkthroughFilename => - (await import(`../service-walkthroughs/${walkthroughFilename}`)).serviceWalkthrough; +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 index 1196423873..3d339aecd0 100644 --- 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 @@ -1,18 +1,14 @@ -import inquirer, { ConfirmQuestion } from 'inquirer'; -import path from 'path'; +import { $TSContext, pathManager } from 'amplify-cli-core'; +import { prompter } from 'amplify-prompts'; +import * as path from 'path'; import { category } from '../../../category-constants'; import { gqlSchemaFilename } from '../aws-constants'; -export const editSchemaFlow = async (context: any, apiName: string) => { - const prompt: ConfirmQuestion = { - type: 'confirm', - name: 'editNow', - message: 'Do you want to edit the schema now?', - default: true, - }; +export const editSchemaFlow = async (context: $TSContext, apiName: string) => { + if (!(await prompter.yesOrNo('Do you want to edit the schema now?', true))) { + return; + } - if (!(await inquirer.prompt(prompt)).editNow) return; - - const schemaPath = path.join(context.amplify.pathManager.getBackendDirPath(), category, apiName, gqlSchemaFilename); + 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 new file mode 100644 index 0000000000..7fb7eb88b2 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-auth-config.ts @@ -0,0 +1,18 @@ +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 (resourceName: string) => { + const cliState = new AppsyncApiInputState(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 new file mode 100644 index 0000000000..089952ffbc --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/get-appsync-resolver-config.ts @@ -0,0 +1,15 @@ +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 (resourceName: string) => { + const cliState = new AppsyncApiInputState(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 new file mode 100644 index 0000000000..2e28ce65d4 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/getAppSyncApiName.ts @@ -0,0 +1,15 @@ +import { $TSContext, AmplifySupportedService } from '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 Error(`${AmplifySupportedService.APPSYNC} API does not exist. To add an api, use "amplify update api".`); + } + return apiResourceName; +}; 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 new file mode 100644 index 0000000000..d1f2c8331a --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/migrate-api-override-resource.ts @@ -0,0 +1,120 @@ +import { + $TSAny, + AmplifyCategories, + JSONUtilities, + NotInitializedError, + pathManager, + ResourceDoesNotExistError, + stateManager, +} from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import * as fs from 'fs-extra'; +import { ResolverConfig } from 'graphql-transformer-core'; +import _ from 'lodash'; +import * as path from 'path'; +import { v4 as uuid } from 'uuid'; +import { gqlSchemaFilename } from '../aws-constants'; +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: $TSAny; + 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 NotInitializedError(); + } + 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, apiresourceDirPath); + 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, apiResourceDir: string): 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, + gqlSchemaPath: path.join(apiResourceDir, gqlSchemaFilename), + }, + }; +}; 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 index f98601878b..eb8a6d423e 100644 --- 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 @@ -1,17 +1,19 @@ +import { printer } from '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 = (context, oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { +export const printApiKeyWarnings = (oldConfigHadApiKey: boolean, newConfigHasApiKey: boolean) => { if (oldConfigHadApiKey && !newConfigHasApiKey) { - context.print.warning('The API_KEY auth type has been removed from the API.'); - context.print.warning( + 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.', ); - context.print.warning('⚠️ This must be done before running "amplify push" to prevent a push failure'); + printer.warn('This must be done before running "amplify push" to prevent a push failure'); } if (!oldConfigHadApiKey && newConfigHasApiKey) { - context.print.warning('The API_KEY auth type has been added to the API.'); - context.print.warning( - '⚠️ 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.', + 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/rest-api-path-utils.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/utils/rest-api-path-utils.ts index 37370c2dea..2893bfe9a9 100644 --- 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 @@ -37,7 +37,7 @@ export const validatePathName = (name: string) => { // } // // checkForPathOverlap assumes that all provided paths have previously been run through validatePathName(). -export const checkForPathOverlap = (name: string, paths: { name: string }[]) => { +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 @@ -59,7 +59,7 @@ export const checkForPathOverlap = (name: string, paths: { name: string }[]) => 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.map(path => path.name).find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); + overlappingPath = paths.find(name => name === '/' || name.replace(/{[a-zA-Z0-9\-]+}/g, '{}') === subpath); return overlappingPath !== undefined; }); if (subMatch) { diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index 65b5b01910..b0e2a08bf6 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -27,7 +27,6 @@ export const supportedDatasources = { }, ], alias: 'Aurora Serverless', - defaultValuesFilename: 'appSync-rds-defaults.js', serviceWalkthroughFilename: 'appSync-rds-walkthrough.js', cfnFilename: 'appSync-rds-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index 99cc2e128b..70734fee70 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -122,7 +122,6 @@ export const supportedServices = { }, ], alias: 'GraphQL', - defaultValuesFilename: 'appSync-defaults.js', serviceWalkthroughFilename: 'appSync-walkthrough.js', cfnFilename: 'appSync-cloudformation-template-default.yml.ejs', provider: 'awscloudformation', @@ -148,9 +147,7 @@ export const supportedServices = { }, ], alias: 'REST', - defaultValuesFilename: 'apigw-defaults.js', serviceWalkthroughFilename: 'apigw-walkthrough.js', - cfnFilename: 'apigw-cloudformation-template-default.json.ejs', provider: 'awscloudformation', }, }; diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 5a69dbb23d..f4f67b9ed0 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -4,14 +4,17 @@ "outDir": "lib", "rootDir": "src", "strict": false, // because package has been converted from js - "allowJs": true + "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__" ], "references": [ From 879ff508a3d9a48b80eea6b4cddeccd51f349c7b Mon Sep 17 00:00:00 2001 From: Ammar <56042290+ammarkarachi@users.noreply.github.com> Date: Mon, 22 Nov 2021 18:14:37 -0800 Subject: [PATCH 506/587] docs: update graphql-transformer docs on version (#9033) Co-authored-by: AmmarKarachi --- .../awscloudformation/utils/global-sandbox-mode.test.ts | 4 ++-- .../service-walkthroughs/appSync-walkthrough.ts | 3 ++- .../awscloudformation/utils/global-sandbox-mode.ts | 4 ++-- 3 files changed, 6 insertions(+), 5 deletions(-) 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 index 5603957515..28716c527e 100644 --- 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 @@ -2,8 +2,8 @@ import { defineGlobalSandboxMode } from '../../../../provider-utils/awscloudform describe('global sandbox mode GraphQL directive', () => { it('returns input AMPLIFY with code comment', () => { - expect(defineGlobalSandboxMode()).toEqual(`# 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-transformer/auth + 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/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts b/packages/amplify-category-api/src/provider-utils/awscloudformation/service-walkthroughs/appSync-walkthrough.ts index cc9f30f0e5..2e8f9abca9 100644 --- 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 @@ -10,6 +10,7 @@ import { ResourceDoesNotExistError, stateManager, UnknownResourceTypeError, + getGraphQLTransformerAuthDocLink, } from 'amplify-cli-core'; import { UpdateApiRequest } from 'amplify-headless-interface'; import { printer } from 'amplify-prompts'; @@ -423,7 +424,7 @@ export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $ const { templateSelection } = await inquirer.prompt(templateSelectionQuestion); const schemaFilePath = path.join(graphqlSchemaDir, templateSelection); - schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode() : ''; + schemaContent += transformerVersion === 2 ? defineGlobalSandboxMode(getGraphQLTransformerAuthDocLink(transformerVersion)) : ''; schemaContent += fs.readFileSync(schemaFilePath, 'utf8'); return { 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 index 6c3d8db0cc..b9cd1c9884 100644 --- 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 @@ -1,6 +1,6 @@ -export function defineGlobalSandboxMode(): string { +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: https://docs.amplify.aws/cli/graphql-transformer/auth +# all models in this schema. Learn more about authorization rules here: ${link} input AMPLIFY { globalAuthRule: AuthRule = { allow: public } } # FOR TESTING ONLY!\n `; } From 0537bbb886757eb2e6590895f332c24f04d04b8b Mon Sep 17 00:00:00 2001 From: John Hockett Date: Mon, 22 Nov 2021 18:18:56 -0800 Subject: [PATCH 507/587] chore: add ^ to version, disable override test (#9040) --- .../awscloudformation/overrides-resource/APIGW/package.json | 2 +- .../awscloudformation/overrides-resource/AppSync/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) 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 index 6715c04ecd..33e7fd156b 100644 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/APIGW/package.json @@ -7,7 +7,7 @@ "watch": "tsc -w" }, "dependencies": { - "@aws-amplify/cli-extensibility-helper": "2.3.0" + "@aws-amplify/cli-extensibility-helper": "^2.3.0" }, "devDependencies": { "typescript": "^4.2.4" 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 index 6715c04ecd..33e7fd156b 100644 --- a/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json +++ b/packages/amplify-category-api/resources/awscloudformation/overrides-resource/AppSync/package.json @@ -7,7 +7,7 @@ "watch": "tsc -w" }, "dependencies": { - "@aws-amplify/cli-extensibility-helper": "2.3.0" + "@aws-amplify/cli-extensibility-helper": "^2.3.0" }, "devDependencies": { "typescript": "^4.2.4" From 6b057e61d688d2fa52c6428b73f326f4c9501ed9 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 23 Nov 2021 21:48:04 +0000 Subject: [PATCH 508/587] chore(release): Publish [ci skip] - amplify-app@4.2.5 - amplify-appsync-simulator@2.2.3 - amplify-category-analytics@3.2.5 - @aws-amplify/amplify-category-api@1.1.0 - @aws-amplify/amplify-category-auth@2.4.0 - @aws-amplify/amplify-category-custom@2.3.4 - amplify-category-function@3.3.4 - amplify-category-geo@2.2.5 - amplify-category-hosting@3.2.5 - amplify-category-interactions@3.2.5 - amplify-category-predictions@3.2.5 - @aws-amplify/amplify-category-storage@3.1.0 - amplify-category-xr@3.2.5 - amplify-cli-core@2.4.0 - @aws-amplify/cli-extensibility-helper@2.3.0 - @aws-amplify/cli@7.5.0 - amplify-console-hosting@2.2.5 - amplify-console-integration-tests@2.2.6 - amplify-container-hosting@2.4.0 - amplify-dotnet-function-template-provider@2.2.5 - amplify-dynamodb-simulator@2.2.5 - amplify-e2e-core@2.4.0 - amplify-e2e-tests@3.5.0 - amplify-frontend-ios@3.3.4 - amplify-frontend-javascript@3.3.4 - amplify-go-function-runtime-provider@2.2.5 - amplify-graphiql-explorer@2.4.0 - @aws-amplify/graphql-auth-transformer@0.5.0 - @aws-amplify/graphql-default-value-transformer@0.5.5 - @aws-amplify/graphql-function-transformer@0.7.0 - @aws-amplify/graphql-http-transformer@0.8.0 - @aws-amplify/graphql-index-transformer@0.8.0 - amplify-graphql-migration-tests@2.2.7 - @aws-amplify/graphql-model-transformer@0.10.0 - @aws-amplify/graphql-predictions-transformer@0.6.0 - @aws-amplify/graphql-relational-transformer@0.6.7 - @aws-amplify/graphql-searchable-transformer@0.10.0 - @aws-amplify/graphql-transformer-core@0.14.0 - @aws-amplify/graphql-transformer-migrator@1.2.7 - amplify-java-function-runtime-provider@2.2.5 - amplify-migration-tests@4.4.0 - amplify-nodejs-function-runtime-provider@2.2.5 - amplify-nodejs-function-template-provider@2.2.5 - amplify-prompts@1.6.0 - amplify-provider-awscloudformation@5.6.0 - amplify-python-function-runtime-provider@2.2.5 - amplify-util-import@2.2.5 - amplify-util-mock@4.2.11 - graphql-auth-transformer@7.2.5 - graphql-connection-transformer@5.2.5 - graphql-dynamodb-transformer@7.2.5 - graphql-elasticsearch-transformer@5.2.5 - graphql-function-transformer@3.2.5 - graphql-http-transformer@5.2.5 - graphql-key-transformer@3.2.5 - graphql-predictions-transformer@3.2.5 - graphql-relational-schema-transformer@2.21.0 - graphql-transformer-core@7.2.5 - graphql-transformers-e2e-tests@7.3.4 - graphql-versioned-transformer@5.2.5 --- packages/amplify-category-api/CHANGELOG.md | 209 +++++++++++++++++++++ packages/amplify-category-api/package.json | 12 +- 2 files changed, 215 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 42a4403117..8e31eca58a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,215 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# 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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index aefe311abc..af82f0b126 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.0.0", + "version": "1.1.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.6", + "@aws-amplify/graphql-transformer-migrator": "1.2.7", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.3.3", + "amplify-cli-core": "2.4.0", "amplify-headless-interface": "1.13.1", - "amplify-prompts": "1.5.1", + "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", "amplify-util-headless-input": "1.8.1", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.20.2", - "graphql-transformer-core": "7.2.4", + "graphql-relational-schema-transformer": "2.21.0", + "graphql-transformer-core": "7.2.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 6b282ed8208f5f6e182ffc945c847db3a963fd3e Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 24 Nov 2021 06:48:23 +0000 Subject: [PATCH 509/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.1.1 - @aws-amplify/cli@7.5.1 - amplify-container-hosting@2.4.1 - amplify-graphql-migration-tests@2.2.8 - @aws-amplify/graphql-transformer-migrator@1.2.8 - amplify-provider-awscloudformation@5.6.1 - amplify-util-mock@4.2.12 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8e31eca58a..fa7f2ffaa8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index af82f0b126..90ad0bfa99 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.0", + "version": "1.1.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.7", + "@aws-amplify/graphql-transformer-migrator": "1.2.8", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", From 02d13a800659b5805d4dca58746dc87b11ae0355 Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Wed, 24 Nov 2021 17:20:05 -0800 Subject: [PATCH 510/587] fix: console override build issue (#9078) * fix: console build issue * fix: remove console logs * fix: address comments * fix: uncommented e2e test * fix: build override for api * fix: address comments * fix: adding tsconfig to build if not present --- packages/amplify-category-api/src/index.ts | 10 ++-------- .../cdk-stack-builder/apigw-stack-transform.ts | 2 +- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 156259d1e3..377c02e7dc 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -291,8 +291,8 @@ export async function transformCategoryStack(context: $TSContext, resource: $TSO const backendDir = pathManager.getBackendDirPath(); const overrideDir = path.join(backendDir, resource.category, resource.resourceName); const isBuild = await buildOverrideDir(backendDir, overrideDir).catch(error => { - printer.debug(`Skipping build due to ${error.message}`); - return false; + printer.error(`Build error : ${error.message}`); + throw new Error(error); }); await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'compileSchema', [ context, @@ -308,12 +308,6 @@ export async function transformCategoryStack(context: $TSContext, resource: $TSO } } else if (resource.service === AmplifySupportedService.APIGW) { if (canResourceBeTransformed(resource.resourceName)) { - const backendDir = pathManager.getBackendDirPath(); - const overrideDir = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, resource.resourceName); - await buildOverrideDir(backendDir, overrideDir).catch(error => { - printer.debug(`Skipping build as ${error.message}`); - return false; - }); // Rebuild CFN const apigwStack = new ApigwStackTransform(context, resource.resourceName); apigwStack.transform(); 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 index 81eed824aa..8299ca64f5 100644 --- 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 @@ -183,7 +183,7 @@ export class ApigwStackTransform { const overrideJSFilePath = path.join(overrideFilePath, 'build', 'override.js'); const isBuild = await buildOverrideDir(backendDir, overrideFilePath).catch(error => { - printer.debug(`Skipping build as ${error.message}`); + printer.debug(`Build error : ${error.message}`); return false; }); From 1f1fef9d6b0368e89c61dd9b6d8680c34bb08a32 Mon Sep 17 00:00:00 2001 From: akshbhu <39866697+akshbhu@users.noreply.github.com> Date: Thu, 25 Nov 2021 16:06:12 -0800 Subject: [PATCH 511/587] fix: transformer version (#9092) * fix: transformer version * fix: unit tests * fix: async unit tests --- .../service-walkthroughs/appSync-walkthrough.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index 2e8f9abca9..aa535e6bc3 100644 --- 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 @@ -394,7 +394,7 @@ const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $TSObject) => { const resourceName = resourceAlreadyExists(); const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); - const transformerVersion = providerPlugin.getTransformerVersion(context); + const transformerVersion = await providerPlugin.getTransformerVersion(context); await addLambdaAuthorizerChoice(context); if (resourceName) { @@ -669,7 +669,7 @@ async function askSyncFunctionQuestion() { async function addLambdaAuthorizerChoice(context: $TSContext) { const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); - const transformerVersion = providerPlugin.getTransformerVersion(context); + const transformerVersion = await providerPlugin.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ name: 'Lambda', From fe6e48e246580b527ed209dbc4e40f1cb7e43f21 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 26 Nov 2021 23:51:54 +0000 Subject: [PATCH 512/587] chore(release): Publish [ci skip] - amplify-app@4.2.6 - amplify-category-analytics@3.2.6 - @aws-amplify/amplify-category-api@1.1.2 - @aws-amplify/amplify-category-auth@2.4.1 - @aws-amplify/amplify-category-custom@2.3.5 - amplify-category-function@3.3.5 - amplify-category-geo@2.2.6 - amplify-category-hosting@3.2.6 - amplify-category-interactions@3.2.6 - amplify-category-predictions@3.2.6 - @aws-amplify/amplify-category-storage@3.1.1 - amplify-category-xr@3.2.6 - amplify-cli-core@2.4.1 - @aws-amplify/cli-extensibility-helper@2.3.1 - @aws-amplify/cli@7.5.3 - amplify-console-hosting@2.2.6 - amplify-console-integration-tests@2.2.7 - amplify-container-hosting@2.4.2 - amplify-dotnet-function-template-provider@2.2.6 - amplify-dynamodb-simulator@2.2.6 - amplify-e2e-core@2.4.1 - amplify-e2e-tests@3.5.1 - amplify-frontend-ios@3.3.5 - amplify-frontend-javascript@3.3.5 - amplify-go-function-runtime-provider@2.2.6 - @aws-amplify/graphql-auth-transformer@0.5.1 - amplify-graphql-migration-tests@2.2.9 - @aws-amplify/graphql-relational-transformer@0.6.8 - @aws-amplify/graphql-transformer-migrator@1.2.9 - amplify-java-function-runtime-provider@2.2.6 - amplify-migration-tests@4.4.1 - amplify-nodejs-function-runtime-provider@2.2.6 - amplify-nodejs-function-template-provider@2.2.6 - amplify-provider-awscloudformation@5.7.0 - amplify-python-function-runtime-provider@2.2.6 - amplify-util-import@2.2.6 - amplify-util-mock@4.2.14 - graphql-auth-transformer@7.2.6 - graphql-connection-transformer@5.2.6 - graphql-dynamodb-transformer@7.2.6 - graphql-elasticsearch-transformer@5.2.6 - graphql-function-transformer@3.2.6 - graphql-http-transformer@5.2.6 - graphql-key-transformer@3.2.6 - graphql-predictions-transformer@3.2.6 - graphql-transformer-core@7.2.6 - graphql-transformers-e2e-tests@7.3.5 - graphql-versioned-transformer@5.2.6 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index fa7f2ffaa8..05f3424e14 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 90ad0bfa99..498452aa7b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.1", + "version": "1.1.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.8", + "@aws-amplify/graphql-transformer-migrator": "1.2.9", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,7 +68,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.0", + "amplify-cli-core": "2.4.1", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.2.5", + "graphql-transformer-core": "7.2.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 1b342bb4330db76d2cac274c4823ebafd2f1bb56 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Sun, 28 Nov 2021 15:32:01 -0500 Subject: [PATCH 513/587] fix: use __dirname instead of '.' in import path (#9105) Co-authored-by: Colin Ihrig --- packages/amplify-category-api/src/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 377c02e7dc..1ea3d3fa91 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -54,7 +54,7 @@ export async function migrate(context: $TSContext, serviceName?: string) { try { if (amplifyMeta[category][resourceName].providerPlugin) { const providerController = await import( - path.join('.', 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') + path.join(__dirname, 'provider-utils', amplifyMeta[category][resourceName].providerPlugin, 'index') ); if (providerController) { if (!serviceName || serviceName === amplifyMeta[category][resourceName].service) { @@ -125,7 +125,7 @@ export async function initEnv(context: $TSContext) { return; } - const providerController = await import(path.join('.', 'provider-utils', provider, 'index')); + const providerController = await import(path.join(__dirname, 'provider-utils', provider, 'index')); if (!providerController) { printer.error('Provider not configured for this category'); From 2a5cfefb3d83f1eb107187b27e57c8e732dbbc17 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 29 Nov 2021 00:34:50 +0000 Subject: [PATCH 514/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.1.3 - @aws-amplify/cli@7.5.4 - amplify-container-hosting@2.4.3 - amplify-graphql-migration-tests@2.2.10 - @aws-amplify/graphql-relational-transformer@0.6.9 - amplify-provider-awscloudformation@5.7.1 - amplify-util-mock@4.2.15 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 05f3424e14..afcc4f5286 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 498452aa7b..4b45d5ec03 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.2", + "version": "1.1.3", "description": "amplify-cli api plugin", "repository": { "type": "git", From aac2fbb7af01f3ec2c95381bfcab6135bcbca7be Mon Sep 17 00:00:00 2001 From: John Hockett Date: Mon, 29 Nov 2021 15:46:30 -0800 Subject: [PATCH 515/587] fix: migrate rest apis with protected routes on push (#9068) * fix: migrate rest apis with protected routes on push * fix: gracefully exit after 'no' to REST API migration --- .../awscloudformation/apigw-input-state.test.ts | 13 ++++++------- packages/amplify-category-api/src/index.ts | 4 ++-- .../awscloudformation/apigw-input-state.ts | 10 +++++----- .../service-walkthroughs/apigw-walkthrough.ts | 5 +++++ 4 files changed, 18 insertions(+), 14 deletions(-) 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 index 58057f9179..6211316a17 100644 --- 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 @@ -1,5 +1,6 @@ import { $TSContext, getMigrateResourceMessageForOverride, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; import { prompter } from 'amplify-prompts'; +import * as fs from 'fs-extra'; import { ApigwInputState } from '../../../provider-utils/awscloudformation/apigw-input-state'; jest.mock('amplify-cli-core'); @@ -7,6 +8,7 @@ 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; @@ -17,9 +19,6 @@ const context_mock = { updateamplifyMetaAfterResourceAdd: jest.fn(), updateamplifyMetaAfterResourceUpdate: jest.fn(), }, - filesystem: { - remove: jest.fn(), - }, } as unknown as $TSContext; pathManager_mock.findProjectRoot = jest.fn().mockReturnValue('mockProjRoot'); @@ -131,7 +130,7 @@ describe('REST API input state', () => { paths: mockApiPaths, }); expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.filesystem.remove).toHaveBeenCalledTimes(3); + expect(fs_mock.removeSync).toHaveBeenCalledTimes(3); }); it('does nothing when choosing NOT to migrate a REST API', async () => { @@ -145,7 +144,7 @@ describe('REST API input state', () => { expect(stateManager_mock.setResourceInputsJson).not.toHaveBeenCalled(); expect(stateManager_mock.setResourceParametersJson).not.toHaveBeenCalled(); expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).not.toHaveBeenCalled(); - expect(context_mock.filesystem.remove).not.toHaveBeenCalled(); + expect(fs_mock.removeSync).not.toHaveBeenCalled(); }); it('generates expected artifacts when choosing to migrate an Admin Queries API', async () => { @@ -162,7 +161,7 @@ describe('REST API input state', () => { expect(getMigrateResourceMessageForOverride).toHaveBeenCalled(); expect(stateManager_mock.setResourceInputsJson).toHaveBeenCalled(); expect(stateManager_mock.setResourceParametersJson).toHaveBeenCalled(); - expect(context_mock.filesystem.remove).toHaveBeenCalledTimes(2); + expect(fs_mock.removeSync).toHaveBeenCalledTimes(2); }); it('does nothing when choosing NOT to migrate an Admin Queries API', async () => { @@ -181,7 +180,7 @@ describe('REST API input state', () => { expect(stateManager_mock.setResourceInputsJson).not.toHaveBeenCalled(); expect(stateManager_mock.setResourceParametersJson).not.toHaveBeenCalled(); expect(context_mock.amplify.updateamplifyMetaAfterResourceUpdate).not.toHaveBeenCalled(); - expect(context_mock.filesystem.remove).not.toHaveBeenCalled(); + expect(fs_mock.removeSync).not.toHaveBeenCalled(); }); it('generates expected artifacts when adding an Admin Queries API', async () => { diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 1ea3d3fa91..907872f87e 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -45,8 +45,8 @@ export async function console(context: $TSContext) { } export async function migrate(context: $TSContext, serviceName?: string) { - const { projectPath } = context.migrationInfo; - const amplifyMeta = stateManager.getMeta(); + const { projectPath } = context?.migrationInfo ?? { projectPath: pathManager.findProjectRoot() }; + const amplifyMeta = stateManager.getMeta(projectPath); const migrateResourcePromises = []; for (const categoryName of Object.keys(amplifyMeta)) { if (categoryName === category) { 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 index 3a20074f6b..ab9529cfdf 100644 --- 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 @@ -108,8 +108,8 @@ export class ApigwInputState { } const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); - this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - this.context.filesystem.remove(join(resourceDirPath, 'admin-queries-cloudformation-template.json')); + fs.removeSync(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + fs.removeSync(join(resourceDirPath, 'admin-queries-cloudformation-template.json')); return this.updateAdminQueriesResource(adminQueriesProps); }; @@ -199,9 +199,9 @@ export class ApigwInputState { }; }); - this.context.filesystem.remove(deprecatedParametersFilePath); - this.context.filesystem.remove(join(resourceDirPath, PathConstants.ParametersJsonFileName)); - this.context.filesystem.remove(join(resourceDirPath, `${this.resourceName}-cloudformation-template.json`)); + fs.removeSync(deprecatedParametersFilePath); + fs.removeSync(join(resourceDirPath, PathConstants.ParametersJsonFileName)); + fs.removeSync(join(resourceDirPath, `${this.resourceName}-cloudformation-template.json`)); await this.createApigwArtifacts(); }; 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 index 4a61ff3274..e2b6db7ef6 100644 --- 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 @@ -78,6 +78,11 @@ export async function updateWalkthrough(context: $TSContext) { 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); From a12b115e9b78dc3218ffa5e28c3c9d9d8317cc27 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 1 Dec 2021 02:28:22 +0000 Subject: [PATCH 516/587] chore(release): Publish [ci skip] - amplify-app@4.2.7 - amplify-category-analytics@3.2.7 - @aws-amplify/amplify-category-api@1.1.4 - @aws-amplify/amplify-category-auth@2.4.2 - @aws-amplify/amplify-category-custom@2.3.6 - amplify-category-function@3.3.6 - amplify-category-geo@2.2.7 - amplify-category-hosting@3.2.7 - amplify-category-interactions@3.2.7 - amplify-category-predictions@3.2.7 - @aws-amplify/amplify-category-storage@3.1.2 - amplify-category-xr@3.2.7 - amplify-cli-core@2.4.2 - @aws-amplify/cli-extensibility-helper@2.3.2 - @aws-amplify/cli@7.5.5 - amplify-console-hosting@2.2.7 - amplify-console-integration-tests@2.2.8 - amplify-container-hosting@2.4.4 - amplify-dotnet-function-template-provider@2.2.7 - amplify-dynamodb-simulator@2.2.7 - amplify-e2e-core@2.4.2 - amplify-e2e-tests@3.5.2 - amplify-frontend-ios@3.3.6 - amplify-frontend-javascript@3.3.6 - amplify-go-function-runtime-provider@2.2.7 - @aws-amplify/graphql-auth-transformer@0.5.2 - amplify-graphql-migration-tests@2.2.11 - @aws-amplify/graphql-relational-transformer@0.6.10 - @aws-amplify/graphql-transformer-migrator@1.2.10 - amplify-java-function-runtime-provider@2.2.7 - amplify-migration-tests@4.4.2 - amplify-nodejs-function-runtime-provider@2.2.7 - amplify-nodejs-function-template-provider@2.2.7 - amplify-provider-awscloudformation@5.7.2 - amplify-python-function-runtime-provider@2.2.7 - amplify-util-import@2.2.7 - amplify-util-mock@4.2.16 - graphql-auth-transformer@7.2.7 - graphql-connection-transformer@5.2.7 - graphql-dynamodb-transformer@7.2.7 - graphql-elasticsearch-transformer@5.2.7 - graphql-function-transformer@3.2.7 - graphql-http-transformer@5.2.7 - graphql-key-transformer@3.2.7 - graphql-predictions-transformer@3.2.7 - graphql-transformer-core@7.2.7 - graphql-transformers-e2e-tests@7.3.6 - graphql-versioned-transformer@5.2.7 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index afcc4f5286..b03ed3a0ff 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4b45d5ec03..70e4b337a9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.3", + "version": "1.1.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.9", + "@aws-amplify/graphql-transformer-migrator": "1.2.10", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,7 +68,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.1", + "amplify-cli-core": "2.4.2", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.2.6", + "graphql-transformer-core": "7.2.7", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 2c8e8dabca19f6fddc561e7d27d944caa0d09ee6 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Wed, 1 Dec 2021 14:16:23 -0800 Subject: [PATCH 517/587] fix: call the correct migration function for Admin Queries (#9174) * fix: call the correct migration function for Admin Queries * fix: address PR feedback to use lodash * fix: missing ! in conditional * fix: conditional fix for interactions category --- .../service-walkthroughs/apigw-walkthrough.ts | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) 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 index e2b6db7ef6..88652e6da7 100644 --- 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 @@ -13,6 +13,7 @@ import { } from 'amplify-cli-core'; import { byValues, printer, prompter } from 'amplify-prompts'; import inquirer from 'inquirer'; +import _ from 'lodash'; import os from 'os'; import { v4 as uuid } from 'uuid'; import { ADMIN_QUERIES_NAME } from '../../../category-constants'; @@ -597,6 +598,27 @@ async function askLambdaArn(context: $TSContext, currentPath?: ApigwPath) { 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); } From a91019f330bf0573adb66f017307869ab6d8a4e0 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 2 Dec 2021 06:19:16 +0000 Subject: [PATCH 518/587] chore(release): Publish [ci skip] - amplify-app@4.2.8 - amplify-category-analytics@3.2.8 - @aws-amplify/amplify-category-api@1.1.5 - @aws-amplify/amplify-category-auth@2.4.3 - @aws-amplify/amplify-category-custom@2.3.7 - amplify-category-function@3.3.7 - amplify-category-geo@2.2.8 - amplify-category-hosting@3.2.8 - amplify-category-interactions@3.2.8 - amplify-category-predictions@3.2.8 - @aws-amplify/amplify-category-storage@3.1.3 - amplify-category-xr@3.2.8 - amplify-cli-core@2.4.3 - @aws-amplify/cli-extensibility-helper@2.3.3 - @aws-amplify/cli@7.5.6 - amplify-console-hosting@2.2.8 - amplify-console-integration-tests@2.2.9 - amplify-container-hosting@2.4.5 - amplify-dotnet-function-template-provider@2.2.8 - amplify-dynamodb-simulator@2.2.8 - amplify-e2e-core@2.4.3 - amplify-e2e-tests@3.5.3 - amplify-frontend-ios@3.3.7 - amplify-frontend-javascript@3.3.7 - amplify-go-function-runtime-provider@2.2.8 - amplify-graphql-migration-tests@2.2.12 - @aws-amplify/graphql-transformer-migrator@1.2.11 - amplify-java-function-runtime-provider@2.2.8 - amplify-migration-tests@4.4.3 - amplify-nodejs-function-runtime-provider@2.2.8 - amplify-nodejs-function-template-provider@2.2.8 - amplify-provider-awscloudformation@5.7.3 - amplify-python-function-runtime-provider@2.2.8 - amplify-util-import@2.2.8 - amplify-util-mock@4.2.17 - graphql-auth-transformer@7.2.8 - graphql-connection-transformer@5.2.8 - graphql-dynamodb-transformer@7.2.8 - graphql-elasticsearch-transformer@5.2.8 - graphql-function-transformer@3.2.8 - graphql-http-transformer@5.2.8 - graphql-key-transformer@3.2.8 - graphql-predictions-transformer@3.2.8 - graphql-transformer-core@7.2.8 - graphql-transformers-e2e-tests@7.3.7 - graphql-versioned-transformer@5.2.8 --- packages/amplify-category-api/CHANGELOG.md | 15 +++++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index b03ed3a0ff..430867c38a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 70e4b337a9..99130701e8 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.4", + "version": "1.1.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.10", + "@aws-amplify/graphql-transformer-migrator": "1.2.11", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,7 +68,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.2", + "amplify-cli-core": "2.4.3", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.2.7", + "graphql-transformer-core": "7.2.8", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From cf7b88faed5f02e861cb1d25a757762c1a7afaa4 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Thu, 2 Dec 2021 16:40:01 -0500 Subject: [PATCH 519/587] fix: add safety check (#9193) This protects against malformed input files. Fixes: https://github.com/aws-amplify/amplify-cli/issues/9186 Co-authored-by: Colin Ihrig --- .../service-walkthroughs/appSync-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index aa535e6bc3..12c1fa9500 100644 --- 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 @@ -507,7 +507,7 @@ async function displayApiInformation(context: $TSContext, resource: $TSObject, p authModes.push( `- Default: ${await displayAuthMode(context, resource, resource.output.authConfig.defaultAuthentication.authenticationType)}`, ); - await resource.output.authConfig.additionalAuthenticationProviders.map(async authMode => { + await resource.output.authConfig.additionalAuthenticationProviders?.map(async authMode => { authModes.push(`- ${await displayAuthMode(context, resource, authMode.authenticationType)}`); }); From 05c8b66767b17e752226e798b310b55c914345dd Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 3 Dec 2021 06:12:46 +0000 Subject: [PATCH 520/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@2.3.1 - @aws-amplify/amplify-category-api@1.1.6 - amplify-category-function@3.3.8 - amplify-category-geo@2.2.9 - @aws-amplify/cli@7.6.2 - amplify-console-integration-tests@2.2.11 - amplify-container-hosting@2.4.6 - amplify-dotnet-function-template-provider@2.2.9 - amplify-e2e-core@2.4.5 - amplify-e2e-tests@3.5.5 - @aws-amplify/graphql-auth-transformer@0.5.3 - @aws-amplify/graphql-default-value-transformer@0.5.6 - @aws-amplify/graphql-function-transformer@0.7.1 - @aws-amplify/graphql-http-transformer@0.8.1 - @aws-amplify/graphql-index-transformer@0.8.1 - amplify-graphql-migration-tests@2.2.13 - @aws-amplify/graphql-model-transformer@0.10.1 - @aws-amplify/graphql-predictions-transformer@0.6.1 - @aws-amplify/graphql-relational-transformer@0.6.11 - @aws-amplify/graphql-searchable-transformer@0.10.1 - @aws-amplify/graphql-transformer-core@0.15.0 - @aws-amplify/graphql-transformer-migrator@1.2.12 - amplify-migration-tests@4.4.5 - amplify-nodejs-function-template-provider@2.2.9 - amplify-provider-awscloudformation@5.8.2 - amplify-util-mock@4.2.20 - @aws-amplify/amplify-util-uibuilder@1.1.2 - graphql-auth-transformer@7.2.9 - graphql-connection-transformer@5.2.9 - graphql-dynamodb-transformer@7.2.9 - graphql-elasticsearch-transformer@5.2.9 - graphql-function-transformer@3.3.0 - graphql-http-transformer@5.2.9 - graphql-key-transformer@3.2.9 - graphql-predictions-transformer@3.2.9 - graphql-transformer-core@7.3.0 - graphql-transformers-e2e-tests@7.3.8 - graphql-versioned-transformer@5.2.9 --- packages/amplify-category-api/CHANGELOG.md | 15 +++++++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 430867c38a..1f904704e0 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 99130701e8..c21c286711 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.5", + "version": "1.1.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.11", + "@aws-amplify/graphql-transformer-migrator": "1.2.12", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.2.8", + "graphql-transformer-core": "7.3.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 12bd5b312bfa3203f996cba3847d4fb97cdaaaef Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 10 Dec 2021 13:29:32 -0800 Subject: [PATCH 521/587] fix: add-graphql-datasource command (#9288) --- .../src/commands/api/add-graphql-datasource.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 index f2c14ca785..ae779b7ca3 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -11,6 +11,7 @@ import { import inquirer from 'inquirer'; import _ from 'lodash'; import * as path from 'path'; +import { supportedDatasources } from '../../provider-utils/supported-datasources'; const subcommand = 'add-graphql-datasource'; const categories = 'categories'; @@ -21,10 +22,9 @@ export const name = subcommand; export const run = async (context: $TSContext) => { try { - const servicesMetadata = (await import(path.join('..', '..', 'provider-utils', 'supported-services'))).supportedServices; const AWS = await getAwsClient(context, 'list'); - const result: $TSAny = await datasourceSelectionPrompt(context, servicesMetadata); + const result: $TSAny = await datasourceSelectionPrompt(context, supportedDatasources); const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); From 8e859ef9d1cfda88a9f93daa11d7a0f5bd7ff5cf Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 10 Dec 2021 13:31:51 -0800 Subject: [PATCH 522/587] fix: add missing salt to deployment logicalId (#9234) * fix: add missing salt to deployment logicalId * test: update e2e test to call rest api endpoints --- .../cdk-stack-builder/apigw-stack-builder.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 index 338f77bac4..f5ad1af03c 100644 --- 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 @@ -4,6 +4,7 @@ import * as lambda from '@aws-cdk/aws-lambda'; import * as cdk from '@aws-cdk/core'; import { $TSObject, JSONUtilities } from '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'; @@ -284,7 +285,8 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw } private _setDeploymentResource = (resourceName: string) => { - this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}`, { + const [shortId] = uuid().split('-'); + this.deploymentResource = new apigw.CfnDeployment(this, `DeploymentAPIGW${resourceName}${shortId}`, { description: 'The Development stage deployment of your API.', stageName: cdk.Fn.conditionIf('ShouldNotCreateEnvResources', 'Prod', cdk.Fn.ref('env')).toString(), restApiId: cdk.Fn.ref(resourceName), From 8f0b72ae36bedce6bd03b9cbdf5cfc442f8f1cce Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 10 Dec 2021 13:32:01 -0800 Subject: [PATCH 523/587] fix: improve api migration logic, update migration prompt (#9267) * fix: improve migration logic, update migration prompt * fix: update migration message text --- packages/amplify-category-api/src/index.ts | 5 +++-- .../awscloudformation/apigw-input-state.ts | 16 ++++++++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 907872f87e..9e3c79e6ca 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -73,8 +73,9 @@ export async function migrate(context: $TSContext, serviceName?: string) { } } } - - await Promise.all(migrateResourcePromises); + for (const migrateResourcePromise of migrateResourcePromises) { + await migrateResourcePromise; + } } export async function initEnv(context: $TSContext) { 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 index ab9529cfdf..599c08a022 100644 --- 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 @@ -153,11 +153,15 @@ export class ApigwInputState { return Array.from(new Set(deprecatedPrivacyArray.map(op => opMap[op]))); } + 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: $TSObject) => { let pathPermissionSetting = - path.privacy.open === true + path.privacy?.open === true ? PermissionSetting.OPEN - : path.privacy.private === true + : path.privacy?.private === true ? PermissionSetting.PRIVATE : PermissionSetting.PROTECTED; @@ -165,15 +169,15 @@ export class ApigwInputState { let guest; let groups; // convert deprecated permissions to CRUD structure - if (typeof path.privacy.auth === 'string' && ['r', 'rw'].includes(path.privacy.auth)) { + if (typeof path.privacy?.auth === 'string' && ['r', 'rw'].includes(path.privacy.auth)) { auth = _convertDeprecatedPermissionStringToCRUD(path.privacy.auth); - } else if (Array.isArray(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)) { + if (typeof path.privacy?.unauth === 'string' && ['r', 'rw'].includes(path.privacy.unauth)) { guest = _convertDeprecatedPermissionStringToCRUD(path.privacy.unauth); - } else if (Array.isArray(path.privacy.unauth)) { + } else if (Array.isArray(path.privacy?.unauth)) { guest = _convertDeprecatedPermissionArrayToCRUD(path.privacy.unauth); } From d134d25c8f8503f21f4fb904398e84781417b0e1 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 17 Dec 2021 00:37:11 +0000 Subject: [PATCH 524/587] chore(release): Publish [ci skip] - amplify-app@4.2.9 - amplify-category-analytics@3.2.9 - @aws-amplify/amplify-category-api@1.1.7 - @aws-amplify/amplify-category-auth@2.4.5 - @aws-amplify/amplify-category-custom@2.3.8 - amplify-category-function@3.3.9 - amplify-category-geo@2.2.10 - amplify-category-hosting@3.2.9 - amplify-category-interactions@3.2.9 - amplify-category-predictions@3.2.9 - @aws-amplify/amplify-category-storage@3.1.4 - amplify-category-xr@3.2.9 - amplify-cli-core@2.4.4 - @aws-amplify/cli-extensibility-helper@2.3.4 - @aws-amplify/cli@7.6.4 - amplify-console-hosting@2.2.9 - amplify-console-integration-tests@2.2.12 - amplify-container-hosting@2.4.7 - amplify-dotnet-function-template-provider@2.2.10 - amplify-dynamodb-simulator@2.2.9 - amplify-e2e-core@2.4.6 - amplify-e2e-tests@3.5.7 - amplify-frontend-ios@3.3.8 - amplify-frontend-javascript@3.3.8 - amplify-go-function-runtime-provider@2.2.9 - @aws-amplify/graphql-auth-transformer@0.5.4 - @aws-amplify/graphql-default-value-transformer@0.5.7 - @aws-amplify/graphql-function-transformer@0.7.2 - @aws-amplify/graphql-http-transformer@0.8.2 - @aws-amplify/graphql-index-transformer@0.8.2 - amplify-graphql-migration-tests@2.2.14 - @aws-amplify/graphql-model-transformer@0.10.2 - @aws-amplify/graphql-predictions-transformer@0.6.2 - @aws-amplify/graphql-relational-transformer@0.6.12 - @aws-amplify/graphql-searchable-transformer@0.10.2 - @aws-amplify/graphql-transformer-core@0.15.1 - @aws-amplify/graphql-transformer-migrator@1.2.13 - amplify-java-function-runtime-provider@2.2.9 - amplify-migration-tests@4.4.6 - amplify-nodejs-function-runtime-provider@2.2.9 - amplify-nodejs-function-template-provider@2.2.10 - amplify-provider-awscloudformation@5.8.4 - amplify-python-function-runtime-provider@2.2.9 - amplify-util-import@2.2.9 - amplify-util-mock@4.2.22 - graphql-auth-transformer@7.2.10 - graphql-connection-transformer@5.2.10 - graphql-dynamodb-transformer@7.2.10 - graphql-elasticsearch-transformer@5.2.10 - graphql-function-transformer@3.3.1 - graphql-http-transformer@5.2.10 - graphql-key-transformer@3.2.10 - graphql-predictions-transformer@3.2.10 - graphql-transformer-core@7.3.1 - graphql-transformers-e2e-tests@7.3.9 - graphql-versioned-transformer@5.2.10 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1f904704e0..e7e7001187 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c21c286711..421f084b48 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.6", + "version": "1.1.7", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.12", + "@aws-amplify/graphql-transformer-migrator": "1.2.13", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,7 +68,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.3", + "amplify-cli-core": "2.4.4", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.3.0", + "graphql-transformer-core": "7.3.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From e3849ba2247015022cb3b04b907e0e107f2645e4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 21 Dec 2021 21:08:44 +0000 Subject: [PATCH 525/587] chore(release): Publish [ci skip] - amplify-app@4.2.10 - amplify-category-analytics@3.2.10 - @aws-amplify/amplify-category-api@1.1.8 - @aws-amplify/amplify-category-auth@2.4.6 - @aws-amplify/amplify-category-custom@2.3.9 - amplify-category-function@3.3.10 - amplify-category-geo@2.2.11 - amplify-category-hosting@3.2.10 - amplify-category-interactions@3.2.10 - amplify-category-predictions@3.2.10 - @aws-amplify/amplify-category-storage@3.1.5 - amplify-category-xr@3.2.10 - amplify-cli-core@2.4.5 - @aws-amplify/cli-extensibility-helper@2.3.5 - @aws-amplify/cli@7.6.5 - amplify-console-hosting@2.2.10 - amplify-console-integration-tests@2.2.13 - amplify-container-hosting@2.4.8 - amplify-dotnet-function-template-provider@2.2.11 - amplify-dynamodb-simulator@2.2.10 - amplify-e2e-core@2.4.7 - amplify-e2e-tests@3.5.8 - amplify-frontend-ios@3.3.9 - amplify-frontend-javascript@3.3.9 - amplify-go-function-runtime-provider@2.2.10 - @aws-amplify/graphql-auth-transformer@0.5.5 - @aws-amplify/graphql-default-value-transformer@0.5.8 - @aws-amplify/graphql-function-transformer@0.7.3 - @aws-amplify/graphql-http-transformer@0.8.3 - @aws-amplify/graphql-index-transformer@0.8.3 - amplify-graphql-migration-tests@2.2.15 - @aws-amplify/graphql-model-transformer@0.10.3 - @aws-amplify/graphql-predictions-transformer@0.6.3 - @aws-amplify/graphql-relational-transformer@0.6.13 - @aws-amplify/graphql-searchable-transformer@0.10.3 - @aws-amplify/graphql-transformer-core@0.15.2 - @aws-amplify/graphql-transformer-migrator@1.2.14 - amplify-java-function-runtime-provider@2.2.10 - amplify-migration-tests@4.4.7 - amplify-nodejs-function-runtime-provider@2.2.10 - amplify-nodejs-function-template-provider@2.2.11 - amplify-provider-awscloudformation@5.8.5 - amplify-python-function-runtime-provider@2.2.10 - amplify-util-import@2.2.10 - amplify-util-mock@4.2.23 - graphql-auth-transformer@7.2.11 - graphql-connection-transformer@5.2.11 - graphql-dynamodb-transformer@7.2.11 - graphql-elasticsearch-transformer@5.2.11 - graphql-function-transformer@3.3.2 - graphql-http-transformer@5.2.11 - graphql-key-transformer@3.2.11 - graphql-predictions-transformer@3.2.11 - graphql-transformer-core@7.3.2 - graphql-transformers-e2e-tests@7.3.10 - graphql-versioned-transformer@5.2.11 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 8 ++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e7e7001187..5471f6253b 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 421f084b48..1e05f25525 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.7", + "version": "1.1.8", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.13", + "@aws-amplify/graphql-transformer-migrator": "1.2.14", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,7 +68,7 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.4", + "amplify-cli-core": "2.4.5", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", "amplify-provider-awscloudformation": "4.61.1", @@ -78,7 +78,7 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.3.1", + "graphql-transformer-core": "7.3.2", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 4b661912f9222a7def70bd4100ab446926d81045 Mon Sep 17 00:00:00 2001 From: Yoshiaki Togami <62130798+togami2864@users.noreply.github.com> Date: Thu, 6 Jan 2022 01:28:32 +0900 Subject: [PATCH 526/587] chore: rename Mac OS -> macOS (#8628) --- .../src/provider-utils/supported-services.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/src/provider-utils/supported-services.ts b/packages/amplify-category-api/src/provider-utils/supported-services.ts index 70734fee70..21de2e9c38 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-services.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-services.ts @@ -87,11 +87,11 @@ export const supportedServices = { value: 'idea14ce', }, { - name: 'Vim (via Terminal, Mac OS only)', + name: 'Vim (via Terminal, macOS only)', value: 'vim', }, { - name: 'Emacs (via Terminal, Mac OS only)', + name: 'Emacs (via Terminal, macOS only)', value: 'emacs', }, { From b3a814b35b85be57f34e012ed9d78391971c0a27 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Wed, 5 Jan 2022 16:48:56 -0500 Subject: [PATCH 527/587] fix: update dep and use node test environment (#9434) There is an out of date dependency on amplify-provider-awscloudformation, which is pulling in a number of older dependency versions. This commit fixes the dependency version. This commit also updates some of our test suites to use the Node testing environment instead of the default of jsdom. This is done because the default does not properly handle some Node globals. Refs: https://github.com/panva/jose/issues/307 Co-authored-by: Colin Ihrig --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1e05f25525..c0a1afc5f0 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -71,7 +71,7 @@ "amplify-cli-core": "2.4.5", "amplify-headless-interface": "1.13.1", "amplify-prompts": "1.6.0", - "amplify-provider-awscloudformation": "4.61.1", + "amplify-provider-awscloudformation": "5.8.5", "amplify-util-headless-input": "1.8.1", "chalk": "^4.1.1", "constructs": "^3.3.125", From f8bda3eb0927968d72a0f917d8c4d30722076d47 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Sun, 9 Jan 2022 18:43:48 -0800 Subject: [PATCH 528/587] chore: manual patch version bump for all packages (#9471) --- packages/amplify-category-api/package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index c0a1afc5f0..ece71f170d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.8", + "version": "1.1.9", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.14", + "@aws-amplify/graphql-transformer-migrator": "1.2.15", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.5", - "amplify-headless-interface": "1.13.1", - "amplify-prompts": "1.6.0", - "amplify-provider-awscloudformation": "5.8.5", - "amplify-util-headless-input": "1.8.1", + "amplify-cli-core": "2.4.6", + "amplify-headless-interface": "1.13.2", + "amplify-prompts": "1.6.1", + "amplify-provider-awscloudformation": "5.8.6", + "amplify-util-headless-input": "1.8.2", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.0", - "graphql-transformer-core": "7.3.2", + "graphql-relational-schema-transformer": "2.21.1", + "graphql-transformer-core": "7.3.3", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 467fdf7e10407e4ef709e8a5fa9ed03413de6c58 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 10 Jan 2022 03:18:29 +0000 Subject: [PATCH 529/587] chore(release): Publish [ci skip] - amplify-app@4.2.12 - amplify-appsync-simulator@2.3.4 - amplify-category-analytics@3.2.12 - @aws-amplify/amplify-category-api@1.1.10 - @aws-amplify/amplify-category-auth@2.4.8 - @aws-amplify/amplify-category-custom@2.3.11 - amplify-category-function@3.3.12 - amplify-category-geo@2.2.13 - amplify-category-hosting@3.2.12 - amplify-category-interactions@3.2.12 - amplify-category-predictions@3.2.12 - @aws-amplify/amplify-category-storage@3.1.7 - amplify-category-xr@3.2.12 - amplify-cli-core@2.4.7 - @aws-amplify/cli-extensibility-helper@2.3.7 - @aws-amplify/cli@7.6.7 - amplify-codegen-appsync-model-plugin@1.24.4 - amplify-console-hosting@2.2.12 - amplify-console-integration-tests@2.2.15 - amplify-container-hosting@2.4.10 - amplify-dotnet-function-runtime-provider@1.6.6 - amplify-dotnet-function-template-provider@2.2.13 - amplify-dynamodb-simulator@2.2.12 - amplify-e2e-core@2.4.9 - amplify-e2e-tests@3.5.10 - amplify-frontend-android@3.3.2 - amplify-frontend-flutter@1.3.2 - amplify-frontend-ios@3.3.11 - amplify-frontend-javascript@3.3.11 - amplify-function-plugin-interface@1.9.4 - amplify-go-function-runtime-provider@2.2.12 - amplify-go-function-template-provider@1.3.13 - amplify-graphiql-explorer@2.4.3 - @aws-amplify/graphql-auth-transformer@0.5.7 - @aws-amplify/graphql-default-value-transformer@0.5.10 - @aws-amplify/graphql-function-transformer@0.7.5 - @aws-amplify/graphql-http-transformer@0.8.5 - @aws-amplify/graphql-index-transformer@0.8.5 - amplify-graphql-migration-tests@2.2.17 - @aws-amplify/graphql-model-transformer@0.10.5 - @aws-amplify/graphql-predictions-transformer@0.6.5 - @aws-amplify/graphql-relational-transformer@0.6.15 - @aws-amplify/graphql-searchable-transformer@0.10.5 - @aws-amplify/graphql-transformer-core@0.15.4 - @aws-amplify/graphql-transformer-interfaces@1.12.5 - @aws-amplify/graphql-transformer-migrator@1.2.16 - amplify-headless-interface@1.13.3 - amplify-java-function-runtime-provider@2.2.12 - amplify-java-function-template-provider@1.5.12 - amplify-migration-tests@4.4.9 - amplify-nodejs-function-runtime-provider@2.2.12 - amplify-nodejs-function-template-provider@2.2.13 - amplify-prompts@1.6.2 - amplify-provider-awscloudformation@5.8.7 - amplify-python-function-runtime-provider@2.2.12 - amplify-python-function-template-provider@1.3.15 - amplify-storage-simulator@1.6.3 - amplify-util-headless-input@1.8.3 - amplify-util-import@2.2.12 - amplify-util-mock@4.2.25 - @aws-amplify/amplify-util-uibuilder@1.1.4 - graphql-auth-transformer@7.2.13 - graphql-connection-transformer@5.2.13 - graphql-dynamodb-transformer@7.2.13 - graphql-elasticsearch-transformer@5.2.13 - graphql-function-transformer@3.3.4 - graphql-http-transformer@5.2.13 - graphql-key-transformer@3.2.13 - graphql-mapping-template@4.20.3 - graphql-predictions-transformer@3.2.13 - graphql-relational-schema-transformer@2.21.2 - graphql-transformer-common@4.22.4 - graphql-transformer-core@7.3.4 - graphql-transformers-e2e-tests@7.3.12 - graphql-versioned-transformer@5.2.13 --- packages/amplify-category-api/CHANGELOG.md | 15 +++++++++++++++ packages/amplify-category-api/package.json | 18 +++++++++--------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 5471f6253b..4eacddb381 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,21 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index ece71f170d..93b1723ba4 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.9", + "version": "1.1.10", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.15", + "@aws-amplify/graphql-transformer-migrator": "1.2.16", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.6", - "amplify-headless-interface": "1.13.2", - "amplify-prompts": "1.6.1", - "amplify-provider-awscloudformation": "5.8.6", - "amplify-util-headless-input": "1.8.2", + "amplify-cli-core": "2.4.7", + "amplify-headless-interface": "1.13.3", + "amplify-prompts": "1.6.2", + "amplify-provider-awscloudformation": "5.8.7", + "amplify-util-headless-input": "1.8.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.1", - "graphql-transformer-core": "7.3.3", + "graphql-relational-schema-transformer": "2.21.2", + "graphql-transformer-core": "7.3.4", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From d0f4e3223c4e724cad6a792927cbc0b458b58517 Mon Sep 17 00:00:00 2001 From: James Au <40404256+jamesaucode@users.noreply.github.com> Date: Tue, 11 Jan 2022 11:39:07 -0800 Subject: [PATCH 530/587] feat(amplify-category-api): enable default 4xx and 5xx api gateway cors response (#9158) * feat(amplify-category-api): enable default 4xx and 5xx api gateway cors response fix #5183 * add @aws-cdk/assertions and unit tests * Update apigw-stack-builder.test.ts remove console.log from test file * move @aws-cdk/assertions to devDependencies * add e2e test --- packages/amplify-category-api/package.json | 1 + .../apigw-stack-builder.test.ts | 47 +++++++++++++++++++ .../cdk-stack-builder/apigw-stack-builder.ts | 17 +++++++ 3 files changed, 65 insertions(+) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 93b1723ba4..9a7f29cf02 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -86,6 +86,7 @@ "uuid": "^8.3.2" }, "devDependencies": { + "@aws-cdk/assertions": "~1.124.0", "@types/js-yaml": "^4.0.0" }, "jest": { 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 new file mode 100644 index 0000000000..d4ab256e77 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder.test.ts @@ -0,0 +1,47 @@ +import * as cdk from '@aws-cdk/core'; +import { Template } from '@aws-cdk/assertions'; +import { AmplifyApigwResourceStack } from '../../../../provider-utils/awscloudformation/cdk-stack-builder/apigw-stack-builder'; +import { PermissionSetting } from '../../../../provider-utils/awscloudformation/cdk-stack-builder/types'; + +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', + }, + }); + }); +}); 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 index f5ad1af03c..9a4a236bdc 100644 --- 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 @@ -244,6 +244,16 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw }, }, }); + new apigw.CfnGatewayResponse(this, `${resourceName}Default4XXResponse`, { + responseType: 'DEFAULT_4XX', + restApiId: cdk.Fn.ref(resourceName), + responseParameters: defaultCorsGatewayResponseParams, + }); + new apigw.CfnGatewayResponse(this, `${resourceName}Default5XXResponse`, { + responseType: 'DEFAULT_5XX', + restApiId: cdk.Fn.ref(resourceName), + responseParameters: defaultCorsGatewayResponseParams, + }); this._setDeploymentResource(resourceName); }; @@ -457,6 +467,13 @@ const defaultCorsResponseObject = { }, }; +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: { From 2e48122f17d3947ef9a327e675a6b3e88c8e5978 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 13 Jan 2022 04:22:39 +0000 Subject: [PATCH 531/587] chore(release): Publish [ci skip] - amplify-appsync-simulator@2.3.5 - @aws-amplify/amplify-category-api@1.2.0 - @aws-amplify/amplify-category-auth@2.4.9 - amplify-category-function@3.3.13 - amplify-category-geo@2.3.0 - @aws-amplify/amplify-category-storage@3.1.8 - @aws-amplify/cli@7.6.9 - amplify-console-integration-tests@2.2.17 - amplify-container-hosting@2.4.11 - amplify-dotnet-function-template-provider@2.2.14 - amplify-e2e-core@2.6.0 - amplify-e2e-tests@3.7.0 - @aws-amplify/graphql-auth-transformer@0.5.8 - @aws-amplify/graphql-default-value-transformer@0.5.11 - @aws-amplify/graphql-function-transformer@0.7.6 - @aws-amplify/graphql-http-transformer@0.8.6 - @aws-amplify/graphql-index-transformer@0.8.6 - amplify-graphql-migration-tests@2.2.18 - @aws-amplify/graphql-model-transformer@0.10.6 - @aws-amplify/graphql-predictions-transformer@0.6.6 - @aws-amplify/graphql-relational-transformer@0.6.16 - @aws-amplify/graphql-searchable-transformer@0.10.6 - @aws-amplify/graphql-transformer-core@0.15.5 - @aws-amplify/graphql-transformer-interfaces@1.12.6 - @aws-amplify/graphql-transformer-migrator@1.2.17 - amplify-headless-interface@1.14.0 - amplify-migration-tests@4.4.11 - amplify-nodejs-function-template-provider@2.2.14 - amplify-provider-awscloudformation@5.8.8 - amplify-util-headless-input@1.9.0 - amplify-util-mock@4.2.26 - @aws-amplify/amplify-util-uibuilder@1.2.1 - amplify-velocity-template@1.4.6 - graphql-auth-transformer@7.2.14 - graphql-connection-transformer@5.2.14 - graphql-dynamodb-transformer@7.2.14 - graphql-elasticsearch-transformer@5.2.14 - graphql-function-transformer@3.3.5 - graphql-http-transformer@5.2.14 - graphql-key-transformer@3.2.14 - graphql-predictions-transformer@3.2.14 - graphql-relational-schema-transformer@2.21.3 - graphql-transformer-common@4.22.5 - graphql-transformer-core@7.3.5 - graphql-transformers-e2e-tests@7.3.13 - graphql-versioned-transformer@5.2.14 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4eacddb381..53e61e0fb4 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9a7f29cf02..3a3d9ec322 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.1.10", + "version": "1.2.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.16", + "@aws-amplify/graphql-transformer-migrator": "1.2.17", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -69,16 +69,16 @@ "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", "amplify-cli-core": "2.4.7", - "amplify-headless-interface": "1.13.3", + "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.2", - "amplify-provider-awscloudformation": "5.8.7", - "amplify-util-headless-input": "1.8.3", + "amplify-provider-awscloudformation": "5.8.8", + "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.2", - "graphql-transformer-core": "7.3.4", + "graphql-relational-schema-transformer": "2.21.3", + "graphql-transformer-core": "7.3.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 0b6977a8d02e0ddff50c1c748cb25a086128a4c7 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Thu, 13 Jan 2022 13:43:03 -0800 Subject: [PATCH 532/587] fix(api): container secrets pickup correct environment values (#9513) * fix(api): container secrets pickup correct environment values * lint fix * remove unused code and variables * uncomment actual tests * fix lgtm alerts --- .../awscloudformation/base-api-stack.ts | 2 +- .../utils/containers-artifacts.ts | 13 ++++++++++++- .../utils/containers/set-existing-secret-arns.ts | 15 ++++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) 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 index 7eecf409af..66ebac4376 100644 --- 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 @@ -349,7 +349,7 @@ export abstract class ContainersStack extends cdk.Stack { containerSecrets.forEach((s, i) => { if (secretsArns.has(s)) { - secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretCompleteArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); + secrets[s] = ecs.Secret.fromSecretsManager(ssm.Secret.fromSecretPartialArn(this, `${name}secret${i + 1}`, secretsArns.get(s))); } delete environmentWithoutSecrets[s]; 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 index 05de9ccea5..e411cfcc33 100644 --- 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 @@ -13,6 +13,7 @@ import { $TSAny, $TSContext, JSONUtilities, pathManager, readCFNTemplate } from import { DEPLOYMENT_MECHANISM } from '../base-api-stack'; import { setExistingSecretArns } from './containers/set-existing-secret-arns'; import { category } from '../../../category-constants'; +import * as cdk from '@aws-cdk/core'; export const cfnFileName = (resourceName: string) => `${resourceName}-cloudformation-template.json`; @@ -290,7 +291,17 @@ export async function processDockerConfig( version: uuid(), }); - secretsArns.set(secretName, secretArn); + 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))); 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 index e425a26da5..cc15a1d1fc 100644 --- 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 @@ -1,5 +1,7 @@ import { $TSAny } from 'amplify-cli-core'; import _ from 'lodash'; +import * as cdk from '@aws-cdk/core'; + /** * 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 @@ -38,5 +40,16 @@ export const setExistingSecretArns = (secretsMap: Map, cfnObj: $ .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 => secretsMap.set(secretDef.Name, secretDef.ValueFrom)); // add it to the secretsMap map + .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 }; From 39e2e5a5b2cf232d32461989bb7b532f0205a823 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 20 Jan 2022 00:39:45 +0000 Subject: [PATCH 533/587] chore(release): Publish [ci skip] - amplify-app@4.2.13 - amplify-appsync-simulator@2.3.6 - @aws-amplify/amplify-category-api@1.2.1 - @aws-amplify/cli@7.6.10 - amplify-console-integration-tests@2.2.18 - amplify-container-hosting@2.4.12 - amplify-e2e-core@2.6.1 - amplify-e2e-tests@3.7.1 - amplify-frontend-android@3.3.3 - amplify-frontend-flutter@1.3.3 - amplify-frontend-ios@3.3.12 - amplify-frontend-javascript@3.3.12 - @aws-amplify/graphql-auth-transformer@0.5.9 - @aws-amplify/graphql-default-value-transformer@0.5.12 - @aws-amplify/graphql-function-transformer@0.7.7 - @aws-amplify/graphql-http-transformer@0.8.7 - @aws-amplify/graphql-index-transformer@0.8.7 - amplify-graphql-migration-tests@2.2.19 - @aws-amplify/graphql-model-transformer@0.10.7 - @aws-amplify/graphql-predictions-transformer@0.6.7 - @aws-amplify/graphql-relational-transformer@0.6.17 - @aws-amplify/graphql-searchable-transformer@0.10.7 - @aws-amplify/graphql-transformer-core@0.15.6 - @aws-amplify/graphql-transformer-migrator@1.2.18 - amplify-migration-tests@4.4.12 - amplify-provider-awscloudformation@5.8.9 - amplify-util-mock@4.2.27 - @aws-amplify/amplify-util-uibuilder@1.2.2 - graphql-transformers-e2e-tests@7.3.14 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 53e61e0fb4..ce8825b826 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3a3d9ec322..4bb0f321e1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.0", + "version": "1.2.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.17", + "@aws-amplify/graphql-transformer-migrator": "1.2.18", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -71,7 +71,7 @@ "amplify-cli-core": "2.4.7", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.2", - "amplify-provider-awscloudformation": "5.8.8", + "amplify-provider-awscloudformation": "5.8.9", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", From b17baf4d5301e6506af4322663c63ab9251a0ac9 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Wed, 19 Jan 2022 18:19:16 -0800 Subject: [PATCH 534/587] fix(api): container rest api push treats incorrect initial push behavior (#9556) --- .../awscloudformation/base-api-stack.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) 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 index 66ebac4376..a3b4bca35a 100644 --- 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 @@ -120,7 +120,7 @@ export abstract class ContainersStack extends cdk.Stack { const { pipelineWithAwaiter } = this.pipeline({ skipWait, service, - containersInfo, + containersInfo: containersInfo.filter(container => container.repository), gitHubSourceActionInfo, }); @@ -375,12 +375,10 @@ export abstract class ContainersStack extends cdk.Stack { secrets, }); - if (build) { - containersInfo.push({ - container, - repository, - }); - } + containersInfo.push({ + container, + repository, + }); // TODO: should we use hostPort too? check network mode portMappings?.forEach(({ containerPort, protocol, hostPort }) => { From 16b3fff066ec36252ed8bbec711090c2c5a96712 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 20 Jan 2022 19:23:02 +0000 Subject: [PATCH 535/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.2.2 - @aws-amplify/cli@7.6.11 - amplify-container-hosting@2.4.13 - @aws-amplify/graphql-auth-transformer@0.5.10 - amplify-graphql-migration-tests@2.2.20 - @aws-amplify/graphql-relational-transformer@0.6.18 - amplify-provider-awscloudformation@5.8.10 - amplify-util-mock@4.2.28 - @aws-amplify/amplify-util-uibuilder@1.2.3 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ce8825b826..ea712dce8f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4bb0f321e1..909b0c7565 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.1", + "version": "1.2.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -71,7 +71,7 @@ "amplify-cli-core": "2.4.7", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.2", - "amplify-provider-awscloudformation": "5.8.9", + "amplify-provider-awscloudformation": "5.8.10", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", From cee021d022a66cf7fb1421b568fbc17272f028c4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Sun, 23 Jan 2022 21:10:39 +0000 Subject: [PATCH 536/587] chore(release): Publish [ci skip] - amplify-app@4.2.14 - amplify-category-analytics@3.2.13 - @aws-amplify/amplify-category-api@1.2.3 - @aws-amplify/amplify-category-auth@2.4.10 - @aws-amplify/amplify-category-custom@2.3.12 - amplify-category-function@3.3.14 - amplify-category-geo@2.3.1 - amplify-category-hosting@3.2.13 - amplify-category-interactions@3.2.13 - amplify-category-predictions@3.2.13 - @aws-amplify/amplify-category-storage@3.1.9 - amplify-category-xr@3.2.13 - amplify-cli-core@2.4.8 - @aws-amplify/cli-extensibility-helper@2.3.8 - @aws-amplify/cli@7.6.12 - amplify-console-hosting@2.2.13 - amplify-console-integration-tests@2.2.19 - amplify-container-hosting@2.4.14 - amplify-dotnet-function-template-provider@2.2.15 - amplify-dynamodb-simulator@2.2.13 - amplify-e2e-core@2.6.2 - amplify-e2e-tests@3.7.2 - amplify-frontend-ios@3.3.13 - amplify-frontend-javascript@3.3.13 - amplify-go-function-runtime-provider@2.2.13 - @aws-amplify/graphql-auth-transformer@0.5.11 - amplify-graphql-migration-tests@2.2.21 - @aws-amplify/graphql-relational-transformer@0.6.19 - @aws-amplify/graphql-transformer-migrator@1.2.19 - amplify-java-function-runtime-provider@2.2.13 - amplify-migration-tests@4.4.13 - amplify-nodejs-function-runtime-provider@2.2.13 - amplify-nodejs-function-template-provider@2.2.15 - amplify-provider-awscloudformation@5.8.11 - amplify-python-function-runtime-provider@2.2.13 - amplify-util-import@2.2.13 - amplify-util-mock@4.2.29 - @aws-amplify/amplify-util-uibuilder@1.2.4 - graphql-auth-transformer@7.2.15 - graphql-connection-transformer@5.2.15 - graphql-dynamodb-transformer@7.2.15 - graphql-elasticsearch-transformer@5.2.15 - graphql-function-transformer@3.3.6 - graphql-http-transformer@5.2.15 - graphql-key-transformer@3.2.15 - graphql-predictions-transformer@3.2.15 - graphql-transformer-core@7.3.6 - graphql-transformers-e2e-tests@7.3.15 - graphql-versioned-transformer@5.2.15 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index ea712dce8f..14d5a5328a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 909b0c7565..40d0e63cd1 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.2", + "version": "1.2.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.18", + "@aws-amplify/graphql-transformer-migrator": "1.2.19", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.7", + "amplify-cli-core": "2.4.8", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.2", - "amplify-provider-awscloudformation": "5.8.10", + "amplify-provider-awscloudformation": "5.8.11", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.3", - "graphql-transformer-core": "7.3.5", + "graphql-transformer-core": "7.3.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From ab17d219d8d4b799c9ff5cd6f25af514d3f36760 Mon Sep 17 00:00:00 2001 From: Attila Hajdrik Date: Mon, 24 Jan 2022 11:13:49 -0800 Subject: [PATCH 537/587] fix: handle auth and api dependency in state files correctly (#9528) * fix: #9341 correctly create dependsOn between api and auth * test: fix unit test * chore: address feedback --- .../cfn-api-artifact-handler.ts | 82 ++++++++++++++++++- 1 file changed, 79 insertions(+), 3 deletions(-) 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 index 097e974297..377aaa5003 100644 --- 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 @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, $TSObject, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, @@ -23,6 +23,12 @@ import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-aut import { printApiKeyWarnings } from './utils/print-api-key-warnings'; import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-conflict-resolution-bi-di-mapper'; +type DependsOnEntry = { + category: string; + resourceName: string; + attributes: Array; +}; + // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -96,7 +102,9 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { authConfig, }); - this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig)); + const dependsOn: Array = this.createDependsOnFromAuthConfig(authConfig); + + this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig, dependsOn)); return serviceConfig.apiName; }; @@ -140,6 +148,45 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); + + // If we have cognito configured now but before update it was not there then add dependsOn for the API + if (this.hasCognitoAuthMode(authConfig) && !this.hasCognitoAuthMode(previousAuthConfig)) { + const dependsOn: Array = this.createDependsOnFromAuthConfig(authConfig); + const authResourceName = checkIfAuthExists(); + + if (dependsOn) { + const existingDependsOn = _.get(stateManager.getMeta(), [category, apiName, 'dependsOn'], []); + + // If existing dependsOn does not have a cognito dependsOn entry then add it, otherwise skip update + if (existingDependsOn.find(dep => dep.category === 'auth' && dep.resourceName === authResourceName) === undefined) { + // There is always a single entry in the constructed dependsOn array + existingDependsOn.push(dependsOn[0]); + + this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'dependsOn', dependsOn); + } + } + } else if (!this.hasCognitoAuthMode(authConfig) && this.hasCognitoAuthMode(previousAuthConfig)) { + // If previously we had cognito configured but now we don't then remove dependsOn for the API + + let existingDependsOn: Array<$TSObject> = _.get(stateManager.getMeta(), [category, apiName, 'dependsOn'], []); + const authResourceName = checkIfAuthExists(); + + const existingAuthDependencyIndex = existingDependsOn.findIndex( + dep => dep.category === 'auth' && dep.resourceName === authResourceName, + ); + + if (existingDependsOn && existingAuthDependencyIndex >= 0) { + existingDependsOn.splice(existingAuthDependencyIndex, 1); + + // To be consistent set the object to undefined if no entries left in it before writing it back to the meta + if (existingDependsOn.length === 0) { + existingDependsOn = undefined; + } + + this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'dependsOn', existingDependsOn); + } + } + printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; @@ -149,9 +196,10 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); - private createAmplifyMeta = authConfig => ({ + private createAmplifyMeta = (authConfig, dependsOn: DependsOnEntry[] | undefined) => ({ service: 'AppSync', providerPlugin: provider, + dependsOn, output: { authConfig, }, @@ -318,6 +366,34 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await cliState.saveCLIInputPayload(appsyncInputs); return appsyncInputs; }; + + private createDependsOnFromAuthConfig(authConfig: { defaultAuthentication: any; additionalAuthenticationProviders: any[] }) { + let dependsOn: Array; + + if (this.hasCognitoAuthMode(authConfig)) { + // get the auth resource name + const authResourceName = checkIfAuthExists(); + + if (authResourceName) { + dependsOn = [ + { + category: 'auth', + resourceName: authResourceName, + attributes: ['UserPoolId'], + }, + ]; + } + } + + return dependsOn; + } + + private hasCognitoAuthMode(authConfig: { defaultAuthentication: any; additionalAuthenticationProviders: any[] }) { + return ( + authConfig?.defaultAuthentication?.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || + authConfig?.additionalAuthenticationProviders?.find(aap => aap.authenticationType === 'AMAZON_COGNITO_USER_POOLS') !== undefined + ); + } } /** From 928277489e40e9524afc9e8da556dc420b2cd886 Mon Sep 17 00:00:00 2001 From: Colin Ihrig Date: Tue, 25 Jan 2022 11:07:04 -0500 Subject: [PATCH 538/587] Revert "fix: handle auth and api dependency in state files correctly (#9528)" (#9602) This reverts commit ab17d219d8d4b799c9ff5cd6f25af514d3f36760. This was causing widespread failures in the E2E test suite. Co-authored-by: Colin Ihrig --- .../cfn-api-artifact-handler.ts | 82 +------------------ 1 file changed, 3 insertions(+), 79 deletions(-) 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 index 377aaa5003..097e974297 100644 --- 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 @@ -1,4 +1,4 @@ -import { $TSAny, $TSContext, $TSObject, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, @@ -23,12 +23,6 @@ import { appSyncAuthTypeToAuthConfig } from './utils/auth-config-to-app-sync-aut import { printApiKeyWarnings } from './utils/print-api-key-warnings'; import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-conflict-resolution-bi-di-mapper'; -type DependsOnEntry = { - category: string; - resourceName: string; - attributes: Array; -}; - // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; @@ -102,9 +96,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { authConfig, }); - const dependsOn: Array = this.createDependsOnFromAuthConfig(authConfig); - - this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig, dependsOn)); + this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig)); return serviceConfig.apiName; }; @@ -148,45 +140,6 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'output', { authConfig }); this.context.amplify.updateBackendConfigAfterResourceUpdate(category, apiName, 'output', { authConfig }); - - // If we have cognito configured now but before update it was not there then add dependsOn for the API - if (this.hasCognitoAuthMode(authConfig) && !this.hasCognitoAuthMode(previousAuthConfig)) { - const dependsOn: Array = this.createDependsOnFromAuthConfig(authConfig); - const authResourceName = checkIfAuthExists(); - - if (dependsOn) { - const existingDependsOn = _.get(stateManager.getMeta(), [category, apiName, 'dependsOn'], []); - - // If existing dependsOn does not have a cognito dependsOn entry then add it, otherwise skip update - if (existingDependsOn.find(dep => dep.category === 'auth' && dep.resourceName === authResourceName) === undefined) { - // There is always a single entry in the constructed dependsOn array - existingDependsOn.push(dependsOn[0]); - - this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'dependsOn', dependsOn); - } - } - } else if (!this.hasCognitoAuthMode(authConfig) && this.hasCognitoAuthMode(previousAuthConfig)) { - // If previously we had cognito configured but now we don't then remove dependsOn for the API - - let existingDependsOn: Array<$TSObject> = _.get(stateManager.getMeta(), [category, apiName, 'dependsOn'], []); - const authResourceName = checkIfAuthExists(); - - const existingAuthDependencyIndex = existingDependsOn.findIndex( - dep => dep.category === 'auth' && dep.resourceName === authResourceName, - ); - - if (existingDependsOn && existingAuthDependencyIndex >= 0) { - existingDependsOn.splice(existingAuthDependencyIndex, 1); - - // To be consistent set the object to undefined if no entries left in it before writing it back to the meta - if (existingDependsOn.length === 0) { - existingDependsOn = undefined; - } - - this.context.amplify.updateamplifyMetaAfterResourceUpdate(category, apiName, 'dependsOn', existingDependsOn); - } - } - printApiKeyWarnings(oldConfigHadApiKey, authConfigHasApiKey(authConfig)); }; @@ -196,10 +149,9 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); - private createAmplifyMeta = (authConfig, dependsOn: DependsOnEntry[] | undefined) => ({ + private createAmplifyMeta = authConfig => ({ service: 'AppSync', providerPlugin: provider, - dependsOn, output: { authConfig, }, @@ -366,34 +318,6 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await cliState.saveCLIInputPayload(appsyncInputs); return appsyncInputs; }; - - private createDependsOnFromAuthConfig(authConfig: { defaultAuthentication: any; additionalAuthenticationProviders: any[] }) { - let dependsOn: Array; - - if (this.hasCognitoAuthMode(authConfig)) { - // get the auth resource name - const authResourceName = checkIfAuthExists(); - - if (authResourceName) { - dependsOn = [ - { - category: 'auth', - resourceName: authResourceName, - attributes: ['UserPoolId'], - }, - ]; - } - } - - return dependsOn; - } - - private hasCognitoAuthMode(authConfig: { defaultAuthentication: any; additionalAuthenticationProviders: any[] }) { - return ( - authConfig?.defaultAuthentication?.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || - authConfig?.additionalAuthenticationProviders?.find(aap => aap.authenticationType === 'AMAZON_COGNITO_USER_POOLS') !== undefined - ); - } } /** From 842a75b2fa8bc393011f8b2c61ecf3459b503a85 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Tue, 25 Jan 2022 11:36:46 -0800 Subject: [PATCH 539/587] fix: rest api override CloudFormation parameters (#9325) * fix: improve error handling for overrides * fix: (#9221) new addCfnParameterValue for REST override * test: add e2e test for api override.ts with parameter * chore: add optional arg for api override addCfnParameter * chore: update eslint ignore * fix: remove preceeding underscore from paths key * Revert "chore: update eslint ignore" This reverts commit e9cf3d9cf860eb5f359dcbc9fa151827593b8b51. * fix: address PR feedback --- .../cdk-stack-builder/apigw-stack-builder.ts | 41 ++++++++++++++----- .../apigw-stack-transform.ts | 28 ++++++------- 2 files changed, 44 insertions(+), 25 deletions(-) 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 index 9a4a236bdc..8ed37d7f56 100644 --- 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 @@ -12,20 +12,23 @@ 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 { - _scope: cdk.Construct; - restApi!: apigw.CfnRestApi; + restApi: apigw.CfnRestApi; deploymentResource: apigw.CfnDeployment; - _lambdaPermission: lambda.CfnPermission; - _props: ApigwInputs; paths: $TSObject; policies: { [pathName: string]: ApigwPathPolicy }; - _cfnParameterMap: Map = new Map(); + private _scope: cdk.Construct; + private _props: ApigwInputs; + private _cfnParameterMap: Map = new Map(); + private _cfnParameterValues: $TSObject; + private _seenLogicalIds: Set; constructor(scope: cdk.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; @@ -37,6 +40,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * @param logicalId */ addCfnOutput(props: cdk.CfnOutputProps, logicalId: string): void { + this.validateLogicalId(logicalId); new cdk.CfnOutput(this, logicalId, props); } @@ -46,6 +50,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * @param logicalId */ addCfnMapping(props: cdk.CfnMappingProps, logicalId: string): void { + this.validateLogicalId(logicalId); new cdk.CfnMapping(this, logicalId, props); } @@ -55,6 +60,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * @param logicalId */ addCfnCondition(props: cdk.CfnConditionProps, logicalId: string): void { + this.validateLogicalId(logicalId); new cdk.CfnCondition(this, logicalId, props); } @@ -64,6 +70,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * @param logicalId */ addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void { + this.validateLogicalId(logicalId); new cdk.CfnResource(this, logicalId, props); } @@ -72,7 +79,8 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * @param props * @param logicalId */ - addLambdaPermissionCfnResource(props: lambda.CfnPermissionProps, logicalId: string): void { + addCfnLambdaPermissionResource(props: lambda.CfnPermissionProps, logicalId: string): void { + this.validateLogicalId(logicalId); new lambda.CfnPermission(this, logicalId, props); } @@ -80,12 +88,25 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw * * @param props * @param logicalId + * @param value optional value which will be stored in parameters.json */ - addCfnParameter(props: cdk.CfnParameterProps, logicalId: string): void { - if (this._cfnParameterMap.has(logicalId)) { + addCfnParameter(props: cdk.CfnParameterProps, logicalId: string, value?: string | $TSObject): 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._cfnParameterMap.set(logicalId, new cdk.CfnParameter(this, logicalId, props)); + this._seenLogicalIds.add(logicalId); } private _craftPolicyDocument(apiResourceName: string, pathName: string, supportedOperations: string[]) { @@ -273,7 +294,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw if (!addedFunctionPermissions.has(path.lambdaFunction)) { addedFunctionPermissions.add(path.lambdaFunction); - this.addLambdaPermissionCfnResource( + this.addCfnLambdaPermissionResource( { functionName: cdk.Fn.ref(`function${path.lambdaFunction}Name`), action: 'lambda:InvokeFunction', 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 index 8299ca64f5..ba912aa78d 100644 --- 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 @@ -1,6 +1,5 @@ import * as cdk from '@aws-cdk/core'; import { - $TSAny, $TSContext, $TSObject, AmplifyCategories, @@ -21,13 +20,13 @@ import { AmplifyApigwResourceStack, ApigwInputs, CrudOperation, Path } from '.'; import { ApigwInputState } from '../apigw-input-state'; import { ADMIN_QUERIES_NAME } from '../../../category-constants'; export class ApigwStackTransform { - _app: cdk.App; cliInputs: ApigwInputs; resourceTemplateObj: AmplifyApigwResourceStack | undefined; cliInputsState: ApigwInputState; - cfn!: Template; - cfnInputParams!: $TSObject; + cfn: Template; + cfnInputParams: $TSObject; resourceName: string; + private _app: cdk.App; constructor(context: $TSContext, resourceName: string, cliInputState?: ApigwInputState) { this._app = new cdk.App(); @@ -51,18 +50,23 @@ export class ApigwStackTransform { // Generate cloudformation stack from cli-inputs.json this.generateStack(authResourceName, pathsWithUserPoolGroups); + try { + // Modify cloudformation files based on overrides + await this.applyOverrides(); + } catch (error) { + printer.error(`Failed to override ${this.resourceName} due to: ${error}.`); + return; + } + // Generate cloudformation stack input params from cli-inputs.json this.generateCfnInputParameters(); - // Modify cloudformation files based on overrides - await this.applyOverrides(); - // Save generated cloudformation.json and parameters.json files await this.saveBuildFiles(); } generateCfnInputParameters() { - this.cfnInputParams = {}; + this.cfnInputParams = this.resourceTemplateObj.getCfnParameterValues(); } generateStack(authResourceName?: string, pathsWithUserPoolGroups: [string, Path][] = []) { @@ -211,13 +215,7 @@ export class ApigwStackTransform { }, }); - try { - await sandboxNode.run(overrideCode, overrideJSFilePath).override(this.resourceTemplateObj as AmplifyApigwResourceStack); - } catch (err: $TSAny) { - const error = new Error(`Skipping override due to ${err}.`); - printer.error(`${error}`); - throw error; - } + await sandboxNode.run(overrideCode, overrideJSFilePath).override(this.resourceTemplateObj as AmplifyApigwResourceStack); } } } From 1c67bd185f3387f273393efa5b56b8870389d0a4 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 27 Jan 2022 00:10:45 +0000 Subject: [PATCH 540/587] chore(release): Publish [ci skip] - amplify-app@4.2.15 - amplify-category-analytics@3.2.14 - @aws-amplify/amplify-category-api@1.2.4 - @aws-amplify/amplify-category-auth@2.4.11 - @aws-amplify/amplify-category-custom@2.3.13 - amplify-category-function@3.3.15 - amplify-category-geo@2.3.4 - amplify-category-hosting@3.2.14 - amplify-category-interactions@3.2.14 - amplify-category-predictions@3.2.14 - @aws-amplify/amplify-category-storage@3.1.10 - amplify-category-xr@3.2.14 - amplify-cli-core@2.4.9 - @aws-amplify/cli-extensibility-helper@2.3.9 - @aws-amplify/cli@7.6.13 - amplify-console-hosting@2.2.14 - amplify-console-integration-tests@2.2.20 - amplify-container-hosting@2.4.15 - amplify-dotnet-function-template-provider@2.2.16 - amplify-dynamodb-simulator@2.2.14 - amplify-e2e-core@2.6.3 - amplify-e2e-tests@3.7.3 - amplify-frontend-ios@3.3.14 - amplify-frontend-javascript@3.3.14 - amplify-go-function-runtime-provider@2.2.14 - @aws-amplify/graphql-auth-transformer@0.5.12 - @aws-amplify/graphql-default-value-transformer@0.5.13 - @aws-amplify/graphql-function-transformer@0.7.8 - @aws-amplify/graphql-http-transformer@0.8.8 - @aws-amplify/graphql-index-transformer@0.8.8 - amplify-graphql-migration-tests@2.2.22 - @aws-amplify/graphql-model-transformer@0.10.8 - @aws-amplify/graphql-predictions-transformer@0.6.8 - @aws-amplify/graphql-relational-transformer@0.6.20 - @aws-amplify/graphql-schema-test-library@1.0.1 - @aws-amplify/graphql-searchable-transformer@0.10.8 - @aws-amplify/graphql-transformer-core@0.15.7 - @aws-amplify/graphql-transformer-migrator@1.2.20 - amplify-java-function-runtime-provider@2.2.14 - amplify-migration-tests@4.4.14 - amplify-nodejs-function-runtime-provider@2.2.14 - amplify-nodejs-function-template-provider@2.2.16 - amplify-prompts@1.6.3 - amplify-provider-awscloudformation@5.8.12 - amplify-python-function-runtime-provider@2.2.14 - amplify-util-import@2.2.14 - amplify-util-mock@4.2.30 - @aws-amplify/amplify-util-uibuilder@1.2.5 - graphql-auth-transformer@7.2.16 - graphql-connection-transformer@5.2.16 - graphql-dynamodb-transformer@7.2.16 - graphql-elasticsearch-transformer@5.2.16 - graphql-function-transformer@3.3.7 - graphql-http-transformer@5.2.16 - graphql-key-transformer@3.2.16 - graphql-predictions-transformer@3.2.16 - graphql-transformer-core@7.3.7 - graphql-transformers-e2e-tests@7.3.16 - graphql-versioned-transformer@5.2.16 --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 14d5a5328a..9b6a00b2f3 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 40d0e63cd1..5ca170883f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.3", + "version": "1.2.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.19", + "@aws-amplify/graphql-transformer-migrator": "1.2.20", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.8", + "amplify-cli-core": "2.4.9", "amplify-headless-interface": "1.14.0", - "amplify-prompts": "1.6.2", - "amplify-provider-awscloudformation": "5.8.11", + "amplify-prompts": "1.6.3", + "amplify-provider-awscloudformation": "5.8.12", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.3", - "graphql-transformer-core": "7.3.6", + "graphql-transformer-core": "7.3.7", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 3101a09ce1dbb244649c5e1c224323505e0a3646 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 31 Jan 2022 19:23:31 +0000 Subject: [PATCH 541/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.2.5 - amplify-category-function@3.4.0 - @aws-amplify/cli@7.6.14 - amplify-console-integration-tests@2.2.21 - amplify-container-hosting@2.4.16 - amplify-dotnet-function-template-provider@2.2.17 - amplify-e2e-core@2.6.4 - amplify-e2e-tests@3.7.4 - @aws-amplify/graphql-auth-transformer@0.7.0 - @aws-amplify/graphql-default-value-transformer@0.5.14 - @aws-amplify/graphql-function-transformer@0.7.9 - @aws-amplify/graphql-http-transformer@0.8.9 - @aws-amplify/graphql-index-transformer@0.11.0 - @aws-amplify/graphql-maps-to-transformer@1.1.0 - amplify-graphql-migration-tests@2.2.23 - @aws-amplify/graphql-model-transformer@0.13.0 - @aws-amplify/graphql-predictions-transformer@0.6.9 - @aws-amplify/graphql-relational-transformer@0.7.0 - @aws-amplify/graphql-schema-test-library@1.0.2 - @aws-amplify/graphql-searchable-transformer@0.13.0 - @aws-amplify/graphql-transformer-core@0.16.0 - @aws-amplify/graphql-transformer-interfaces@1.13.0 - @aws-amplify/graphql-transformer-migrator@1.2.21 - amplify-migration-tests@4.4.15 - amplify-nodejs-function-template-provider@2.2.17 - amplify-provider-awscloudformation@5.9.0 - amplify-util-mock@4.3.0 - @aws-amplify/amplify-util-uibuilder@1.2.6 - graphql-auth-transformer@7.2.17 - graphql-connection-transformer@5.2.17 - graphql-dynamodb-transformer@7.2.17 - graphql-elasticsearch-transformer@5.2.17 - graphql-function-transformer@3.3.8 - graphql-http-transformer@5.2.17 - graphql-key-transformer@3.2.17 - graphql-predictions-transformer@3.2.17 - graphql-relational-schema-transformer@2.21.4 - graphql-transformer-common@4.23.0 - graphql-transformer-core@7.4.0 - graphql-transformers-e2e-tests@7.4.0 - graphql-versioned-transformer@5.2.17 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 9b6a00b2f3..c30ea30c22 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5ca170883f..08976683aa 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.4", + "version": "1.2.5", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.20", + "@aws-amplify/graphql-transformer-migrator": "1.2.21", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -71,14 +71,14 @@ "amplify-cli-core": "2.4.9", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.8.12", + "amplify-provider-awscloudformation": "5.9.0", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.3", - "graphql-transformer-core": "7.3.7", + "graphql-relational-schema-transformer": "2.21.4", + "graphql-transformer-core": "7.4.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 282d77bd9742b097b7c023c32a575c30a3fa2bd2 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 3 Feb 2022 00:53:57 +0000 Subject: [PATCH 542/587] chore(release): Publish [ci skip] - amplify-app@4.2.16 - amplify-category-analytics@3.2.15 - @aws-amplify/amplify-category-api@1.2.6 - @aws-amplify/amplify-category-auth@2.4.12 - @aws-amplify/amplify-category-custom@2.3.14 - amplify-category-function@3.4.1 - amplify-category-geo@2.3.5 - amplify-category-hosting@3.2.15 - amplify-category-interactions@3.2.15 - amplify-category-predictions@3.2.15 - @aws-amplify/amplify-category-storage@3.1.11 - amplify-category-xr@3.2.15 - amplify-cli-core@2.4.10 - @aws-amplify/cli-extensibility-helper@2.3.10 - @aws-amplify/cli@7.6.15 - amplify-console-hosting@2.2.15 - amplify-console-integration-tests@2.2.22 - amplify-container-hosting@2.4.17 - amplify-dotnet-function-template-provider@2.2.18 - amplify-dynamodb-simulator@2.2.15 - amplify-e2e-core@2.6.5 - amplify-e2e-tests@3.7.5 - amplify-frontend-ios@3.3.15 - amplify-frontend-javascript@3.3.15 - amplify-go-function-runtime-provider@2.2.15 - @aws-amplify/graphql-auth-transformer@0.7.1 - @aws-amplify/graphql-maps-to-transformer@1.1.1 - amplify-graphql-migration-tests@2.2.24 - @aws-amplify/graphql-relational-transformer@0.7.1 - @aws-amplify/graphql-schema-test-library@1.0.3 - @aws-amplify/graphql-transformer-migrator@1.2.22 - amplify-java-function-runtime-provider@2.2.15 - amplify-migration-tests@4.4.16 - amplify-nodejs-function-runtime-provider@2.2.15 - amplify-nodejs-function-template-provider@2.2.18 - amplify-provider-awscloudformation@5.9.1 - amplify-python-function-runtime-provider@2.2.15 - amplify-util-import@2.2.15 - amplify-util-mock@4.3.1 - @aws-amplify/amplify-util-uibuilder@1.2.7 - graphql-auth-transformer@7.2.18 - graphql-connection-transformer@5.2.18 - graphql-dynamodb-transformer@7.2.18 - graphql-elasticsearch-transformer@5.2.18 - graphql-function-transformer@3.3.9 - graphql-http-transformer@5.2.18 - graphql-key-transformer@3.2.18 - graphql-predictions-transformer@3.2.18 - graphql-transformer-core@7.4.1 - graphql-transformers-e2e-tests@7.4.1 - graphql-versioned-transformer@5.2.18 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index c30ea30c22..e85c8cf664 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 08976683aa..a3601abb78 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.5", + "version": "1.2.6", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.21", + "@aws-amplify/graphql-transformer-migrator": "1.2.22", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.9", + "amplify-cli-core": "2.4.10", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.0", + "amplify-provider-awscloudformation": "5.9.1", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.0", + "graphql-transformer-core": "7.4.1", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From a4d9800a84922ddc0c3f15ae5f47a5af68bd7dfc Mon Sep 17 00:00:00 2001 From: Yathi <511386+yuth@users.noreply.github.com> Date: Tue, 8 Feb 2022 13:58:09 -0800 Subject: [PATCH 543/587] chore: fix versions to align with last beta release (#9716) --- packages/amplify-category-api/package.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a3601abb78..03b39949a3 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.6", + "version": "1.2.9", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.22", + "@aws-amplify/graphql-transformer-migrator": "1.2.25", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.10", + "amplify-cli-core": "2.4.13", "amplify-headless-interface": "1.14.0", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.1", + "amplify-provider-awscloudformation": "5.9.4", "amplify-util-headless-input": "1.9.0", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.1", + "graphql-transformer-core": "7.4.4", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From d624ca739bc89a54539984e3f07a3e96d3cad5f2 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 10 Feb 2022 02:34:28 +0000 Subject: [PATCH 544/587] chore(release): Publish [ci skip] - amplify-app@4.2.20 - amplify-appsync-simulator@2.3.7 - amplify-category-analytics@3.2.19 - @aws-amplify/amplify-category-api@1.2.10 - @aws-amplify/amplify-category-auth@2.5.0 - @aws-amplify/amplify-category-custom@2.3.18 - amplify-category-function@3.5.0 - amplify-category-geo@2.3.9 - amplify-category-hosting@3.2.19 - amplify-category-interactions@3.2.19 - amplify-category-notifications@2.19.5 - amplify-category-predictions@3.2.19 - @aws-amplify/amplify-category-storage@3.1.15 - amplify-category-xr@3.2.19 - amplify-cli-core@2.4.14 - @aws-amplify/cli-extensibility-helper@2.3.14 - @aws-amplify/cli@7.6.19 - amplify-console-hosting@2.2.19 - amplify-console-integration-tests@2.2.26 - amplify-container-hosting@2.4.21 - amplify-dotnet-function-runtime-provider@1.6.7 - amplify-dotnet-function-template-provider@2.2.22 - amplify-dynamodb-simulator@2.2.19 - amplify-e2e-core@2.6.9 - amplify-e2e-tests@3.7.9 - amplify-frontend-ios@3.3.19 - amplify-frontend-javascript@3.3.19 - amplify-go-function-runtime-provider@2.2.19 - amplify-graphiql-explorer@2.4.4 - @aws-amplify/graphql-auth-transformer@0.7.5 - @aws-amplify/graphql-default-value-transformer@0.5.15 - @aws-amplify/graphql-maps-to-transformer@1.1.5 - amplify-graphql-migration-tests@2.2.28 - @aws-amplify/graphql-relational-transformer@0.7.5 - @aws-amplify/graphql-schema-test-library@1.0.7 - @aws-amplify/graphql-searchable-transformer@0.13.1 - @aws-amplify/graphql-transformer-migrator@1.2.26 - amplify-headless-interface@1.14.1 - amplify-java-function-runtime-provider@2.2.19 - amplify-migration-tests@4.4.20 - amplify-nodejs-function-runtime-provider@2.2.19 - amplify-nodejs-function-template-provider@2.3.0 - amplify-provider-awscloudformation@5.9.5 - amplify-python-function-runtime-provider@2.2.19 - amplify-storage-simulator@1.6.4 - amplify-util-headless-input@1.9.1 - amplify-util-import@2.2.19 - amplify-util-mock@4.3.5 - @aws-amplify/amplify-util-uibuilder@1.2.11 - graphql-auth-transformer@7.2.22 - graphql-connection-transformer@5.2.22 - graphql-dynamodb-transformer@7.2.22 - graphql-elasticsearch-transformer@5.2.22 - graphql-function-transformer@3.3.13 - graphql-http-transformer@5.2.22 - graphql-key-transformer@3.2.22 - graphql-predictions-transformer@3.2.22 - graphql-transformer-core@7.4.5 - graphql-transformers-e2e-tests@7.4.5 - graphql-versioned-transformer@5.2.22 --- packages/amplify-category-api/CHANGELOG.md | 12 ++++++++++++ packages/amplify-category-api/package.json | 14 +++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index e85c8cf664..f26f1d61e7 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,18 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 03b39949a3..d2f782b6d7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.9", + "version": "1.2.10", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.25", + "@aws-amplify/graphql-transformer-migrator": "1.2.26", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.13", - "amplify-headless-interface": "1.14.0", + "amplify-cli-core": "2.4.14", + "amplify-headless-interface": "1.14.1", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.4", - "amplify-util-headless-input": "1.9.0", + "amplify-provider-awscloudformation": "5.9.5", + "amplify-util-headless-input": "1.9.1", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.4", + "graphql-transformer-core": "7.4.5", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 3a89db898694afbb63ce9bea9a916794b2f4f81c Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 15 Feb 2022 19:44:36 +0000 Subject: [PATCH 545/587] chore(release): Publish [ci skip] - amplify-app@4.2.21 - amplify-category-analytics@3.2.20 - @aws-amplify/amplify-category-api@1.2.11 - @aws-amplify/amplify-category-auth@2.7.2 - @aws-amplify/amplify-category-custom@2.3.19 - amplify-category-function@3.5.1 - amplify-category-geo@2.4.0 - amplify-category-hosting@3.2.20 - amplify-category-interactions@3.2.20 - amplify-category-predictions@3.2.20 - @aws-amplify/amplify-category-storage@3.1.16 - amplify-category-xr@3.2.20 - amplify-cli-core@2.4.15 - @aws-amplify/cli-extensibility-helper@2.3.15 - @aws-amplify/cli@7.6.20 - amplify-console-hosting@2.2.20 - amplify-console-integration-tests@2.2.27 - amplify-container-hosting@2.4.22 - amplify-dotnet-function-template-provider@2.2.23 - amplify-dynamodb-simulator@2.2.20 - amplify-e2e-core@2.6.10 - amplify-e2e-tests@3.7.10 - amplify-frontend-ios@3.3.20 - amplify-frontend-javascript@3.3.20 - amplify-go-function-runtime-provider@2.2.20 - @aws-amplify/graphql-auth-transformer@0.7.6 - @aws-amplify/graphql-default-value-transformer@0.5.16 - @aws-amplify/graphql-function-transformer@0.7.10 - @aws-amplify/graphql-http-transformer@0.8.10 - @aws-amplify/graphql-index-transformer@0.11.1 - @aws-amplify/graphql-maps-to-transformer@1.1.6 - amplify-graphql-migration-tests@2.2.29 - @aws-amplify/graphql-model-transformer@0.13.1 - @aws-amplify/graphql-predictions-transformer@0.6.10 - @aws-amplify/graphql-relational-transformer@0.7.6 - @aws-amplify/graphql-schema-test-library@1.0.8 - @aws-amplify/graphql-searchable-transformer@0.13.2 - @aws-amplify/graphql-transformer-core@0.16.1 - @aws-amplify/graphql-transformer-migrator@1.2.27 - amplify-java-function-runtime-provider@2.2.20 - amplify-migration-tests@4.4.21 - amplify-nodejs-function-runtime-provider@2.2.20 - amplify-nodejs-function-template-provider@2.3.4 - amplify-provider-awscloudformation@5.9.6 - amplify-python-function-runtime-provider@2.2.20 - amplify-util-import@2.2.20 - amplify-util-mock@4.3.6 - @aws-amplify/amplify-util-uibuilder@1.2.12 - graphql-auth-transformer@7.2.23 - graphql-connection-transformer@5.2.23 - graphql-dynamodb-transformer@7.2.23 - graphql-elasticsearch-transformer@5.2.23 - graphql-function-transformer@3.3.14 - graphql-http-transformer@5.2.23 - graphql-key-transformer@3.2.23 - graphql-predictions-transformer@3.2.23 - graphql-transformer-core@7.4.6 - graphql-transformers-e2e-tests@7.4.6 - graphql-versioned-transformer@5.2.23 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f26f1d61e7..1a2f83f62d 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d2f782b6d7..d33a6157d2 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.10", + "version": "1.2.11", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.26", + "@aws-amplify/graphql-transformer-migrator": "1.2.27", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.14", + "amplify-cli-core": "2.4.15", "amplify-headless-interface": "1.14.1", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.5", + "amplify-provider-awscloudformation": "5.9.6", "amplify-util-headless-input": "1.9.1", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.5", + "graphql-transformer-core": "7.4.6", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 23fdc4b9da7ed509f557acc4b154d04e1cebfd61 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 18 Feb 2022 00:09:01 +0000 Subject: [PATCH 546/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.2.12 - @aws-amplify/cli@7.6.21 - amplify-console-integration-tests@2.2.28 - amplify-container-hosting@2.4.23 - amplify-e2e-core@2.6.11 - amplify-e2e-tests@3.7.11 - amplify-migration-tests@4.4.22 - amplify-provider-awscloudformation@5.9.7 - amplify-util-mock@4.3.7 - @aws-amplify/amplify-util-uibuilder@1.2.13 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 1a2f83f62d..66309422fe 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index d33a6157d2..9d120dfe84 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.11", + "version": "1.2.12", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -71,7 +71,7 @@ "amplify-cli-core": "2.4.15", "amplify-headless-interface": "1.14.1", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.6", + "amplify-provider-awscloudformation": "5.9.7", "amplify-util-headless-input": "1.9.1", "chalk": "^4.1.1", "constructs": "^3.3.125", From 2c05116d5bf5103417f326ebd7e3385f4195334f Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Thu, 24 Feb 2022 07:50:20 -0800 Subject: [PATCH 547/587] test(api): update container flask requirements.txt (#9844) --- .../dockercompose-rest-express/python/requirements.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 index 0f2af12d22..1a04a5d60c 100644 --- 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 @@ -1 +1,2 @@ -Flask==1.1.1 \ No newline at end of file +Flask==1.1.2 +itsdangerous==2.0.1 \ No newline at end of file From 2ad6545c286eb85f316e84171cc76fb921f77941 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 25 Feb 2022 06:02:38 +0000 Subject: [PATCH 548/587] chore(release): Publish [ci skip] - amplify-app@4.2.22 - amplify-appsync-simulator@2.3.8 - amplify-category-analytics@3.2.21 - @aws-amplify/amplify-category-api@1.2.13 - @aws-amplify/amplify-category-auth@2.7.3 - @aws-amplify/amplify-category-custom@2.3.20 - amplify-category-function@3.5.2 - amplify-category-geo@2.4.1 - amplify-category-hosting@3.2.21 - amplify-category-interactions@3.2.21 - amplify-category-notifications@2.19.6 - amplify-category-predictions@3.2.21 - @aws-amplify/amplify-category-storage@3.1.17 - amplify-category-xr@3.2.21 - amplify-cli-core@2.4.16 - @aws-amplify/cli-extensibility-helper@2.3.16 - @aws-amplify/cli@7.6.22 - amplify-console-hosting@2.2.21 - amplify-console-integration-tests@2.2.29 - amplify-container-hosting@2.4.24 - amplify-dotnet-function-runtime-provider@1.6.8 - amplify-dotnet-function-template-provider@2.2.24 - amplify-dynamodb-simulator@2.2.21 - amplify-e2e-core@2.6.12 - amplify-e2e-tests@3.7.12 - amplify-frontend-ios@3.3.21 - amplify-frontend-javascript@3.3.21 - amplify-go-function-runtime-provider@2.2.21 - amplify-graphiql-explorer@2.4.5 - @aws-amplify/graphql-auth-transformer@0.7.7 - @aws-amplify/graphql-default-value-transformer@0.5.17 - @aws-amplify/graphql-function-transformer@0.7.11 - @aws-amplify/graphql-http-transformer@0.8.11 - @aws-amplify/graphql-index-transformer@0.11.2 - @aws-amplify/graphql-maps-to-transformer@1.1.7 - amplify-graphql-migration-tests@2.2.30 - @aws-amplify/graphql-model-transformer@0.13.2 - @aws-amplify/graphql-predictions-transformer@0.6.11 - @aws-amplify/graphql-relational-transformer@0.7.7 - @aws-amplify/graphql-schema-test-library@1.0.9 - @aws-amplify/graphql-searchable-transformer@0.13.3 - @aws-amplify/graphql-transformer-core@0.16.2 - @aws-amplify/graphql-transformer-migrator@1.2.28 - amplify-java-function-runtime-provider@2.2.21 - amplify-migration-tests@4.4.23 - amplify-nodejs-function-runtime-provider@2.2.21 - amplify-nodejs-function-template-provider@2.3.5 - amplify-provider-awscloudformation@5.9.8 - amplify-python-function-runtime-provider@2.2.21 - amplify-storage-simulator@1.6.5 - amplify-util-headless-input@1.9.2 - amplify-util-import@2.2.21 - amplify-util-mock@4.3.8 - @aws-amplify/amplify-util-uibuilder@1.2.14 - graphql-auth-transformer@7.2.24 - graphql-connection-transformer@5.2.24 - graphql-dynamodb-transformer@7.2.24 - graphql-elasticsearch-transformer@5.2.24 - graphql-function-transformer@3.3.15 - graphql-http-transformer@5.2.24 - graphql-key-transformer@3.2.24 - graphql-predictions-transformer@3.2.24 - graphql-transformer-core@7.4.7 - graphql-transformers-e2e-tests@7.4.7 - graphql-versioned-transformer@5.2.24 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 66309422fe..82f1c809e5 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 9d120dfe84..e34705022c 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.12", + "version": "1.2.13", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.27", + "@aws-amplify/graphql-transformer-migrator": "1.2.28", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.15", + "amplify-cli-core": "2.4.16", "amplify-headless-interface": "1.14.1", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.7", - "amplify-util-headless-input": "1.9.1", + "amplify-provider-awscloudformation": "5.9.8", + "amplify-util-headless-input": "1.9.2", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.6", + "graphql-transformer-core": "7.4.7", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From c1592132e0a5f1df4df4094ff2617596b6d1519a Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 25 Feb 2022 12:34:57 -0800 Subject: [PATCH 549/587] fix(amplify-category-api): surface override build errors for REST APIs (#9804) --- .../apigw-stack-transform.ts | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) 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 index ba912aa78d..33107c029d 100644 --- 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 @@ -186,23 +186,26 @@ export class ApigwStackTransform { const overrideFilePath = pathManager.getResourceDirectoryPath(undefined, AmplifyCategories.API, this.resourceName); const overrideJSFilePath = path.join(overrideFilePath, 'build', 'override.js'); - const isBuild = await buildOverrideDir(backendDir, overrideFilePath).catch(error => { - printer.debug(`Build error : ${error.message}`); - return false; - }); + const isBuild = await buildOverrideDir(backendDir, overrideFilePath); // skip if packageManager or override.ts not found if (isBuild) { - const { override } = await import(overrideJSFilePath).catch(error => { + let override; + try { + ({ override } = await import(overrideJSFilePath)); + } catch { formatter.list(['No override file found', `To override ${this.resourceName} run "amplify override api"`]); - return undefined; - }); + override = undefined; + } if (override && typeof override === 'function') { - const overrideCode: string = await fs.readFile(overrideJSFilePath, 'utf-8').catch(() => { - formatter.list(['No override File Found', `To override ${this.resourceName} run amplify override auth`]); - return ''; - }); + let overrideCode: string; + try { + overrideCode = await fs.readFile(overrideJSFilePath, 'utf-8'); + } catch (error) { + formatter.list(['No override file found', `To override ${this.resourceName} run amplify override auth`]); + return; + } const sandboxNode = new vm.NodeVM({ console: 'inherit', From 679071e589cf24e1ccd5e248e719d125844ab1a8 Mon Sep 17 00:00:00 2001 From: John Corser Date: Fri, 4 Mar 2022 01:02:39 -0500 Subject: [PATCH 550/587] Update ui builder dependencies (#9904) * chore: add git secrets husky hook * chore: studio q1 release poc * chore: update pkgjson * chore: remove logs * chore: add shouldUseQ1Release logic * chore: remove unneeded logs and imports * chore: update dependency notification message * chore: fix semver comparison * chore: use aws-sdk 2.1084.0 * chore: use dev dependency * chore: use dev dependency * chore: remove extraneous scan * chore: clean up any types * chore: use same aws-sdk version everywhere * chore: remove redundant passthrough * chore: fix build types Co-authored-by: John Corser --- .../dockercompose-rest-express/express/package.json | 2 +- .../container-templates/dockerfile-rest-express/package.json | 2 +- .../container-templates/graphql-express/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index 98a3659067..8986f5d776 100644 --- 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 @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1084.0", "axios": "^0.21.4", "body-parser": "^1.19.0", "express": "^4.17.1", 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 index 9c72bb598f..ef470caec3 100644 --- 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 @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1084.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 index ee61e94075..6517c17a7e 100644 --- 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 @@ -7,7 +7,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.845.0", + "aws-sdk": "^2.1084.0", "express": "^4.17.1", "express-graphql": "^0.11.0", "graphql": "^15.4.0" From 336e82303ac4129d12ad81cffccc6fd9e0c2b8d7 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 7 Mar 2022 16:24:49 +0000 Subject: [PATCH 551/587] chore(release): Publish [ci skip] - amplify-app@4.2.23 - amplify-appsync-simulator@2.3.9 - amplify-category-analytics@3.2.22 - @aws-amplify/amplify-category-api@1.2.14 - @aws-amplify/amplify-category-auth@2.7.4 - @aws-amplify/amplify-category-custom@2.3.21 - amplify-category-function@3.5.3 - amplify-category-geo@2.4.2 - amplify-category-hosting@3.2.22 - amplify-category-interactions@3.2.22 - amplify-category-predictions@3.2.22 - @aws-amplify/amplify-category-storage@3.1.18 - amplify-category-xr@3.2.22 - amplify-cli-core@2.4.17 - @aws-amplify/cli-extensibility-helper@2.3.17 - @aws-amplify/cli@7.6.23 - amplify-console-hosting@2.2.22 - amplify-console-integration-tests@2.2.30 - amplify-container-hosting@2.4.25 - amplify-dotnet-function-template-provider@2.2.25 - amplify-dynamodb-simulator@2.2.22 - amplify-e2e-core@2.6.13 - amplify-e2e-tests@3.7.13 - amplify-frontend-ios@3.3.22 - amplify-frontend-javascript@3.3.22 - amplify-go-function-runtime-provider@2.2.22 - @aws-amplify/graphql-auth-transformer@0.7.8 - @aws-amplify/graphql-maps-to-transformer@1.1.8 - amplify-graphql-migration-tests@2.2.31 - @aws-amplify/graphql-relational-transformer@0.7.8 - @aws-amplify/graphql-schema-test-library@1.0.10 - @aws-amplify/graphql-searchable-transformer@0.13.4 - @aws-amplify/graphql-transformer-migrator@1.2.29 - amplify-headless-interface@1.14.2 - amplify-java-function-runtime-provider@2.2.22 - amplify-migration-tests@4.4.24 - amplify-nodejs-function-runtime-provider@2.2.22 - amplify-nodejs-function-template-provider@2.3.6 - amplify-provider-awscloudformation@5.9.9 - amplify-python-function-runtime-provider@2.2.22 - amplify-storage-simulator@1.6.6 - amplify-util-headless-input@1.9.3 - amplify-util-import@2.2.22 - amplify-util-mock@4.3.9 - @aws-amplify/amplify-util-uibuilder@1.2.15 - amplify-velocity-template@1.4.7 - graphql-auth-transformer@7.2.25 - graphql-connection-transformer@5.2.25 - graphql-dynamodb-transformer@7.2.25 - graphql-elasticsearch-transformer@5.2.25 - graphql-function-transformer@3.3.16 - graphql-http-transformer@5.2.25 - graphql-key-transformer@3.2.25 - graphql-predictions-transformer@3.2.25 - graphql-relational-schema-transformer@2.21.5 - graphql-transformer-core@7.4.8 - graphql-transformers-e2e-tests@7.4.8 - graphql-versioned-transformer@5.2.25 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 16 ++++++++-------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 82f1c809e5..7bd4ec967f 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index e34705022c..1fd547bc6a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.13", + "version": "1.2.14", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.28", + "@aws-amplify/graphql-transformer-migrator": "1.2.29", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.16", - "amplify-headless-interface": "1.14.1", + "amplify-cli-core": "2.4.17", + "amplify-headless-interface": "1.14.2", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.8", - "amplify-util-headless-input": "1.9.2", + "amplify-provider-awscloudformation": "5.9.9", + "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.4", - "graphql-transformer-core": "7.4.7", + "graphql-relational-schema-transformer": "2.21.5", + "graphql-transformer-core": "7.4.8", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 9f1a9df9fc4c34a13d00359be4f38ae3f4d29a21 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Tue, 8 Mar 2022 09:43:00 -0800 Subject: [PATCH 552/587] fix: allow api updates without migration (#9864) --- .../cfn-api-artifact-handler.test.ts | 1 + packages/amplify-category-api/src/index.ts | 5 +--- .../cfn-api-artifact-handler.ts | 23 ++++++++++++++----- .../appSync-walkthrough.ts | 5 +--- 4 files changed, 20 insertions(+), 14 deletions(-) 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 index e2f66dce43..c541802382 100644 --- 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 @@ -260,6 +260,7 @@ describe('update artifacts', () => { 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', diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 9e3c79e6ca..21513a3a4d 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -240,10 +240,7 @@ export const executeAmplifyHeadlessCommand = async (context: $TSContext, headles break; case 'update': const resourceName = await getAppSyncApiResourceName(context); - if (!(await checkAppsyncApiResourceMigration(context, resourceName, true))) { - printer.error('Update operations only work on migrated projects. Run "amplify update api" and opt for migration.'); - exitOnNextTick(0); - } + await checkAppsyncApiResourceMigration(context, resourceName, true); await getCfnApiArtifactHandler(context).updateArtifacts(await validateUpdateApiRequest(headlessPayload)); break; default: 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 index 097e974297..e52ba7b64a 100644 --- 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 @@ -110,12 +110,12 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { } const resourceDir = this.getResourceDir(apiName); // update appsync cli-inputs - const appsyncCLIInputs = await this.updateAppsyncCLIInputs(updates, apiName); + const gqlSchemaPath = await this.updateAppsyncCLIInputs(updates, apiName); if (updates.transformSchema) { - this.writeSchema(appsyncCLIInputs.serviceConfiguration.gqlSchemaPath, updates.transformSchema); + this.writeSchema(gqlSchemaPath, updates.transformSchema); } if (updates.conflictResolution) { - updates.conflictResolution = await this.createResolverResources(appsyncCLIInputs.serviceConfiguration.conflictResolution); + updates.conflictResolution = await this.createResolverResources(updates.conflictResolution); await writeResolverConfig(updates.conflictResolution, resourceDir); } @@ -298,13 +298,24 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { return appsyncCLIInputs; }; - private updateAppsyncCLIInputs = async (updates: AppSyncServiceModification, apiName: string) => { + /** + * If the resource is migrated, updates cli-inputs.json with the specified updates + * If not migrated, this method is a noop (but still returns the schema path) + * @param updates The updates to apply + * @param apiName The api name + * @returns The gqlSchemaPath + */ + private updateAppsyncCLIInputs = async (updates: AppSyncServiceModification, apiName: string): Promise => { const cliState = new AppsyncApiInputState(apiName); + const gqlSchemaPath = path.join(this.getResourceDir(apiName), gqlSchemaFilename); + if (!cliState.cliInputFileExists()) { + return gqlSchemaPath; + } const prevAppsyncInputs = cliState.getCLIInputPayload(); const appsyncInputs: AppSyncCLIInputs = prevAppsyncInputs; if (!_.isEmpty(appsyncInputs.serviceConfiguration)) { - appsyncInputs.serviceConfiguration.gqlSchemaPath = path.join(this.getResourceDir(apiName), gqlSchemaFilename); + appsyncInputs.serviceConfiguration.gqlSchemaPath = gqlSchemaPath; } if (updates.conflictResolution) { appsyncInputs.serviceConfiguration.conflictResolution = updates.conflictResolution; @@ -316,7 +327,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { appsyncInputs.serviceConfiguration.additionalAuthTypes = updates.additionalAuthTypes; } await cliState.saveCLIInputPayload(appsyncInputs); - return appsyncInputs; + return gqlSchemaPath; }; } 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 index 12c1fa9500..89e0f0dc75 100644 --- 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 @@ -463,10 +463,7 @@ export const updateWalkthrough = async (context: $TSContext): Promise Date: Wed, 9 Mar 2022 15:11:35 -0800 Subject: [PATCH 553/587] fix: split policies for both legacy and migrated REST APIs (#9572) --- .../convert-deprecated-apigw-paths.test.ts | 73 +++++++++++++++ packages/amplify-category-api/src/index.ts | 1 + .../awscloudformation/apigw-input-state.ts | 88 +----------------- .../apigw-stack-transform.ts | 2 +- .../cdk-stack-builder/types.ts | 2 +- .../convert-deprecated-apigw-paths.ts | 92 +++++++++++++++++++ 6 files changed, 173 insertions(+), 85 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts create mode 100644 packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts 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 new file mode 100644 index 0000000000..45bfc7bfb6 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/provider-utils/awscloudformation/convert-deprecated-apigw-paths.test.ts @@ -0,0 +1,73 @@ +import { JSONUtilities } from 'amplify-cli-core'; + +jest.mock('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/index.ts b/packages/amplify-category-api/src/index.ts index 21513a3a4d..779aef8fc8 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -24,6 +24,7 @@ import { getAppSyncApiResourceName } from './provider-utils/awscloudformation/ut 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'; +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'; 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 index 599c08a022..321c1b0fb7 100644 --- 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 @@ -11,10 +11,11 @@ import { pathManager, stateManager, } from 'amplify-cli-core'; -import { printer, prompter } from 'amplify-prompts'; +import { prompter } from 'amplify-prompts'; import * as fs from 'fs-extra'; import { join } from 'path'; 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 { @@ -49,7 +50,7 @@ export class ApigwInputState { dependsOn: adminQueriesProps.dependsOn, }; - await this.context.amplify.updateamplifyMetaAfterResourceAdd(AmplifyCategories.API, adminQueriesProps.apiName, backendConfigs); + this.context.amplify.updateamplifyMetaAfterResourceAdd(AmplifyCategories.API, adminQueriesProps.apiName, backendConfigs); }; public updateAdminQueriesResource = async (adminQueriesProps: AdminQueriesProps) => { @@ -66,7 +67,7 @@ export class ApigwInputState { await this.createApigwArtifacts(); - await this.context.amplify.updateamplifyMetaAfterResourceUpdate( + this.context.amplify.updateamplifyMetaAfterResourceUpdate( AmplifyCategories.API, adminQueriesProps.apiName, 'dependsOn', @@ -122,86 +123,7 @@ export class ApigwInputState { const deprecatedParametersFileName = 'api-params.json'; const resourceDirPath = pathManager.getResourceDirectoryPath(this.projectRootPath, AmplifyCategories.API, this.resourceName); const deprecatedParametersFilePath = join(resourceDirPath, deprecatedParametersFileName); - let deprecatedParameters: $TSObject; - try { - deprecatedParameters = JSONUtilities.readJson<$TSObject>(deprecatedParametersFilePath); - } catch (e) { - printer.error(`Error reading ${deprecatedParametersFileName} file for ${this.resourceName} resource`); - throw e; - } - - this.paths = {}; - - function _convertDeprecatedPermissionStringToCRUD(deprecatedPrivacy: string) { - let privacyList: string[]; - 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]))); - } - - 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: $TSObject) => { - 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); - } - } - } - - this.paths[path.name] = { - permissions: { - setting: pathPermissionSetting, - auth, - guest, - groups, - }, - lambdaFunction: path.lambdaFunction, - }; - }); + this.paths = convertDeperecatedRestApiPaths(deprecatedParametersFileName, deprecatedParametersFilePath, this.resourceName); fs.removeSync(deprecatedParametersFilePath); fs.removeSync(join(resourceDirPath, PathConstants.ParametersJsonFileName)); 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 index 33107c029d..ed58328806 100644 --- 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 @@ -203,7 +203,7 @@ export class ApigwStackTransform { try { overrideCode = await fs.readFile(overrideJSFilePath, 'utf-8'); } catch (error) { - formatter.list(['No override file found', `To override ${this.resourceName} run amplify override auth`]); + formatter.list(['No override file found', `To override ${this.resourceName} run amplify override api`]); return; } 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 index 4a3a8e0b67..ffd5d459e7 100644 --- 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 @@ -34,7 +34,7 @@ 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): void; + addCfnParameter(props: cdk.CfnParameterProps, logicalId: string, value?: any): void; addCfnResource(props: cdk.CfnResourceProps, logicalId: string): void; }; 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 new file mode 100644 index 0000000000..8e956d7f77 --- /dev/null +++ b/packages/amplify-category-api/src/provider-utils/awscloudformation/convert-deprecated-apigw-paths.ts @@ -0,0 +1,92 @@ +import { $TSObject, JSONUtilities } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import { CrudOperation, PermissionSetting } from './cdk-stack-builder/types'; + +export function convertDeperecatedRestApiPaths( + deprecatedParametersFileName: string, + deprecatedParametersFilePath: string, + resourceName: string, +) { + let deprecatedParameters: $TSObject; + try { + deprecatedParameters = JSONUtilities.readJson<$TSObject>(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: $TSObject) => { + 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]))); +} From 449a7d2e4b2f7d810a88801e0b5f6714b16219b6 Mon Sep 17 00:00:00 2001 From: Marc VandenBerg Date: Wed, 9 Mar 2022 18:12:48 -0500 Subject: [PATCH 554/587] fix(amplify-category-api): remove stack trace from printout for api (#9877) --- packages/amplify-category-api/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index 779aef8fc8..f27f52ee9a 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -226,7 +226,7 @@ export async function executeAmplifyCommand(context: $TSContext) { if (error) { printer.error(error.message || error); if (error.stack) { - printer.info(error.stack); + printer.debug(error.stack); } await context.usageData.emitError(error); } From 9df6f44466b2832fd07022f45f9e0ac12610d484 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 14 Mar 2022 21:01:16 +0000 Subject: [PATCH 555/587] chore(release): Publish [ci skip] - amplify-app@4.2.24 - amplify-appsync-simulator@2.3.10 - amplify-category-analytics@3.2.23 - @aws-amplify/amplify-category-api@1.2.15 - @aws-amplify/amplify-category-auth@2.7.5 - @aws-amplify/amplify-category-custom@2.3.22 - amplify-category-function@3.5.4 - amplify-category-geo@2.4.3 - amplify-category-hosting@3.2.23 - amplify-category-interactions@3.2.23 - amplify-category-predictions@3.2.23 - @aws-amplify/amplify-category-storage@3.1.19 - amplify-category-xr@3.2.23 - amplify-cli-core@2.4.18 - @aws-amplify/cli-extensibility-helper@2.3.18 - @aws-amplify/cli@7.6.24 - amplify-console-hosting@2.2.23 - amplify-console-integration-tests@2.2.31 - amplify-container-hosting@2.4.26 - amplify-dotnet-function-template-provider@2.2.26 - amplify-dynamodb-simulator@2.2.23 - amplify-e2e-core@2.6.14 - amplify-e2e-tests@3.7.14 - amplify-frontend-ios@3.3.23 - amplify-frontend-javascript@3.3.23 - amplify-go-function-runtime-provider@2.2.23 - amplify-graphql-migration-tests@2.2.32 - @aws-amplify/graphql-transformer-migrator@1.2.30 - amplify-java-function-runtime-provider@2.2.23 - amplify-migration-tests@4.4.25 - amplify-nodejs-function-runtime-provider@2.2.23 - amplify-nodejs-function-template-provider@2.3.7 - amplify-provider-awscloudformation@5.9.10 - amplify-python-function-runtime-provider@2.2.23 - amplify-util-import@2.2.23 - amplify-util-mock@4.3.10 - @aws-amplify/amplify-util-uibuilder@1.2.16 - graphql-auth-transformer@7.2.26 - graphql-connection-transformer@5.2.26 - graphql-dynamodb-transformer@7.2.26 - graphql-elasticsearch-transformer@5.2.26 - graphql-function-transformer@3.3.17 - graphql-http-transformer@5.2.26 - graphql-key-transformer@3.2.26 - graphql-predictions-transformer@3.2.26 - graphql-transformer-core@7.4.9 - graphql-transformers-e2e-tests@7.4.9 - graphql-versioned-transformer@5.2.26 --- packages/amplify-category-api/CHANGELOG.md | 13 +++++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 7bd4ec967f..57fb0e8acb 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 1fd547bc6a..8b1a71d723 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.14", + "version": "1.2.15", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.29", + "@aws-amplify/graphql-transformer-migrator": "1.2.30", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.17", + "amplify-cli-core": "2.4.18", "amplify-headless-interface": "1.14.2", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.9", + "amplify-provider-awscloudformation": "5.9.10", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.8", + "graphql-transformer-core": "7.4.9", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 70df622f36238ba3cc303a3e4698d7093efc0587 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Thu, 17 Mar 2022 17:44:36 +0000 Subject: [PATCH 556/587] chore(release): Publish [ci skip] - @aws-amplify/amplify-category-api@1.2.16 - @aws-amplify/amplify-category-auth@2.7.6 - @aws-amplify/amplify-category-custom@2.3.23 - amplify-category-function@3.5.5 - @aws-amplify/amplify-category-storage@3.1.20 - @aws-amplify/cli-extensibility-helper@2.3.19 - @aws-amplify/cli@7.6.25 - amplify-console-integration-tests@2.2.32 - amplify-container-hosting@2.4.27 - amplify-dotnet-function-template-provider@2.2.27 - amplify-e2e-core@2.6.15 - amplify-e2e-tests@3.7.15 - @aws-amplify/graphql-auth-transformer@0.7.9 - @aws-amplify/graphql-maps-to-transformer@1.1.9 - amplify-graphql-migration-tests@2.2.33 - @aws-amplify/graphql-relational-transformer@0.7.9 - @aws-amplify/graphql-schema-test-library@1.0.11 - amplify-migration-tests@4.4.26 - amplify-nodejs-function-template-provider@2.3.8 - amplify-provider-awscloudformation@5.9.11 - amplify-util-mock@4.3.11 - @aws-amplify/amplify-util-uibuilder@1.2.17 - graphql-auth-transformer@7.2.27 - graphql-connection-transformer@5.2.27 - graphql-dynamodb-transformer@7.2.27 - graphql-elasticsearch-transformer@5.2.27 - graphql-function-transformer@3.3.18 - graphql-http-transformer@5.2.27 - graphql-key-transformer@3.2.27 - graphql-predictions-transformer@3.2.27 - graphql-transformer-core@7.4.10 - graphql-transformers-e2e-tests@7.4.10 - graphql-versioned-transformer@5.2.27 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 57fb0e8acb..f90bf21b10 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8b1a71d723..7b9bc45775 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.15", + "version": "1.2.16", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -71,14 +71,14 @@ "amplify-cli-core": "2.4.18", "amplify-headless-interface": "1.14.2", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.10", + "amplify-provider-awscloudformation": "5.9.11", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.9", + "graphql-transformer-core": "7.4.10", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From d3638595164291e680f3bd0b45ebe2662030b4af Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 23 Mar 2022 04:48:43 +0000 Subject: [PATCH 557/587] chore(release): Publish [ci skip] - amplify-app@4.2.25 - amplify-category-analytics@3.2.24 - @aws-amplify/amplify-category-api@1.2.17 - @aws-amplify/amplify-category-auth@2.7.7 - @aws-amplify/amplify-category-custom@2.3.24 - amplify-category-function@3.5.6 - amplify-category-geo@2.4.4 - amplify-category-hosting@3.2.24 - amplify-category-interactions@3.2.24 - amplify-category-predictions@3.2.24 - @aws-amplify/amplify-category-storage@3.1.21 - amplify-category-xr@3.2.24 - amplify-cli-core@2.5.0 - @aws-amplify/cli-extensibility-helper@2.3.20 - @aws-amplify/cli@7.6.26 - amplify-console-hosting@2.2.24 - amplify-console-integration-tests@2.2.33 - amplify-container-hosting@2.4.28 - amplify-dotnet-function-template-provider@2.2.28 - amplify-dynamodb-simulator@2.2.24 - amplify-e2e-core@2.6.16 - amplify-e2e-tests@3.7.16 - amplify-frontend-ios@3.3.24 - amplify-frontend-javascript@3.3.24 - amplify-go-function-runtime-provider@2.2.24 - @aws-amplify/graphql-auth-transformer@0.7.10 - @aws-amplify/graphql-default-value-transformer@0.5.18 - @aws-amplify/graphql-function-transformer@0.7.12 - @aws-amplify/graphql-http-transformer@0.8.12 - @aws-amplify/graphql-index-transformer@0.11.3 - @aws-amplify/graphql-maps-to-transformer@1.1.10 - amplify-graphql-migration-tests@2.2.34 - @aws-amplify/graphql-model-transformer@0.13.3 - @aws-amplify/graphql-predictions-transformer@0.6.12 - @aws-amplify/graphql-relational-transformer@0.7.10 - @aws-amplify/graphql-schema-test-library@1.0.12 - @aws-amplify/graphql-searchable-transformer@0.13.5 - @aws-amplify/graphql-transformer-core@0.16.3 - @aws-amplify/graphql-transformer-migrator@1.2.31 - amplify-java-function-runtime-provider@2.2.24 - amplify-migration-tests@4.4.27 - amplify-nodejs-function-runtime-provider@2.2.24 - amplify-nodejs-function-template-provider@2.3.9 - amplify-provider-awscloudformation@5.9.12 - amplify-python-function-runtime-provider@2.2.24 - amplify-util-import@2.2.24 - amplify-util-mock@4.3.12 - @aws-amplify/amplify-util-uibuilder@1.2.18 - graphql-auth-transformer@7.2.28 - graphql-connection-transformer@5.2.28 - graphql-dynamodb-transformer@7.2.28 - graphql-elasticsearch-transformer@5.2.28 - graphql-function-transformer@3.3.19 - graphql-http-transformer@5.2.28 - graphql-key-transformer@3.2.28 - graphql-predictions-transformer@3.2.28 - graphql-transformer-core@7.4.11 - graphql-transformers-e2e-tests@7.4.11 - graphql-versioned-transformer@5.2.28 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f90bf21b10..221e036985 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7b9bc45775..a1851042e7 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.16", + "version": "1.2.17", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.30", + "@aws-amplify/graphql-transformer-migrator": "1.2.31", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.4.18", + "amplify-cli-core": "2.5.0", "amplify-headless-interface": "1.14.2", "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.11", + "amplify-provider-awscloudformation": "5.9.12", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.10", + "graphql-transformer-core": "7.4.11", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 4df2e94042599a67b973f9f1cb043368d919a923 Mon Sep 17 00:00:00 2001 From: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> Date: Mon, 28 Mar 2022 12:18:16 -0700 Subject: [PATCH 558/587] fix(container-api): upgrade flask version for the python api (#10077) --- .../dockercompose-rest-express/python/requirements.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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 index 1a04a5d60c..fb0dec5b66 100644 --- 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 @@ -1,2 +1 @@ -Flask==1.1.2 -itsdangerous==2.0.1 \ No newline at end of file +Flask==2.0.3 \ No newline at end of file From 16b4358ea95af395bbad4e46bc23f45805c26a44 Mon Sep 17 00:00:00 2001 From: John Corser Date: Mon, 4 Apr 2022 17:04:57 -0400 Subject: [PATCH 559/587] fix: use prompter and handle deletions (#10122) BREAKING CHANGE: package name update requires version bump in order to keep in sync with lerna. --- .../service-walkthroughs/appSync-rds-walkthrough.ts | 12 ++++-------- .../service-walkthroughs/appSync-walkthrough.ts | 10 +++++++--- 2 files changed, 11 insertions(+), 11 deletions(-) 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 index 10d0b2eac0..b522c226e5 100644 --- 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 @@ -1,8 +1,7 @@ import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError } from 'amplify-cli-core'; -import { printer } from 'amplify-prompts'; +import { printer, prompter } from 'amplify-prompts'; import chalk from 'chalk'; import { DataApiParams } from 'graphql-relational-schema-transformer'; -import inquirer from 'inquirer'; import ora from 'ora'; const spinner = ora(''); @@ -237,16 +236,13 @@ async function selectDatabase(context: $TSContext, inputs, clusterArn, secretArn * @param {*} choicesList */ async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) { - const question = [ - { + const question = { type: inputs[questionNumber].type, name: inputs[questionNumber].key, message: inputs[questionNumber].question, choices: choicesList, - }, - ]; - - const answer = await inquirer.prompt(question); + }; + const answer = await prompter.pick(question.message, choicesList) return answer[inputs[questionNumber].key]; } 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 index 89e0f0dc75..9aa0764d90 100644 --- 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 @@ -13,7 +13,7 @@ import { getGraphQLTransformerAuthDocLink, } from 'amplify-cli-core'; import { UpdateApiRequest } from 'amplify-headless-interface'; -import { printer } from 'amplify-prompts'; +import { printer, prompter } from 'amplify-prompts'; import chalk from 'chalk'; import * as fs from 'fs-extra'; import { collectDirectivesByTypeNames, readProjectConfiguration } from 'graphql-transformer-core'; @@ -817,7 +817,7 @@ async function askUserPoolQuestions(context: $TSContext) { export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { let defaultValues = { apiKeyExpirationDays: 7, - description: undefined, + description: '', }; Object.assign(defaultValues, authSettings?.apiKeyConfig); @@ -845,9 +845,13 @@ export async function askApiKeyQuestions(authSettings: $TSObject = undefined) { }, ]; - const apiKeyConfig = await inquirer.prompt(apiKeyQuestions); + const apiKeyConfig: $TSObject = {}; + 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', From dfcff1cdfe1b4cb2a3a0bb499920a042b5d03cab Mon Sep 17 00:00:00 2001 From: John Corser Date: Thu, 7 Apr 2022 15:13:56 -0400 Subject: [PATCH 560/587] chore(release): Publish [ci skip] (#10154) Co-authored-by: John Corser --- packages/amplify-category-api/CHANGELOG.md | 17 +++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 221e036985..f00a0a4290 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,23 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a1851042e7..a19eb0b07a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "1.2.17", + "version": "2.0.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.31", + "@aws-amplify/graphql-transformer-migrator": "1.2.32", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.5.0", + "amplify-cli-core": "2.5.1", "amplify-headless-interface": "1.14.2", - "amplify-prompts": "1.6.3", - "amplify-provider-awscloudformation": "5.9.12", + "amplify-prompts": "2.0.0", + "amplify-provider-awscloudformation": "6.0.0", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.11", + "graphql-transformer-core": "7.4.12", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 71c5857b69715f718e24ea7fb4f2d07ce64bc5b0 Mon Sep 17 00:00:00 2001 From: John Corser Date: Thu, 7 Apr 2022 16:37:57 -0400 Subject: [PATCH 561/587] chore(release): Publish [ci skip] (#10157) - amplify-app@4.2.26 - amplify-category-analytics@4.0.0 - @aws-amplify/amplify-category-api@2.0.0 - @aws-amplify/amplify-category-auth@2.7.8 - @aws-amplify/amplify-category-custom@2.3.25 - amplify-category-function@4.0.0 - amplify-category-geo@2.4.5 - amplify-category-hosting@3.2.25 - amplify-category-interactions@4.0.0 - amplify-category-predictions@4.0.0 - @aws-amplify/amplify-category-storage@3.1.22 - amplify-category-xr@3.2.25 - amplify-cli-core@2.5.1 - @aws-amplify/cli-extensibility-helper@2.3.21 - @aws-amplify/cli@8.0.0 - @aws-amplify/cli-internal@8.0.0 - amplify-console-hosting@2.2.25 - amplify-console-integration-tests@2.2.34 - amplify-container-hosting@2.4.29 - amplify-dotnet-function-template-provider@2.2.29 - amplify-dynamodb-simulator@2.2.25 - amplify-e2e-core@3.0.0 - amplify-e2e-tests@3.7.17 - amplify-frontend-ios@3.3.25 - amplify-frontend-javascript@3.3.25 - amplify-go-function-runtime-provider@2.2.25 - @aws-amplify/graphql-auth-transformer@0.7.11 - @aws-amplify/graphql-default-value-transformer@0.5.19 - @aws-amplify/graphql-function-transformer@0.7.13 - @aws-amplify/graphql-http-transformer@0.8.13 - @aws-amplify/graphql-index-transformer@0.11.4 - @aws-amplify/graphql-maps-to-transformer@1.1.11 - amplify-graphql-migration-tests@2.2.35 - @aws-amplify/graphql-model-transformer@0.13.4 - @aws-amplify/graphql-predictions-transformer@0.6.13 - @aws-amplify/graphql-relational-transformer@0.7.11 - @aws-amplify/graphql-schema-test-library@1.0.13 - @aws-amplify/graphql-searchable-transformer@0.13.6 - @aws-amplify/graphql-transformer-core@0.16.4 - @aws-amplify/graphql-transformer-migrator@1.2.32 - amplify-java-function-runtime-provider@2.2.25 - amplify-migration-tests@4.4.28 - amplify-nodejs-function-runtime-provider@2.2.25 - amplify-nodejs-function-template-provider@2.3.10 - amplify-prompts@2.0.0 - amplify-provider-awscloudformation@6.0.0 - amplify-python-function-runtime-provider@2.2.25 - amplify-util-import@2.2.25 - amplify-util-mock@4.3.13 - @aws-amplify/amplify-util-uibuilder@1.2.19 - graphql-auth-transformer@7.2.29 - graphql-connection-transformer@5.2.29 - graphql-dynamodb-transformer@7.2.29 - graphql-elasticsearch-transformer@5.2.29 - graphql-function-transformer@3.3.20 - graphql-http-transformer@5.2.29 - graphql-key-transformer@3.2.29 - graphql-predictions-transformer@3.2.29 - graphql-transformer-core@7.4.12 - graphql-transformers-e2e-tests@7.4.12 - graphql-versioned-transformer@5.2.29 From c27656fc97a70cd72f746ad0ed689da82fecaea5 Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Thu, 7 Apr 2022 14:03:44 -0700 Subject: [PATCH 562/587] fix: api sets auth dependency correctly in meta files (#10072) * fix: add dependsOn when API is using cognito auth * fix: special case logic for api deployment params * fix: artifact-handler test * test: add tests to artifact handler --- .../cfn-api-artifact-handler.test.ts | 153 +++++++++------ .../cfn-api-artifact-handler.ts | 174 +++++++++++++----- 2 files changed, 227 insertions(+), 100 deletions(-) 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 index c541802382..dfef8a6a40 100644 --- 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 @@ -1,11 +1,11 @@ -import { AppsyncApiInputState } from '../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; -import { $TSContext, pathManager, stateManager } from 'amplify-cli-core'; +import { $TSContext, pathManager } from 'amplify-cli-core'; import { AddApiRequest, UpdateApiRequest } from 'amplify-headless-interface'; import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; import { writeTransformerConfiguration } from 'graphql-transformer-core'; import _ from 'lodash'; import * as path from 'path'; +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'; @@ -16,9 +16,11 @@ import { getAppSyncResourceName, } from '../../../provider-utils/awscloudformation/utils/amplify-meta-utils'; +const testAuthId = 'testAuthId'; + jest.mock('fs-extra'); -const printer_mock = printer as jest.Mocked; -printer_mock.warn = jest.fn(); +const printerMock = printer as jest.Mocked; +printerMock.warn = jest.fn(); jest.mock('../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'); @@ -28,7 +30,7 @@ jest.mock('graphql-transformer-core', () => ({ })); jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', () => ({ - checkIfAuthExists: jest.fn(), + checkIfAuthExists: jest.fn().mockImplementation(() => testAuthId), getAppSyncResourceName: jest.fn(() => testApiName), getAppSyncAuthConfig: jest.fn(() => ({})), authConfigHasApiKey: jest.fn(() => true), @@ -37,11 +39,12 @@ jest.mock('../../../provider-utils/awscloudformation/utils/amplify-meta-utils', jest.mock('amplify-cli-core', () => ({ pathManager: { - getBackendDirPath: jest.fn().mockReturnValue('mockbackendDirPath'), + getBackendDirPath: jest.fn().mockReturnValue('mockBackendDirPath'), findProjectRoot: jest.fn().mockReturnValue('mockProject'), }, stateManager: { getMeta: jest.fn().mockReturnValue({}), + getBackendConfig: jest.fn(), }, AmplifyCategories: { API: 'api', @@ -59,17 +62,16 @@ jest.mock('amplify-cli-core', () => ({ const backendDirPathStub = 'backendDirPath'; const testApiName = 'testApiName'; -const pathManager_mock = pathManager as jest.Mocked; -pathManager_mock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); -const stateManager_mock = stateManager as jest.Mocked; +const pathManagerMock = pathManager as jest.Mocked; +pathManagerMock.getResourceDirectoryPath = jest.fn().mockReturnValue(`${backendDirPathStub}/api/${testApiName}`); -const fs_mock = fs as unknown as jest.Mocked; -const writeTransformerConfiguration_mock = writeTransformerConfiguration as jest.MockedFunction; -const getAppSyncResourceName_mock = getAppSyncResourceName as jest.MockedFunction; -const getAppSyncAuthConfig_mock = getAppSyncAuthConfig as jest.MockedFunction; -const authConfigHasApiKey_mock = authConfigHasApiKey as jest.MockedFunction; +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 context_stub = { +const contextStub = { amplify: { updateamplifyMetaAfterResourceAdd: jest.fn(), updateamplifyMetaAfterResourceUpdate: jest.fn(), @@ -95,40 +97,40 @@ describe('create artifacts', () => { }, }; beforeAll(() => { - fs_mock.existsSync.mockImplementation(() => false); - getAppSyncResourceName_mock.mockImplementation(() => undefined); + fsMock.existsSync.mockImplementation(() => false); + getAppSyncResourceNameMock.mockImplementation(() => undefined); }); beforeEach(() => { jest.clearAllMocks(); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); + cfnApiArtifactHandler = getCfnApiArtifactHandler((contextStub as unknown) as $TSContext); }); it('does not create a second API if one already exists', async () => { - getAppSyncResourceName_mock.mockImplementationOnce(() => testApiName); + getAppSyncResourceNameMock.mockImplementationOnce(() => testApiName); return expect(cfnApiArtifactHandler.createArtifacts(addRequestStub)).rejects.toMatchInlineSnapshot( - `[Error: GraphQL API testApiName already exists in the project. Use 'amplify update api' to make modifications.]`, + "[Error: GraphQL API testApiName already exists in the project. Use 'amplify update api' to make modifications.]", ); }); it('creates the correct directories', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fs_mock.ensureDirSync.mock.calls.length).toBe(1); - expect(fs_mock.ensureDirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName)); - expect(fs_mock.mkdirSync.mock.calls.length).toBe(2); - expect(fs_mock.mkdirSync.mock.calls[0][0]).toBe(path.join(backendDirPathStub, category, testApiName, 'resolvers')); - expect(fs_mock.mkdirSync.mock.calls[1][0]).toBe(path.join(backendDirPathStub, category, testApiName, 'stacks')); + 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(writeTransformerConfiguration_mock.mock.calls.length).toBe(2); - expect(writeTransformerConfiguration_mock.mock.calls[0]).toMatchSnapshot(); + 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(fs_mock.copyFileSync.mock.calls.length).toBe(2); - expect(fs_mock.copyFileSync.mock.calls[1]).toEqual([ + 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'), ]); @@ -150,8 +152,8 @@ describe('create artifacts', () => { it('writes the selected template schema to project', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); - expect(fs_mock.writeFileSync.mock.calls[0]).toEqual([ + 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, ]); @@ -159,21 +161,38 @@ describe('create artifacts', () => { it('executes compileSchema from the provider', async () => { await cfnApiArtifactHandler.createArtifacts(addRequestStub); - expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(context_stub.amplify.executeProviderUtils.mock.calls[0][0]).toStrictEqual(context_stub); - expect(context_stub.amplify.executeProviderUtils.mock.calls[0][1]).toStrictEqual('awscloudformation'); - expect(context_stub.amplify.executeProviderUtils.mock.calls[0][2]).toStrictEqual('compileSchema'); + 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(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls.length).toBe(1); - expect(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][0]).toStrictEqual(category); - expect(context_stub.amplify.updateamplifyMetaAfterResourceAdd.mock.calls[0][1]).toStrictEqual( + 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); @@ -191,8 +210,8 @@ describe('update artifacts', () => { }; beforeAll(() => { - getAppSyncResourceName_mock.mockImplementation(() => testApiName); - getAppSyncAuthConfig_mock.mockImplementation(() => ({ + getAppSyncResourceNameMock.mockImplementation(() => testApiName); + getAppSyncAuthConfigMock.mockImplementation(() => ({ defaultAuthentication: { authenticationType: 'API_KEY', apiKeyConfig: { @@ -214,13 +233,13 @@ describe('update artifacts', () => { beforeEach(() => { jest.clearAllMocks(); updateRequestStub = _.cloneDeep(updateRequestStubBase); - cfnApiArtifactHandler = getCfnApiArtifactHandler(context_stub as unknown as $TSContext); + cfnApiArtifactHandler = getCfnApiArtifactHandler((contextStub as unknown) as $TSContext); }); it('throws error if no GQL API in project', () => { - getAppSyncResourceName_mock.mockImplementationOnce(() => undefined); + getAppSyncResourceNameMock.mockImplementationOnce(() => undefined); return expect(cfnApiArtifactHandler.updateArtifacts(updateRequestStub)).rejects.toMatchInlineSnapshot( - `[Error: No AppSync API configured in the project. Use 'amplify add api' to create an API.]`, + "[Error: No AppSync API configured in the project. Use 'amplify add api' to create an API.]", ); }); @@ -237,8 +256,8 @@ describe('update artifacts', () => { version: 1, }); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(fs_mock.writeFileSync.mock.calls.length).toBe(1); - expect(fs_mock.writeFileSync.mock.calls[0][1]).toBe(newSchemaContents); + 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 () => { @@ -253,8 +272,8 @@ describe('update artifacts', () => { version: 1, }); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(context_stub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); + 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 () => { @@ -296,30 +315,52 @@ describe('update artifacts', () => { }); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); - expect(context_stub.amplify.executeProviderUtils.mock.calls[0][3].authConfig).toMatchSnapshot(); + 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(context_stub.amplify.executeProviderUtils.mock.calls.length).toBe(1); + expect(contextStub.amplify.executeProviderUtils.mock.calls.length).toBe(1); }); it('updates meta files after update', async () => { await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(context_stub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(1); - expect(context_stub.amplify.updateBackendConfigAfterResourceUpdate.mock.calls.length).toBe(1); + 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 () => { - authConfigHasApiKey_mock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); + authConfigHasApiKeyMock.mockImplementationOnce(() => false).mockImplementationOnce(() => true); await cfnApiArtifactHandler.updateArtifacts(updateRequestStub); - expect(printer_mock.warn.mock.calls.length).toBe(2); + expect(printerMock.warn.mock.calls.length).toBe(2); }); it('prints warning when removing API key auth', async () => { - authConfigHasApiKey_mock.mockImplementationOnce(() => true).mockImplementationOnce(() => false); + 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(printer_mock.warn.mock.calls.length).toBe(3); + expect(contextStub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls.length).toBe(2); + expect(contextStub.amplify.updateamplifyMetaAfterResourceUpdate.mock.calls[1][3]).toEqual([ + { + category: 'auth', + resourceName: testAuthId, + attributes: [ + 'UserPoolId', + ], + }, + ]); }); }); 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 index e52ba7b64a..37d78a3d00 100644 --- 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 @@ -1,4 +1,6 @@ -import { $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { + $TSAny, $TSContext, isResourceNameUnique, JSONUtilities, pathManager, stateManager, +} from 'amplify-cli-core'; import { AddApiRequest, AppSyncServiceConfiguration, @@ -16,9 +18,13 @@ 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 { + 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 { + 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'; @@ -26,13 +32,16 @@ import { conflictResolutionToResolverConfig } from './utils/resolver-config-to-c // keep in sync with ServiceName in amplify-category-function, but probably it will not change const FunctionServiceNameLambdaFunction = 'Lambda'; -export const getCfnApiArtifactHandler = (context: $TSContext): ApiArtifactHandler => { - return new CfnApiArtifactHandler(context); -}; +/** + * 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', @@ -96,7 +105,9 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { authConfig, }); - this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig)); + const dependsOn = amendDependsOnForAuthConfig([], authConfig); + + this.context.amplify.updateamplifyMetaAfterResourceAdd(category, serviceConfig.apiName, this.createAmplifyMeta(authConfig, dependsOn)); return serviceConfig.apiName; }; @@ -106,7 +117,7 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { const updates = request.serviceModification; const apiName = getAppSyncResourceName(stateManager.getMeta()); if (!apiName) { - throw new Error(`No AppSync API configured in the project. Use 'amplify add api' to create an API.`); + throw new Error('No AppSync API configured in the project. Use \'amplify add api\' to create an API.'); } const resourceDir = this.getResourceDir(apiName); // update appsync cli-inputs @@ -140,42 +151,51 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { 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) => { + private writeSchema = (resourceDir: string, schema: string): void => { fs.writeFileSync(resourceDir, schema); }; - private getResourceDir = (apiName: string) => pathManager.getResourceDirectoryPath(undefined, category, apiName); + private getResourceDir = (apiName: string): string => pathManager.getResourceDirectoryPath(undefined, category, apiName); - private createAmplifyMeta = authConfig => ({ + // 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) => ({ + private extractAuthConfig = (config: AppSyncServiceConfig): AuthConfig => ({ defaultAuthentication: appSyncAuthTypeToAuthConfig(config.defaultAuthType), additionalAuthenticationProviders: (config.additionalAuthTypes || []).map(appSyncAuthTypeToAuthConfig), }); - private updateTransformerConfigVersion = async resourceDir => { + 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 = {}) => { + private createResolverResources = async (conflictResolution: ConflictResolution = {}): Promise => { const newConflictResolution = _.cloneDeep(conflictResolution); - // if the strat is a new lambda, generate the lambda and update the strategy to reference the new lambda - const generateLambdaIfNew = async (strat: ResolutionStrategy) => { - if (strat && strat.type === 'LAMBDA' && strat.resolver.type === 'NEW') { - strat.resolver = { + // 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(), }; @@ -184,13 +204,13 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await generateLambdaIfNew(newConflictResolution.defaultResolutionStrategy); await Promise.all( (newConflictResolution.perModelResolutionStrategy || []) - .map(perModelStrat => perModelStrat.resolutionStrategy) + .map(perModelStrategy => perModelStrategy.resolutionStrategy) .map(generateLambdaIfNew), ); return newConflictResolution; }; - private getCfnParameters = (apiName: string, authConfig, resourceDir: string) => { + private getCfnParameters = (apiName: string, authConfig, resourceDir: string): Record => { const cfnPath = path.join(resourceDir, cfnParametersFilename); const params = JSONUtilities.readJson<$TSAny>(cfnPath, { throwIfNotExist: false }) || defaultCfnParameters(apiName); const cognitoPool = this.getCognitoUserPool(authConfig); @@ -202,32 +222,33 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { return params; }; - private getCognitoUserPool = authConfig => { + private getCognitoUserPool = (authConfig: AuthConfig): Record | undefined => { const additionalUserPoolProvider = (authConfig.additionalAuthenticationProviders || []).find( - provider => provider.authenticationType === 'AMAZON_COGNITO_USER_POOLS', + aap => aap.authenticationType === 'AMAZON_COGNITO_USER_POOLS', ); - const defaultAuth = authConfig.defaultAuthentication || {}; - if (defaultAuth.authenticationType === 'AMAZON_COGNITO_USER_POOLS' || additionalUserPoolProvider) { - 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'], - }; + 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 () => { + private createSyncFunction = async (): Promise => { const targetDir = pathManager.getBackendDirPath(); const assetDir = path.normalize(path.join(rootAssetDir, 'sync-conflict-handler')); const [shortId] = uuid().split('-'); @@ -269,10 +290,10 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { await this.context.amplify.updateamplifyMetaAfterResourceAdd('function', functionName, backendConfigs); printer.success(`Successfully added ${functionName} function locally`); - return functionName + '-${env}'; + return `${functionName}-\${env}`; }; - private generateAppsyncCLIInputs = async (serviceConfig: AppSyncServiceConfiguration, resourceDir: string) => { + private generateAppsyncCLIInputs = async (serviceConfig: AppSyncServiceConfiguration, resourceDir: string): Promise => { const appsyncCLIInputs: AppSyncCLIInputs = { version: 1, serviceConfiguration: { @@ -337,8 +358,73 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { * * write to the transformer conf if the resolverConfig is valid */ -export const writeResolverConfig = async (conflictResolution: ConflictResolution, resourceDir: string) => { +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; +} From 7295eb15c0168c4c792376219aae7069931e0a70 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 11 Apr 2022 17:28:08 +0000 Subject: [PATCH 563/587] chore(release): Publish [ci skip] - amplify-app@4.2.27 - amplify-category-analytics@4.0.1 - @aws-amplify/amplify-category-api@2.0.1 - @aws-amplify/amplify-category-auth@2.7.9 - @aws-amplify/amplify-category-custom@2.3.26 - amplify-category-function@4.0.1 - amplify-category-geo@2.5.0 - amplify-category-hosting@3.2.26 - amplify-category-interactions@4.0.1 - amplify-category-predictions@4.0.1 - @aws-amplify/amplify-category-storage@3.1.23 - amplify-category-xr@3.2.26 - amplify-cli-core@2.5.2 - @aws-amplify/cli-extensibility-helper@2.3.22 - @aws-amplify/cli@8.0.1 - @aws-amplify/cli-internal@8.0.1 - amplify-console-hosting@2.2.26 - amplify-console-integration-tests@2.2.35 - amplify-container-hosting@2.4.30 - amplify-dotnet-function-template-provider@2.2.30 - amplify-dynamodb-simulator@2.2.26 - amplify-e2e-core@3.1.0 - amplify-e2e-tests@3.8.0 - amplify-frontend-android@3.4.0 - amplify-frontend-ios@3.4.0 - amplify-frontend-javascript@3.4.0 - amplify-go-function-runtime-provider@2.2.26 - @aws-amplify/graphql-auth-transformer@0.7.12 - amplify-graphql-migration-tests@2.2.36 - @aws-amplify/graphql-schema-test-library@1.0.14 - @aws-amplify/graphql-transformer-migrator@1.2.33 - amplify-java-function-runtime-provider@2.2.26 - amplify-migration-tests@4.4.29 - amplify-nodejs-function-runtime-provider@2.2.26 - amplify-nodejs-function-template-provider@2.3.11 - amplify-provider-awscloudformation@6.1.0 - amplify-python-function-runtime-provider@2.2.26 - amplify-util-import@2.2.26 - amplify-util-mock@4.3.14 - @aws-amplify/amplify-util-uibuilder@1.2.20 - graphql-auth-transformer@7.2.30 - graphql-connection-transformer@5.2.30 - graphql-dynamodb-transformer@7.2.30 - graphql-elasticsearch-transformer@5.2.30 - graphql-function-transformer@3.3.21 - graphql-http-transformer@5.2.30 - graphql-key-transformer@3.2.30 - graphql-predictions-transformer@3.2.30 - graphql-transformer-core@7.4.13 - graphql-transformers-e2e-tests@7.4.13 - graphql-versioned-transformer@5.2.30 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f00a0a4290..650950b0f1 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index a19eb0b07a..4b25f77ee5 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.0.0", + "version": "2.0.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.32", + "@aws-amplify/graphql-transformer-migrator": "1.2.33", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.5.1", + "amplify-cli-core": "2.5.2", "amplify-headless-interface": "1.14.2", "amplify-prompts": "2.0.0", - "amplify-provider-awscloudformation": "6.0.0", + "amplify-provider-awscloudformation": "6.1.0", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.12", + "graphql-transformer-core": "7.4.13", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 8d8e48f1504abf76c497068b2cd98efba083e950 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Mon, 18 Apr 2022 14:04:35 +0000 Subject: [PATCH 564/587] chore(release): Publish [ci skip] - amplify-app@4.2.28 - amplify-appsync-simulator@2.3.11 - @aws-amplify/amplify-category-api@2.0.2 - @aws-amplify/amplify-category-auth@2.7.10 - @aws-amplify/amplify-category-custom@2.3.27 - @aws-amplify/amplify-category-storage@3.1.24 - @aws-amplify/cli-extensibility-helper@2.3.23 - @aws-amplify/cli@8.0.2 - @aws-amplify/cli-internal@8.0.2 - amplify-container-hosting@2.4.31 - amplify-e2e-tests@3.8.1 - amplify-frontend-javascript@3.4.1 - @aws-amplify/graphql-auth-transformer@0.8.0 - @aws-amplify/graphql-default-value-transformer@0.5.20 - @aws-amplify/graphql-function-transformer@0.7.14 - @aws-amplify/graphql-http-transformer@0.8.14 - @aws-amplify/graphql-index-transformer@0.11.5 - @aws-amplify/graphql-maps-to-transformer@1.1.12 - amplify-graphql-migration-tests@2.2.37 - @aws-amplify/graphql-model-transformer@0.13.5 - @aws-amplify/graphql-predictions-transformer@0.6.14 - @aws-amplify/graphql-relational-transformer@0.8.0 - @aws-amplify/graphql-schema-test-library@1.0.15 - @aws-amplify/graphql-searchable-transformer@0.13.7 - @aws-amplify/graphql-transformer-core@0.16.5 - @aws-amplify/graphql-transformer-interfaces@1.13.1 - @aws-amplify/graphql-transformer-migrator@1.2.34 - amplify-nodejs-function-template-provider@2.3.12 - amplify-provider-awscloudformation@6.1.1 - amplify-util-mock@4.3.15 - @aws-amplify/amplify-util-uibuilder@1.2.21 - graphql-transformers-e2e-tests@7.4.14 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 650950b0f1..f51b92143a 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 4b25f77ee5..b3cabb5f94 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.0.1", + "version": "2.0.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.33", + "@aws-amplify/graphql-transformer-migrator": "1.2.34", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -71,7 +71,7 @@ "amplify-cli-core": "2.5.2", "amplify-headless-interface": "1.14.2", "amplify-prompts": "2.0.0", - "amplify-provider-awscloudformation": "6.1.0", + "amplify-provider-awscloudformation": "6.1.1", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", From d28f3c4ee2f59b242e5e2f53553cbab04a1e38a4 Mon Sep 17 00:00:00 2001 From: John Corser Date: Wed, 20 Apr 2022 15:46:32 -0400 Subject: [PATCH 565/587] chore: bump aws-sdk version (#10255) Co-authored-by: John Corser --- .../dockercompose-rest-express/express/package.json | 2 +- .../container-templates/dockerfile-rest-express/package.json | 2 +- .../container-templates/graphql-express/package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) 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 index 8986f5d776..84302629ea 100644 --- 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 @@ -8,7 +8,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1084.0", + "aws-sdk": "^2.1113.0", "axios": "^0.21.4", "body-parser": "^1.19.0", "express": "^4.17.1", 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 index ef470caec3..87ea138cec 100644 --- 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 @@ -9,7 +9,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1084.0", + "aws-sdk": "^2.1113.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 index 6517c17a7e..98445c57ea 100644 --- 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 @@ -7,7 +7,7 @@ "author": "", "license": "ISC", "dependencies": { - "aws-sdk": "^2.1084.0", + "aws-sdk": "^2.1113.0", "express": "^4.17.1", "express-graphql": "^0.11.0", "graphql": "^15.4.0" From 5469ef8ebb7e3725f16a08f69d6f5b92c48e124a Mon Sep 17 00:00:00 2001 From: John Corser Date: Wed, 20 Apr 2022 17:51:57 -0400 Subject: [PATCH 566/587] fix: remove prompt from rds headless pull (#10239) * fix: remove prompt from rds headless pull * chore: s/getClusterResourceIdFromArn/getRdsClusterResourceIdFromArn * chore: address nits Co-authored-by: John Corser --- .../appSync-rds-walkthrough.ts | 43 ++++++++++++++++--- 1 file changed, 36 insertions(+), 7 deletions(-) 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 index b522c226e5..326e95c370 100644 --- 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 @@ -1,8 +1,9 @@ -import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError } from 'amplify-cli-core'; +import { $TSContext, $TSObject, exitOnNextTick, ResourceCredentialsNotFoundError, ResourceDoesNotExistError, pathManager, JSONUtilities, $TSAny } from 'amplify-cli-core'; import { printer, prompter } from 'amplify-prompts'; import chalk from 'chalk'; import { DataApiParams } from 'graphql-relational-schema-transformer'; import ora from 'ora'; +import { cfnRootStackFileName } from 'amplify-provider-awscloudformation'; const spinner = ora(''); const category = 'api'; @@ -42,8 +43,14 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata 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: $TSAny = JSONUtilities.readJson(`${pathManager.getCurrentCloudRootStackDirPath(pathManager.findProjectRoot())}/${cfnRootStackFileName}`); + const cfnJsonParameters = cfnJson?.Resources[`api${appSyncApi}`]?.Properties?.Parameters || {}; + let selectedRegion = cfnJsonParameters?.rdsRegion; // Region Question - const selectedRegion = await promptWalkthroughQuestion(inputs, 0, availableRegions); + if (!selectedRegion) { + selectedRegion = await promptWalkthroughQuestion(inputs, 0, availableRegions); + } const AWS = await getAwsClient(context, 'list'); @@ -53,13 +60,23 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata }); // RDS Cluster Question - const { selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, AWS); + let selectedClusterArn = cfnJsonParameters?.rdsClusterIdentifier + let clusterResourceId = getRdsClusterResourceIdFromArn(selectedClusterArn, AWS); + if (!selectedClusterArn || !clusterResourceId) { + ({ selectedClusterArn, clusterResourceId } = await selectCluster(context, inputs, AWS)); + } // Secret Store Question - const selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS); + let selectedSecretArn = cfnJsonParameters?.rdsSecretStoreArn; + if (!selectedSecretArn) { + selectedSecretArn = await getSecretStoreArn(context, inputs, clusterResourceId, AWS); + } // Database Name Question - const selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); + let selectedDatabase = cfnJsonParameters?.rdsDatabaseName; + if (!selectedDatabase) { + selectedDatabase = await selectDatabase(context, inputs, selectedClusterArn, selectedSecretArn, AWS); + } return { region: selectedRegion, @@ -70,6 +87,19 @@ export async function serviceWalkthrough(context: $TSContext, datasourceMetadata }; } +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 @@ -242,8 +272,7 @@ async function promptWalkthroughQuestion(inputs, questionNumber, choicesList) { message: inputs[questionNumber].question, choices: choicesList, }; - const answer = await prompter.pick(question.message, choicesList) - return answer[inputs[questionNumber].key]; + return await prompter.pick(question.message, choicesList) } async function getAwsClient(context: $TSContext, action: string) { From 8536b64aca3be001e9642b36ef1ccb4ee5a0c314 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Wed, 27 Apr 2022 02:18:40 +0000 Subject: [PATCH 567/587] chore(release): Publish [ci skip] - amplify-app@4.2.29 - amplify-appsync-simulator@2.3.12 - amplify-category-analytics@4.0.2 - @aws-amplify/amplify-category-api@2.0.3 - @aws-amplify/amplify-category-auth@2.7.11 - @aws-amplify/amplify-category-custom@2.3.28 - amplify-category-function@4.0.2 - amplify-category-geo@2.5.1 - amplify-category-hosting@3.2.27 - amplify-category-interactions@4.0.2 - amplify-category-predictions@4.0.2 - @aws-amplify/amplify-category-storage@3.1.25 - amplify-category-xr@3.2.27 - amplify-cli-core@2.5.3 - @aws-amplify/cli-extensibility-helper@2.3.24 - @aws-amplify/cli@8.0.3 - @aws-amplify/cli-internal@8.0.3 - amplify-console-hosting@2.2.27 - amplify-console-integration-tests@2.2.36 - amplify-container-hosting@2.4.32 - amplify-dotnet-function-template-provider@2.2.31 - amplify-dynamodb-simulator@2.2.27 - amplify-e2e-core@3.1.1 - amplify-e2e-tests@3.8.2 - amplify-frontend-ios@3.4.1 - amplify-frontend-javascript@3.4.2 - amplify-go-function-runtime-provider@2.2.27 - amplify-graphiql-explorer@2.4.6 - @aws-amplify/graphql-auth-transformer@0.8.1 - @aws-amplify/graphql-default-value-transformer@0.5.21 - @aws-amplify/graphql-function-transformer@0.7.15 - @aws-amplify/graphql-http-transformer@0.8.15 - @aws-amplify/graphql-index-transformer@0.11.6 - @aws-amplify/graphql-maps-to-transformer@1.1.13 - amplify-graphql-migration-tests@2.2.38 - @aws-amplify/graphql-model-transformer@0.13.6 - @aws-amplify/graphql-predictions-transformer@0.6.15 - @aws-amplify/graphql-relational-transformer@0.8.1 - @aws-amplify/graphql-schema-test-library@1.0.16 - @aws-amplify/graphql-searchable-transformer@0.13.8 - @aws-amplify/graphql-transformer-core@0.16.6 - @aws-amplify/graphql-transformer-migrator@1.2.35 - amplify-java-function-runtime-provider@2.2.27 - amplify-migration-tests@4.4.30 - amplify-nodejs-function-runtime-provider@2.2.27 - amplify-nodejs-function-template-provider@2.3.13 - amplify-prompts@2.0.1 - amplify-provider-awscloudformation@6.1.2 - amplify-python-function-runtime-provider@2.2.27 - amplify-storage-simulator@1.6.7 - amplify-util-import@2.2.27 - amplify-util-mock@4.3.16 - @aws-amplify/amplify-util-uibuilder@1.2.22 - amplify-velocity-template@1.4.8 - graphql-auth-transformer@7.2.31 - graphql-connection-transformer@5.2.31 - graphql-dynamodb-transformer@7.2.31 - graphql-elasticsearch-transformer@5.2.31 - graphql-function-transformer@3.3.22 - graphql-http-transformer@5.2.31 - graphql-key-transformer@3.2.31 - graphql-predictions-transformer@3.2.31 - graphql-relational-schema-transformer@2.21.6 - graphql-transformer-core@7.4.14 - graphql-transformers-e2e-tests@7.4.15 - graphql-versioned-transformer@5.2.31 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 14 +++++++------- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index f51b92143a..4308105e82 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b3cabb5f94..b4b2f4f35b 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.0.2", + "version": "2.0.3", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.34", + "@aws-amplify/graphql-transformer-migrator": "1.2.35", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.5.2", + "amplify-cli-core": "2.5.3", "amplify-headless-interface": "1.14.2", - "amplify-prompts": "2.0.0", - "amplify-provider-awscloudformation": "6.1.1", + "amplify-prompts": "2.0.1", + "amplify-provider-awscloudformation": "6.1.2", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.5", - "graphql-transformer-core": "7.4.13", + "graphql-relational-schema-transformer": "2.21.6", + "graphql-transformer-core": "7.4.14", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From 99ee3bb6366215914e39bbe2af59529e27d0c929 Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Wed, 27 Apr 2022 15:05:19 -0700 Subject: [PATCH 568/587] chore: alias appsync provider methods, and rename to graphql (#10247) --- .../service-walkthroughs/appSync-walkthrough.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 index 9aa0764d90..1356296c7a 100644 --- 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 @@ -537,7 +537,7 @@ async function displayApiInformation(context: $TSContext, resource: $TSObject, p async function displayAuthMode(context: $TSContext, resource: $TSObject, authMode: string) { if (authMode === 'API_KEY' && resource.output.GraphQLAPIKeyOutput) { - let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getAppSyncApiKeys', { + let { apiKeys } = await context.amplify.executeProviderUtils(context, 'awscloudformation', 'getGraphQLApiKeys', { apiId: resource.output.GraphQLAPIIdOutput, }); let apiKeyExpires = apiKeys.find(key => key.id == resource.output.GraphQLAPIKeyOutput)?.expires; From e5253cd04f36741b36cd266ee9705f91c4609e85 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 29 Apr 2022 16:58:23 +0000 Subject: [PATCH 569/587] chore(release): Publish [ci skip] - amplify-app@4.2.30 - amplify-category-analytics@4.0.3 - @aws-amplify/amplify-category-api@2.0.4 - @aws-amplify/amplify-category-auth@2.7.12 - @aws-amplify/amplify-category-custom@2.3.29 - amplify-category-function@4.0.3 - amplify-category-geo@2.5.2 - amplify-category-hosting@3.2.28 - amplify-category-interactions@4.0.3 - amplify-category-predictions@4.0.3 - @aws-amplify/amplify-category-storage@3.1.26 - amplify-category-xr@3.2.28 - amplify-cli-core@2.6.0 - @aws-amplify/cli-extensibility-helper@2.3.25 - @aws-amplify/cli@8.1.0 - @aws-amplify/cli-internal@8.1.0 - amplify-console-hosting@2.2.28 - amplify-console-integration-tests@2.2.37 - amplify-container-hosting@2.4.33 - amplify-dotnet-function-template-provider@2.2.32 - amplify-dynamodb-simulator@2.2.28 - amplify-e2e-core@3.1.2 - amplify-e2e-tests@3.9.0 - amplify-frontend-ios@3.4.2 - amplify-frontend-javascript@3.4.3 - amplify-go-function-runtime-provider@2.2.28 - @aws-amplify/graphql-auth-transformer@0.9.0 - @aws-amplify/graphql-default-value-transformer@0.5.22 - @aws-amplify/graphql-function-transformer@0.7.16 - @aws-amplify/graphql-http-transformer@0.8.16 - @aws-amplify/graphql-index-transformer@0.11.7 - @aws-amplify/graphql-maps-to-transformer@1.1.14 - amplify-graphql-migration-tests@2.2.39 - @aws-amplify/graphql-model-transformer@0.14.0 - @aws-amplify/graphql-predictions-transformer@0.6.16 - @aws-amplify/graphql-relational-transformer@0.9.0 - @aws-amplify/graphql-schema-test-library@1.0.17 - @aws-amplify/graphql-searchable-transformer@0.14.0 - @aws-amplify/graphql-transformer-core@0.17.0 - @aws-amplify/graphql-transformer-interfaces@1.14.0 - @aws-amplify/graphql-transformer-migrator@1.2.36 - amplify-java-function-runtime-provider@2.2.28 - amplify-migration-tests@4.4.31 - amplify-nodejs-function-runtime-provider@2.2.28 - amplify-nodejs-function-template-provider@2.3.14 - amplify-provider-awscloudformation@6.1.3 - amplify-python-function-runtime-provider@2.2.28 - amplify-util-import@2.2.28 - amplify-util-mock@4.4.0 - @aws-amplify/amplify-util-uibuilder@1.2.23 - graphql-auth-transformer@7.2.32 - graphql-connection-transformer@5.2.32 - graphql-dynamodb-transformer@7.2.32 - graphql-elasticsearch-transformer@5.2.32 - graphql-function-transformer@3.3.23 - graphql-http-transformer@5.2.32 - graphql-key-transformer@3.2.32 - graphql-predictions-transformer@3.2.32 - graphql-transformer-core@7.5.0 - graphql-transformers-e2e-tests@7.5.0 - graphql-versioned-transformer@5.2.32 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 10 +++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 4308105e82..252803ccf8 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b4b2f4f35b..5c0ccb716f 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.0.3", + "version": "2.0.4", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.35", + "@aws-amplify/graphql-transformer-migrator": "1.2.36", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -68,17 +68,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.5.3", + "amplify-cli-core": "2.6.0", "amplify-headless-interface": "1.14.2", "amplify-prompts": "2.0.1", - "amplify-provider-awscloudformation": "6.1.2", + "amplify-provider-awscloudformation": "6.1.3", "amplify-util-headless-input": "1.9.3", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "2.21.6", - "graphql-transformer-core": "7.4.14", + "graphql-transformer-core": "7.5.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", From d76a0ff9ad66f93074c1bc7d309f987428c0f76c Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Mon, 2 May 2022 09:46:17 -0700 Subject: [PATCH 570/587] API Category Split Milestone 1 Changes in CLI (#10323) * chore(amplify-category-api): split API plugin dependencies * chore(amplify-category-api): remove unrelated doc files * chore(amplify-category-api): update package scripts, tsconfig * chore(amplify-category-api): update dependency on migrated packages * chore: update yarn.lock after split * fix: update mock test avoid importing mocked featureflag provider from trasnsformer Co-authored-by: Al Harris --- packages/amplify-category-api/package.json | 6 +++--- packages/amplify-category-api/tsconfig.json | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 5c0ccb716f..8af533daaf 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "1.2.36", + "@aws-amplify/graphql-transformer-migrator": "^1.2.36", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -77,8 +77,8 @@ "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "2.21.6", - "graphql-transformer-core": "7.5.0", + "graphql-relational-schema-transformer": "^2.21.6", + "graphql-transformer-core": "^7.5.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index f4f67b9ed0..5b558858ae 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -3,7 +3,7 @@ "compilerOptions": { "outDir": "lib", "rootDir": "src", - "strict": false, // because package has been converted from js + "strict": false, "allowJs": false }, "exclude": [ @@ -18,11 +18,17 @@ "src/__tests__" ], "references": [ - {"path": "../amplify-cli-core"}, - {"path": "../amplify-headless-interface"}, - {"path": "../amplify-prompts"}, - {"path": "../graphql-transformer-core"}, - {"path": "../amplify-util-headless-input"}, - {"path": "../amplify-graphql-transformer-migrator"}, + { + "path": "../amplify-cli-core" + }, + { + "path": "../amplify-headless-interface" + }, + { + "path": "../amplify-prompts" + }, + { + "path": "../amplify-util-headless-input" + } ] } From af5fa1d702d724f6aa78e33c49e262ef4bd3f3dd Mon Sep 17 00:00:00 2001 From: John Hockett Date: Wed, 4 May 2022 15:49:27 -0700 Subject: [PATCH 571/587] fix: root path handling for REST APIs (#9842) --- .../cdk-stack-builder/apigw-stack-builder.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) 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 index 8ed37d7f56..305d8405c7 100644 --- 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 @@ -110,7 +110,8 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw } private _craftPolicyDocument(apiResourceName: string, pathName: string, supportedOperations: string[]) { - const resources = [pathName, `${pathName}/*`].flatMap(path => + const paths = [pathName, appendToUrlPath(pathName, '*')]; + const resources = paths.flatMap(path => supportedOperations.map(op => cdk.Fn.join('', [ 'arn:aws:execute-api:', @@ -288,7 +289,7 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw lambdaPermissionLogicalId = `${ADMIN_QUERIES_NAME}APIGWPolicyForLambda`; } else { this.paths[pathName] = createPathObject(path); - this.paths[`${pathName}/{proxy+}`] = createPathObject(path); + this.paths[appendToUrlPath(pathName, '{proxy+}')] = createPathObject(path); lambdaPermissionLogicalId = `function${path.lambdaFunction}Permission${resourceName}`; } @@ -325,6 +326,10 @@ export class AmplifyApigwResourceStack extends cdk.Stack implements AmplifyApigw }; } +const appendToUrlPath = (path: string, postfix: string) => { + return path.charAt(path.length - 1) === '/' ? `${path}${postfix}` : `${path}/${postfix}`; +}; + const getAdminQueriesPathObject = (lambdaFunctionName: string) => ({ options: { consumes: ['application/json'], From 3ebea06e9c9265b8199158cae1d7cf104da8588f Mon Sep 17 00:00:00 2001 From: Sachin Panemangalore <83682223+sachscode@users.noreply.github.com> Date: Thu, 5 May 2022 16:54:51 -0500 Subject: [PATCH 572/587] feat: usage flow logging for interactive and non-interactive cli commands (#10288) * (chore) added flow report class * (feat) amplify cli flow journaling * (chore) insert unique project identifier to index logs * (chore) add timestamp to interactions for Dx tracking * feat: walkthrough logging for headless apis * chore: upgrade lodash dependencies * (chore) flow-report headless unit-tests and redactions * chore: fix unit tests broken by flow * chore: remove extraneous debug logs * chore: update unit tests for redactions and interactive flows * chore: remove extraneous lib folder and update gitignore * chore: address-pr-comment: remove input params from no-op functions * chore: PR comments make flowData as member of usageData instead of singleton * chore: PR comment - revert change which made line too long to read * chore: PR comment - remove extraneous calls to pushFlow and remove pushHeadlessFlow from prompter * chore: PR comment - changelog will be added only after the release * chore: fix lgtm bot errors * fix: ignore amplify-cli-shared-interfaces for testing * fix: prevent symlinks on nodejs package install (#10293) * fix auth unit-tests breaking because of headless flow logging * chore: redact hidden inputs * fix : mocking errors in usageData instance Co-authored-by: Sachin Panemangalore Co-authored-by: John Hockett --- packages/amplify-category-api/src/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index f27f52ee9a..d9c8e4efd6 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -235,6 +235,7 @@ export async function executeAmplifyCommand(context: $TSContext) { } export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => { + context.usageData.pushHeadlessFlow(headlessPayload, context.input); switch (context.input.command) { case 'add': await getCfnApiArtifactHandler(context).createArtifacts(await validateAddApiRequest(headlessPayload)); From f754f2cc4c9fa2b43b0ec310ebfb7aa6dc6413c3 Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 6 May 2022 17:10:54 -0700 Subject: [PATCH 573/587] build: replace lerna task orchestration with nx (#10369) --- packages/amplify-category-api/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 8af533daaf..83a14c957d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -13,7 +13,7 @@ "scripts": { "build": "tsc", "watch": "tsc -w", - "clean": "rimraf lib tsconfig.tsbuildinfo", + "clean": "rimraf lib tsconfig.tsbuildinfo node_modules", "test": "jest", "generateSchemas": "ts-node ./scripts/generateApiSchemas.ts" }, From 6dac43f9f5343ab029d647a4e8213aa042bcf935 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 10 May 2022 22:42:03 +0000 Subject: [PATCH 574/587] chore(release): Publish [ci skip] - amplify-app@4.2.31 - amplify-appsync-simulator@2.3.13 - amplify-category-analytics@4.0.4 - @aws-amplify/amplify-category-api@2.1.0 - @aws-amplify/amplify-category-auth@2.8.0 - @aws-amplify/amplify-category-custom@2.3.30 - amplify-category-function@4.0.4 - amplify-category-geo@2.6.0 - amplify-category-hosting@3.2.29 - amplify-category-interactions@4.0.4 - amplify-category-predictions@4.0.4 - @aws-amplify/amplify-category-storage@3.3.0 - amplify-category-xr@3.2.29 - amplify-cli-core@2.7.0 - @aws-amplify/cli-extensibility-helper@2.3.26 - amplify-cli-logger@1.1.3 - @aws-amplify/cli@8.2.0 - amplify-cli-shared-interfaces@1.1.0 - @aws-amplify/cli-internal@8.2.0 - amplify-console-hosting@2.2.29 - amplify-console-integration-tests@2.2.38 - amplify-container-hosting@2.4.34 - amplify-dotnet-function-runtime-provider@1.6.9 - amplify-dotnet-function-template-provider@2.2.33 - amplify-dynamodb-simulator@2.2.29 - amplify-e2e-core@3.1.3 - amplify-e2e-tests@3.9.1 - amplify-frontend-ios@3.4.3 - amplify-frontend-javascript@3.4.4 - amplify-function-plugin-interface@1.9.5 - amplify-go-function-runtime-provider@2.2.29 - amplify-go-function-template-provider@1.3.14 - amplify-graphql-migration-tests@2.2.40 - amplify-headless-interface@1.14.3 - amplify-java-function-runtime-provider@2.2.29 - amplify-java-function-template-provider@1.5.13 - amplify-migration-tests@4.4.32 - amplify-nodejs-function-runtime-provider@2.2.29 - amplify-nodejs-function-template-provider@2.3.15 - amplify-prompts@2.1.0 - amplify-provider-awscloudformation@6.1.4 - amplify-python-function-runtime-provider@2.2.29 - amplify-python-function-template-provider@1.3.16 - amplify-util-headless-input@1.9.4 - amplify-util-import@2.2.29 - amplify-util-mock@4.4.1 - @aws-amplify/amplify-util-uibuilder@1.2.24 --- packages/amplify-category-api/CHANGELOG.md | 16 ++++++++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 252803ccf8..bbac0eda97 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 83a14c957d..b7faa11b93 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.0.4", + "version": "2.1.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -68,11 +68,11 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.6.0", - "amplify-headless-interface": "1.14.2", - "amplify-prompts": "2.0.1", - "amplify-provider-awscloudformation": "6.1.3", - "amplify-util-headless-input": "1.9.3", + "amplify-cli-core": "2.7.0", + "amplify-headless-interface": "1.14.3", + "amplify-prompts": "2.1.0", + "amplify-provider-awscloudformation": "6.1.4", + "amplify-util-headless-input": "1.9.4", "chalk": "^4.1.1", "constructs": "^3.3.125", "fs-extra": "^8.1.0", From 48d9c5a328e77ab42023a1210daa97a4c6e05ab6 Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Thu, 12 May 2022 10:09:56 -0700 Subject: [PATCH 575/587] chore: introduce api facade with getTransformerVersion and getDirectiveDefinitions, and methods to api category (#10402) --- packages/amplify-category-api/package.json | 3 +- .../src/commands/api/override.ts | 5 +- .../directive-definitions.ts | 27 +++++++++ .../src/graphql-transformer/index.ts | 2 + .../transformer-version.ts | 57 +++++++++++++++++++ packages/amplify-category-api/src/index.ts | 1 + .../appSync-walkthrough.ts | 7 +-- 7 files changed, 94 insertions(+), 8 deletions(-) create mode 100644 packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/index.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-version.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b7faa11b93..34ff986205 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -83,7 +83,8 @@ "js-yaml": "^4.0.0", "lodash": "^4.17.21", "ora": "^4.0.3", - "uuid": "^8.3.2" + "uuid": "^8.3.2", + "@aws-amplify/graphql-transformer-core": "^0.17.0" }, "devDependencies": { "@aws-cdk/assertions": "~1.124.0", diff --git a/packages/amplify-category-api/src/commands/api/override.ts b/packages/amplify-category-api/src/commands/api/override.ts index 3dbbe3830f..e201258fc0 100644 --- a/packages/amplify-category-api/src/commands/api/override.ts +++ b/packages/amplify-category-api/src/commands/api/override.ts @@ -3,6 +3,7 @@ import { $TSObject, AmplifyCategories, AmplifySupportedService, + ApiCategoryFacade, generateOverrideSkeleton, pathManager, stateManager, @@ -57,9 +58,7 @@ export const run = async (context: $TSContext) => { /** * Below steps checks for TransformerV1 app and updates the FF { useexperimentalpipelinedtransformer , transformerversion} */ - const transformerVersion = await context.amplify.invokePluginMethod(context, 'awscloudformation', undefined, 'getTransformerVersion', [ - context, - ]); + 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); diff --git a/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts b/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts new file mode 100644 index 0000000000..edfc132952 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts @@ -0,0 +1,27 @@ +import { + getAppSyncServiceExtraDirectives, +} from '@aws-amplify/graphql-transformer-core'; +import { + $TSContext, + ApiCategoryFacade, +} from 'amplify-cli-core'; +import { print } from 'graphql'; +import { getTransformerVersion } from './transformer-version'; + +/** + * 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 transformer = await ApiCategoryFacade.getTransformerFactory(context, resourceDir); + const transformList = transformerVersion === 2 + ? await transformer({ addSearchableTransformer: true, authConfig: {} }) + : await transformer(true); + + const transformDirectives = transformList + .map(transformPluginInst => [transformPluginInst.directive, ...transformPluginInst.typeDefinitions].map(node => print(node)).join('\n')) + .join('\n'); + + return [getAppSyncServiceExtraDirectives(), transformDirectives].join('\n'); +}; diff --git a/packages/amplify-category-api/src/graphql-transformer/index.ts b/packages/amplify-category-api/src/graphql-transformer/index.ts new file mode 100644 index 0000000000..3cce30be29 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/index.ts @@ -0,0 +1,2 @@ +export { getDirectiveDefinitions } from './directive-definitions'; +export { getTransformerVersion } from './transformer-version'; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts new file mode 100644 index 0000000000..e5f84e78ab --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts @@ -0,0 +1,57 @@ +import { + $TSContext, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { FeatureFlags } from '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 Error(`Invalid value specified for transformerVersion: '${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/index.ts b/packages/amplify-category-api/src/index.ts index d9c8e4efd6..f81d2b2a02 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -37,6 +37,7 @@ export { 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'; const category = AmplifyCategories.API; const categories = 'categories'; 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 index 1356296c7a..64df03c011 100644 --- 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 @@ -11,6 +11,7 @@ import { stateManager, UnknownResourceTypeError, getGraphQLTransformerAuthDocLink, + ApiCategoryFacade, } from 'amplify-cli-core'; import { UpdateApiRequest } from 'amplify-headless-interface'; import { printer, prompter } from 'amplify-prompts'; @@ -393,8 +394,7 @@ const updateApiInputWalkthrough = async (context: $TSContext, project: $TSObject export const serviceWalkthrough = async (context: $TSContext, serviceMetadata: $TSObject) => { const resourceName = resourceAlreadyExists(); - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); - const transformerVersion = await providerPlugin.getTransformerVersion(context); + const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); await addLambdaAuthorizerChoice(context); if (resourceName) { @@ -665,8 +665,7 @@ async function askSyncFunctionQuestion() { } async function addLambdaAuthorizerChoice(context: $TSContext) { - const providerPlugin = await import(context.amplify.getProviderPlugins(context)[providerName]); - const transformerVersion = await providerPlugin.getTransformerVersion(context); + const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); if (transformerVersion === 2 && !authProviderChoices.some(choice => choice.value == 'AWS_LAMBDA')) { authProviderChoices.push({ name: 'Lambda', From 00fc7625c881b63f8bf06af43ef5d6ad073e2ab3 Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Thu, 12 May 2022 12:20:08 -0700 Subject: [PATCH 576/587] refactor: migrate transformer factory into api category package (#10404) --- packages/amplify-category-api/package.json | 27 +- .../src/graphql-transformer/index.ts | 1 + .../transformer-factory.ts | 233 ++++++++++++++++++ 3 files changed, 259 insertions(+), 2 deletions(-) create mode 100644 packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 34ff986205..21154646f9 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -78,13 +78,36 @@ "fs-extra": "^8.1.0", "graphql": "^14.5.8", "graphql-relational-schema-transformer": "^2.21.6", - "graphql-transformer-core": "^7.5.0", "inquirer": "^7.3.3", "js-yaml": "^4.0.0", "lodash": "^4.17.21", "ora": "^4.0.3", "uuid": "^8.3.2", - "@aws-amplify/graphql-transformer-core": "^0.17.0" + "@aws-amplify/graphql-auth-transformer": "^0.9.0", + "@aws-amplify/graphql-default-value-transformer": "^0.5.22", + "@aws-amplify/graphql-function-transformer": "^0.7.16", + "@aws-amplify/graphql-http-transformer": "^0.8.16", + "@aws-amplify/graphql-index-transformer": "^0.11.7", + "@aws-amplify/graphql-maps-to-transformer": "^1.1.14", + "@aws-amplify/graphql-model-transformer": "^0.14.0", + "@aws-amplify/graphql-predictions-transformer": "^0.6.16", + "@aws-amplify/graphql-relational-transformer": "^0.9.0", + "@aws-amplify/graphql-searchable-transformer": "^0.14.0", + "@aws-amplify/graphql-transformer-core": "^0.17.0", + "@aws-amplify/graphql-transformer-interfaces": "^1.14.0", + "graphql-auth-transformer": "^7.2.32", + "graphql-connection-transformer": "^5.2.32", + "graphql-dynamodb-transformer": "^7.2.32", + "graphql-elasticsearch-transformer": "^5.2.32", + "graphql-function-transformer": "^3.3.23", + "graphql-http-transformer": "^5.2.32", + "graphql-key-transformer": "^3.2.32", + "graphql-predictions-transformer": "^3.2.32", + "graphql-transformer-common": "^4.23.0", + "graphql-transformer-core": "^7.5.0", + "graphql-versioned-transformer": "^5.2.32", + "import-from": "^3.0.0", + "import-global": "^0.1.0" }, "devDependencies": { "@aws-cdk/assertions": "~1.124.0", diff --git a/packages/amplify-category-api/src/graphql-transformer/index.ts b/packages/amplify-category-api/src/graphql-transformer/index.ts index 3cce30be29..21edbf0ae2 100644 --- a/packages/amplify-category-api/src/graphql-transformer/index.ts +++ b/packages/amplify-category-api/src/graphql-transformer/index.ts @@ -1,2 +1,3 @@ export { getDirectiveDefinitions } from './directive-definitions'; export { getTransformerVersion } from './transformer-version'; +export { getTransformerFactory } from './transformer-factory'; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts new file mode 100644 index 0000000000..1dd04b75b4 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts @@ -0,0 +1,233 @@ +import { AuthTransformer as AuthTransformerV2 } from '@aws-amplify/graphql-auth-transformer'; +import { DefaultValueTransformer as DefaultValueTransformerV2 } from '@aws-amplify/graphql-default-value-transformer'; +import { FunctionTransformer as FunctionTransformerV2 } from '@aws-amplify/graphql-function-transformer'; +import { HttpTransformer as HttpTransformerV2 } from '@aws-amplify/graphql-http-transformer'; +import { + IndexTransformer as IndexTransformerV2, + PrimaryKeyTransformer as PrimaryKeyTransformerV2, +} from '@aws-amplify/graphql-index-transformer'; +import { MapsToTransformer as MapsToTransformerV2 } from '@aws-amplify/graphql-maps-to-transformer'; +import { ModelTransformer as ModelTransformerV2 } from '@aws-amplify/graphql-model-transformer'; +import { PredictionsTransformer as PredictionsTransformerV2 } from '@aws-amplify/graphql-predictions-transformer'; +import { + BelongsToTransformer as BelongsToTransformerV2, + HasManyTransformer as HasManyTransformerV2, + HasOneTransformer as HasOneTransformerV2, + ManyToManyTransformer as ManyToManyTransformerV2, +} from '@aws-amplify/graphql-relational-transformer'; +import { SearchableModelTransformer as SearchableModelTransformerV2 } from '@aws-amplify/graphql-searchable-transformer'; +import { TransformerPluginProvider as TransformerPluginProviderV2 } from '@aws-amplify/graphql-transformer-interfaces'; +import { DynamoDBModelTransformer as DynamoDBModelTransformerV1 } from 'graphql-dynamodb-transformer'; +import { ModelAuthTransformer as ModelAuthTransformerV1 } from 'graphql-auth-transformer'; +import { ModelConnectionTransformer as ModelConnectionTransformerV1 } from 'graphql-connection-transformer'; +import { SearchableModelTransformer as SearchableModelTransformerV1 } from 'graphql-elasticsearch-transformer'; +import { VersionedModelTransformer as VersionedModelTransformerV1 } from 'graphql-versioned-transformer'; +import { FunctionTransformer as FunctionTransformerV1 } from 'graphql-function-transformer'; +import { HttpTransformer as HttpTransformerV1 } from 'graphql-http-transformer'; +import { PredictionsTransformer as PredictionsTransformerV1 } from 'graphql-predictions-transformer'; +import { KeyTransformer as KeyTransformerV1 } from 'graphql-key-transformer'; +import { + $TSAny, + $TSContext, + pathManager, + stateManager, + ApiCategoryFacade, + CloudformationProviderFacade, +} from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import { + loadProject, + readTransformerConfiguration, + TRANSFORM_CONFIG_FILE_NAME, + ITransformer, + TransformConfig, +} from 'graphql-transformer-core'; +import importFrom from 'import-from'; +import importGlobal from 'import-global'; +import path from 'path'; + +const PROVIDER_NAME = 'awscloudformation'; + +type TransformerFactoryArgs = { + addSearchableTransformer: boolean; + authConfig: $TSAny; + storageConfig?: $TSAny; + adminRoles?: Array; + identityPoolId?: string; + }; + +/** + * Return the graphql transformer factory based on the projects current transformer version. + */ +export const getTransformerFactory = async ( + context: $TSContext, + resourceDir: string, + authConfig?: $TSAny, +): Promise<(options: $TSAny) => Promise<(TransformerPluginProviderV2 | ITransformer)[]>> => { + const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); + return transformerVersion === 2 + ? getTransformerFactoryV2(resourceDir) + : getTransformerFactoryV1(context, resourceDir, authConfig); +}; + +const getTransformerFactoryV2 = ( + resourceDir: string, +): (options: TransformerFactoryArgs) => Promise => async (options?: TransformerFactoryArgs) => { + const modelTransformer = new ModelTransformerV2(); + const indexTransformer = new IndexTransformerV2(); + const hasOneTransformer = new HasOneTransformerV2(); + const authTransformer = new AuthTransformerV2({ + adminRoles: options.adminRoles ?? [], + identityPoolId: options.identityPoolId, + }); + const transformerList: TransformerPluginProviderV2[] = [ + modelTransformer, + new FunctionTransformerV2(), + new HttpTransformerV2(), + new PredictionsTransformerV2(options?.storageConfig), + new PrimaryKeyTransformerV2(), + indexTransformer, + new BelongsToTransformerV2(), + new HasManyTransformerV2(), + hasOneTransformer, + new ManyToManyTransformerV2(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), + new DefaultValueTransformerV2(), + authTransformer, + new MapsToTransformerV2(), + // TODO: initialize transformer plugins + ]; + + if (options?.addSearchableTransformer) { + transformerList.push(new SearchableModelTransformerV2()); + } + + const customTransformersConfig = await loadProject(resourceDir); + const customTransformerList = customTransformersConfig?.config?.transformers; + const customTransformers = (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); + + if (customTransformers.length > 0) { + transformerList.push(...customTransformers); + } + + return transformerList; +}; + +function getTransformerFactoryV1(context: $TSContext, resourceDir: string, authConfig?: $TSAny) { + return async (addSearchableTransformer: boolean, storageConfig?: $TSAny) => { + const transformerList: ITransformer[] = [ + // TODO: Removing until further discussion. `getTransformerOptions(project, '@model')` + new DynamoDBModelTransformerV1(), + new VersionedModelTransformerV1(), + new FunctionTransformerV1(), + new HttpTransformerV1(), + new KeyTransformerV1(), + new ModelConnectionTransformerV1(), + new PredictionsTransformerV1(storageConfig), + ]; + + if (addSearchableTransformer) { + transformerList.push(new SearchableModelTransformerV1()); + } + + 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(); + } else 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: boolean = 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 ModelAuthTransformerV1({ 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 + */ +const importTransformerModule = (transformerName: string) => { + 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; + } +}; From a37e72e0c9d15eb7a75b0d2b6a56dfd06153c10b Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Thu, 12 May 2022 15:58:24 -0700 Subject: [PATCH 577/587] refactor: migrate transformGraphQL schema into api category (#10411) --- packages/amplify-category-api/package.json | 5 +- .../api-key-helpers.test.ts | 24 + .../graphql-push-schema-checks.test.ts | 130 +++++ .../sandbox-mode-helpers.test.ts | 138 +++++ .../transformer-feature-flag-adapter.test.ts | 94 ++++ .../user-defined-slots.test.ts | 195 ++++++++ .../graphql-transformer/utils.test.ts | 279 +++++++++++ .../amplify-cli-feature-flag-adapter.ts | 41 ++ .../graphql-transformer/api-key-helpers.ts | 6 + .../src/graphql-transformer/api-utils.ts | 24 + .../graphql-transformer/auth-mode-compare.ts | 38 ++ .../directive-definitions.ts | 4 +- .../src/graphql-transformer/index.ts | 3 +- .../sandbox-mode-helpers.ts | 69 +++ .../graphql-transformer/transform-config.ts | 98 ++++ .../transform-graphql-schema-v1.ts | 465 +++++++++++++++++ .../transform-graphql-schema-v2.ts | 473 ++++++++++++++++++ .../transform-graphql-schema.ts | 18 + .../transformer-version.ts | 2 +- .../graphql-transformer/user-defined-slots.ts | 71 +++ .../src/graphql-transformer/utils.ts | 321 ++++++++++++ 21 files changed, 2493 insertions(+), 5 deletions(-) create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts create mode 100644 packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/api-utils.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-config.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts create mode 100644 packages/amplify-category-api/src/graphql-transformer/utils.ts diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 21154646f9..0a973aee18 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -107,7 +107,10 @@ "graphql-transformer-core": "^7.5.0", "graphql-versioned-transformer": "^5.2.32", "import-from": "^3.0.0", - "import-global": "^0.1.0" + "import-global": "^0.1.0", + "rimraf": "^3.0.0", + "cloudform": "^4.2.0", + "cloudform-types": "^4.2.0" }, "devDependencies": { "@aws-cdk/assertions": "~1.124.0", 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 new file mode 100644 index 0000000000..8dad60e4d2 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/api-key-helpers.test.ts @@ -0,0 +1,24 @@ +import { ApiKeyConfig } from '@aws-amplify/graphql-transformer-interfaces'; +import { hasApiKey } from '../../graphql-transformer/api-key-helpers'; + +jest.mock('amplify-cli-core', () => { + const original = jest.requireActual('amplify-cli-core'); + return { + ...original, + ApiCategoryFacade: { + 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 new file mode 100644 index 0000000000..68eb483da6 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/graphql-push-schema-checks.test.ts @@ -0,0 +1,130 @@ +import { stateManager, FeatureFlags, getGraphQLTransformerOpenSearchProductionDocLink } from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import { searchablePushChecks } from '../../graphql-transformer/api-utils'; + +jest.mock('amplify-cli-core'); +jest.mock('amplify-prompts'); + +const printerMock = printer as jest.Mocked; +const stateManagerMock = stateManager as jest.Mocked; +const FeatureFlagsMock = FeatureFlags as jest.Mocked; +const getGraphQLTransformerOpenSearchProductionDocLinkMock = getGraphQLTransformerOpenSearchProductionDocLink as jest.MockedFunction< + typeof getGraphQLTransformerOpenSearchProductionDocLink +>; +getGraphQLTransformerOpenSearchProductionDocLinkMock.mockReturnValue('mockDocsLink'); + +FeatureFlags.getNumber = jest.fn().mockReturnValue(2); +describe('graphql schema checks', () => { + const contextMock = { + amplify: { + getEnvInfo: jest.fn(), + }, + }; + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should warn users if they use not recommended open search instance without overrides', async () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({}); + contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); + const map = { Post: ['model', 'searchable'] }; + await searchablePushChecks(contextMock, map, 'test_api_name'); + expect(printerMock.warn).lastCalledWith( + 'Your instance type for OpenSearch is t2.small.elasticsearch, you may experience performance issues or data loss. Consider reconfiguring with the instructions here mockDocsLink', + ); + }); + + it('should warn users if they use not recommended open search instance with overrides', async () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + test: { + categories: { + api: { + test_api_name: { + ElasticSearchInstanceType: 't2.small.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); + const map = { Post: ['model', 'searchable'] }; + await searchablePushChecks(contextMock, map, 'test_api_name'); + expect(printerMock.warn).lastCalledWith( + 'Your instance type for OpenSearch is t2.small.elasticsearch, you may experience performance issues or data loss. Consider reconfiguring with the instructions here mockDocsLink', + ); + }); + + it('should NOT warn users if they use recommended open search instance', async () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + test: { + categories: { + api: { + test_api_name: { + ElasticSearchInstanceType: 't2.medium.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.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 () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + dev: { + categories: { + api: { + test_api_name: { + ElasticSearchInstanceType: 't2.small.elasticsearch', + }, + }, + }, + }, + prod: { + categories: { + api: { + test_api_name: { + ElasticSearchInstanceType: 't2.medium.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.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 () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({}); + contextMock.amplify.getEnvInfo.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 () => { + printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + test: { + categories: {}, + }, + }); + contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); + const map = { Post: ['model', 'searchable'] }; + await searchablePushChecks(contextMock, map, 'test_api_name'); + expect(printerMock.warn).lastCalledWith( + 'Your instance type for OpenSearch is t2.small.elasticsearch, you may experience performance issues or data loss. Consider reconfiguring with the instructions here mockDocsLink', + ); + }); +}); 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 new file mode 100644 index 0000000000..71c1c499e2 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/sandbox-mode-helpers.test.ts @@ -0,0 +1,138 @@ +import { $TSContext } from 'amplify-cli-core'; +import chalk from 'chalk'; +import * as prompts from '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'; + ctx = { + amplify: { + getEnvInfo() { + return { envName }; + }, + 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('checks for "globalAuthRule"', () => { + const schema = ` + input AMPLIFY { auth_rule: AuthenticationRule = { allow: public } } + `; + + expect(() => schemaHasSandboxModeEnabled(schema, 'mockLink')).toThrow( + Error('input AMPLIFY requires "globalAuthRule" field. Learn more here: mockLink'), + ); + }); + + 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/transformer-feature-flag-adapter.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts new file mode 100644 index 0000000000..0855a9efa4 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/transformer-feature-flag-adapter.test.ts @@ -0,0 +1,94 @@ +import { AmplifyCLIFeatureFlagAdapter } from '../../graphql-transformer/amplify-cli-feature-flag-adapter'; +import { FeatureFlags } from 'amplify-cli-core'; + +jest.mock('amplify-cli-core'); + +describe('AmplifyCLIFeatureFlagAdapter', () => { + const ff = new AmplifyCLIFeatureFlagAdapter(); + const transformerFeatureFlagPrefix = 'graphQLTransformer'; + + describe('getBoolean', () => { + test('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('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('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('getString', () => { + test('test getString to return default value', () => { + const expectedValue = 'StrValue'; + (FeatureFlags.getString).mockReturnValue(expectedValue); + const flagName = 'testFlag'; + expect(ff.getString(flagName, 'some other value')).toEqual(expectedValue); + expect(FeatureFlags.getString).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); + }); + + test('test getString should return defaultValue when the FF throw error', () => { + (FeatureFlags.getString).mockImplementation(() => { + throw new Error('Error'); + }); + const flagName = 'testFlag'; + const expectedValue = 'StrValue'; + expect(ff.getString(flagName, expectedValue)).toEqual(expectedValue); + expect(FeatureFlags.getString).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); + }); + + test('test getString should throw error when defaultValue is missing and the FF throw error', () => { + (FeatureFlags.getString).mockImplementation(() => { + throw new Error('Error'); + }); + const flagName = 'testFlag'; + expect(() => ff.getString(flagName)).toThrowError(); + expect(FeatureFlags.getString).toHaveBeenCalledWith(`${transformerFeatureFlagPrefix}.${flagName}`); + }); + }); + + describe('getNumber', () => { + test('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('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('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/user-defined-slots.test.ts b/packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts new file mode 100644 index 0000000000..13840dadc4 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/user-defined-slots.test.ts @@ -0,0 +1,195 @@ +import { SLOT_NAMES, parseUserDefinedSlots } from '../../graphql-transformer'; + +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 new file mode 100644 index 0000000000..9eab0ca428 --- /dev/null +++ b/packages/amplify-category-api/src/__tests__/graphql-transformer/utils.test.ts @@ -0,0 +1,279 @@ +import { mergeUserConfigWithTransformOutput, writeDeploymentToDisk } from '../../graphql-transformer/utils'; +import { TransformerProjectConfig, DeploymentResources } from '@aws-amplify/graphql-transformer-core'; +import * as fs from 'fs-extra'; +import * as path from 'path'; +import { $TSContext, CloudformationProviderFacade } from 'amplify-cli-core'; + +jest.mock('fs-extra'); +jest.mock('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: {}, + 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: {}, + 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: {}, + 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.', + }, + }, + }, + }, + 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.', + }, + }, + }, + }); + }); + }); + }); +}); 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 new file mode 100644 index 0000000000..24b977a416 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/amplify-cli-feature-flag-adapter.ts @@ -0,0 +1,41 @@ +import { FeatureFlags } from 'amplify-cli-core'; +import { FeatureFlagProvider } from 'graphql-transformer-core'; +import { FeatureFlagProvider as NewTransformerFFProvider } from '@aws-amplify/graphql-transformer-interfaces' +export class AmplifyCLIFeatureFlagAdapterBase implements FeatureFlagProvider { + getBoolean(featureName: string, defaultValue?: boolean): boolean { + return this.getValue(featureName, 'boolean', defaultValue); + } + getString(featureName: string, defaultValue?: string): string { + return this.getValue(featureName, 'string', 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; + case 'string': + return FeatureFlags.getString(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 implements NewTransformerFFProvider {} \ No newline at end of file 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 new file mode 100644 index 0000000000..abab1949be --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/api-key-helpers.ts @@ -0,0 +1,6 @@ +import { $TSContext, CloudformationProviderFacade } from '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 new file mode 100644 index 0000000000..2c8640bfa0 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/api-utils.ts @@ -0,0 +1,24 @@ +import { stateManager, getGraphQLTransformerOpenSearchProductionDocLink, ApiCategoryFacade } from "amplify-cli-core"; +import { printer } from "amplify-prompts"; +import { ResourceConstants } from "graphql-transformer-common"; +import _ from "lodash"; + +export async function searchablePushChecks(context, map, apiName): Promise { + const searchableModelTypes = Object.keys(map).filter(type => map[type].includes('searchable') && map[type].includes('model')); + if (searchableModelTypes.length) { + const currEnv = context.amplify.getEnvInfo().envName; + const teamProviderInfo = stateManager.getTeamProviderInfo(); + const instanceType = _.get( + teamProviderInfo, + [currEnv, 'categories', 'api', apiName, 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}`, + ); + } + } + } \ No newline at end of file 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 new file mode 100644 index 0000000000..8d97b0c226 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/auth-mode-compare.ts @@ -0,0 +1,38 @@ +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 comparision + 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; +} \ No newline at end of file diff --git a/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts b/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts index edfc132952..376d50b0e1 100644 --- a/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts +++ b/packages/amplify-category-api/src/graphql-transformer/directive-definitions.ts @@ -3,9 +3,9 @@ import { } from '@aws-amplify/graphql-transformer-core'; import { $TSContext, - ApiCategoryFacade, } from 'amplify-cli-core'; import { print } from 'graphql'; +import { getTransformerFactory } from './transformer-factory'; import { getTransformerVersion } from './transformer-version'; /** @@ -14,7 +14,7 @@ import { getTransformerVersion } from './transformer-version'; */ export const getDirectiveDefinitions = async (context: $TSContext, resourceDir: string): Promise => { const transformerVersion = await getTransformerVersion(context); - const transformer = await ApiCategoryFacade.getTransformerFactory(context, resourceDir); + const transformer = await getTransformerFactory(context, resourceDir); const transformList = transformerVersion === 2 ? await transformer({ addSearchableTransformer: true, authConfig: {} }) : await transformer(true); diff --git a/packages/amplify-category-api/src/graphql-transformer/index.ts b/packages/amplify-category-api/src/graphql-transformer/index.ts index 21edbf0ae2..9fa8410dc3 100644 --- a/packages/amplify-category-api/src/graphql-transformer/index.ts +++ b/packages/amplify-category-api/src/graphql-transformer/index.ts @@ -1,3 +1,4 @@ export { getDirectiveDefinitions } from './directive-definitions'; export { getTransformerVersion } from './transformer-version'; -export { getTransformerFactory } from './transformer-factory'; +export { SLOT_NAMES, parseUserDefinedSlots } from './user-defined-slots'; +export { transformGraphQLSchema } from './transform-graphql-schema'; 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 new file mode 100644 index 0000000000..ad73aee882 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/sandbox-mode-helpers.ts @@ -0,0 +1,69 @@ +import chalk from 'chalk'; +import { $TSContext } from 'amplify-cli-core'; +import { printer } from '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'; + +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', + ); + 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) { + throw Error(`input AMPLIFY requires "globalAuthRule" field. Learn more here: ${docLink}`); + } + + 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; + } else { + 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 new file mode 100644 index 0000000000..d48a0a5e64 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transform-config.ts @@ -0,0 +1,98 @@ +import { TransformConfig } from '@aws-amplify/graphql-transformer-core'; +import fs from 'fs-extra'; +import { TRANSFORM_CONFIG_FILE_NAME } from 'graphql-transformer-core'; +import * as path from 'path'; + +export interface ProjectOptions { + projectDirectory?: string; + transformersFactory: Function; + transformersFactoryArgs: object[]; + currentCloudBackendDirectory: string; + rootStackFileName?: string; + dryRun?: boolean; + disableFunctionOverrides?: boolean; + disablePipelineFunctionOverrides?: boolean; + disableResolverOverrides?: boolean; + buildParameters?: Object; + minify?: boolean; +} + +/** + * 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 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}`); + } +} + +/** + * 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 Error(`Could not find a schema at ${schemaFilePath}`); + } + 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 new file mode 100644 index 0000000000..5e066c34d9 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v1.ts @@ -0,0 +1,465 @@ +import fs from 'fs-extra'; +import path from 'path'; +import chalk from 'chalk'; +import inquirer from 'inquirer'; +import { AmplifyCLIFeatureFlagAdapter } from './amplify-cli-feature-flag-adapter'; +import { + $TSContext, + AmplifyCategories, + ApiCategoryFacade, + CloudformationProviderFacade, + getGraphQLTransformerAuthDocLink, + getGraphQLTransformerAuthSubscriptionsDocLink, + getGraphQLTransformerOpenSearchProductionDocLink, + JSONUtilities, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { isAuthModeUpdated } from './auth-mode-compare'; +import { + collectDirectivesByTypeNames, + readTransformerConfiguration, + writeTransformerConfiguration, + TRANSFORM_CONFIG_FILE_NAME, + TRANSFORM_BASE_VERSION, + CLOUDFORMATION_FILE_NAME, + revertAPIMigration, + migrateAPIProject, + readProjectConfiguration, + buildAPIProject, + getSanityCheckRules, +} from 'graphql-transformer-core'; +import { exitOnNextTick } from 'amplify-cli-core'; +import { searchablePushChecks } from './api-utils'; +import { getTransformerFactory } 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 ? false : true; + + 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 getTransformerFactory(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, + minify: options.minify, + 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 new file mode 100644 index 0000000000..425806e0f6 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema-v2.ts @@ -0,0 +1,473 @@ +import { + collectDirectivesByTypeNames, + DeploymentResources, + GraphQLTransform, + ResolverConfig, + TransformerProjectConfig, +} from '@aws-amplify/graphql-transformer-core'; +import { Template } from '@aws-amplify/graphql-transformer-core/lib/config/project-config'; +import { OverrideConfig } from '@aws-amplify/graphql-transformer-core/lib/transformation/types'; +import { AppSyncAuthConfiguration, TransformerPluginProvider } from '@aws-amplify/graphql-transformer-interfaces'; +import { + $TSAny, + $TSContext, + $TSMeta, + $TSObject, + AmplifyCategories, + AmplifySupportedService, + ApiCategoryFacade, + CloudformationProviderFacade, + getGraphQLTransformerAuthDocLink, + JSONUtilities, + pathManager, + stateManager, +} from 'amplify-cli-core'; +import { printer } from 'amplify-prompts'; +import fs from 'fs-extra'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { + DiffRule, + getSanityCheckRules, + loadProject, + ProjectRule, + sanityCheckProject, +} from 'graphql-transformer-core'; +import _ from 'lodash'; +import path from 'path'; +/* eslint-disable-next-line import/no-cycle */ +import { searchablePushChecks } from './api-utils'; +import { AmplifyCLIFeatureFlagAdapter } from './amplify-cli-feature-flag-adapter'; +import { isAuthModeUpdated } from './auth-mode-compare'; +import { schemaHasSandboxModeEnabled, showGlobalSandboxModeWarning, showSandboxModePrompts } from './sandbox-mode-helpers'; +import { parseUserDefinedSlots } from './user-defined-slots'; +import { + getAdminRoles, getIdentityPoolId, mergeUserConfigWithTransformOutput, writeDeploymentToDisk, +} from './utils'; +import { getTransformerFactory } from './transformer-factory'; + +const PARAMETERS_FILENAME = 'parameters.json'; +const SCHEMA_FILENAME = 'schema.graphql'; +const SCHEMA_DIR_NAME = 'schema'; +const ROOT_APPSYNC_S3_KEY = 'amplify-appsync-files'; +const DESTRUCTIVE_UPDATES_FLAG = 'allow-destructive-graphql-schema-updates'; +const PROVIDER_NAME = 'awscloudformation'; + +type SanityCheckRules = { + diffRules: DiffRule[]; + projectRules: ProjectRule[]; +}; + +const warnOnAuth = (map: $TSObject, 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'); + } +}; + +/** + * 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.existsSync(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; + } + } + + 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', + [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 auth transformer we get any admin roles and a cognito identity pool to check for + // potential authenticated roles outside of the provided authRole + const adminRoles = await getAdminRoles(context, resourceName); + const identityPoolId = await getIdentityPoolId(context); + + // for the predictions directive get storage config + const s3Resource = s3ResourceAlreadyExists(); + const storageConfig = s3Resource ? getBucketName(s3Resource) : undefined; + + 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)); + 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, + }; + + // 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); + } + + const project = await loadProject(resourceDir); + + const lastDeployedProjectConfig = fs.existsSync(previouslyDeployedBackendDir) + ? await loadProject(previouslyDeployedBackendDir) + : undefined; + const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); + const docLink = getGraphQLTransformerAuthDocLink(transformerVersion); + const sandboxModeEnabled = schemaHasSandboxModeEnabled(project.schema, docLink); + const directiveMap = collectDirectivesByTypeNames(project.schema); + const hasApiKey = authConfig.defaultAuthentication.authenticationType === 'API_KEY' + || authConfig.additionalAuthenticationProviders.some(a => a.authenticationType === 'API_KEY'); + const showSandboxModeMessage = sandboxModeEnabled && hasApiKey; + + if (showSandboxModeMessage) { + showGlobalSandboxModeWarning(docLink); + } else { + warnOnAuth(directiveMap.types, docLink); + } + + searchablePushChecks(context, directiveMap.types, parameters[ResourceConstants.PARAMETERS.AppSyncApiName]); + + const transformerListFactory = await getTransformerFactory(context, resourceDir); + + if (sandboxModeEnabled && options.promptApiKeyCreation) { + const apiKeyConfig = await showSandboxModePrompts(context); + if (apiKeyConfig) authConfig.additionalAuthenticationProviders.push(apiKeyConfig); + } + + let searchableTransformerFlag = false; + + if (directiveMap.directives.includes('searchable')) { + searchableTransformerFlag = true; + } + + // 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', + [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 buildConfig: ProjectOptions = { + ...options, + buildParameters, + projectDirectory: resourceDir, + transformersFactory: transformerListFactory, + transformersFactoryArgs: { + addSearchableTransformer: searchableTransformerFlag, + storageConfig, + authConfig, + adminRoles, + identityPoolId, + }, + rootStackFileName: 'cloudformation-template.json', + currentCloudBackendDirectory: previouslyDeployedBackendDir, + minify: options.minify, + projectConfig: project, + lastDeployedProjectConfig, + authConfig, + sandboxModeEnabled, + sanityCheckRules, + resolverConfig, + }; + + 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 getProjectBucket = (): string => { + const meta: $TSMeta = stateManager.getMeta(undefined, { throwIfNotExist: false }); + const projectBucket = meta?.providers ? meta.providers[PROVIDER_NAME].DeploymentBucketName : ''; + return projectBucket; +}; + +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; + } +}; + +/** + * 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; + } +}; + +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: $TSObject; + // 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 }; +}; + +type TransformerFactoryArgs = { + addSearchableTransformer: boolean; + authConfig: $TSAny; + storageConfig?: $TSAny; + adminRoles?: Array; + identityPoolId?: string; +}; + +/** + * ProjectOptions Type Definition + */ +type ProjectOptions = { + buildParameters: { + S3DeploymentBucket: string; + S3DeploymentRootKey: string; + }; + projectDirectory: string; + transformersFactory: (options: T) => Promise; + transformersFactoryArgs: T; + rootStackFileName: 'cloudformation-template.json'; + currentCloudBackendDirectory?: string; + minify: boolean; + lastDeployedProjectConfig?: TransformerProjectConfig; + projectConfig: TransformerProjectConfig; + resolverConfig?: ResolverConfig; + dryRun?: boolean; + authConfig?: AppSyncAuthConfiguration; + stacks: Record; + sandboxModeEnabled?: boolean; + sanityCheckRules: SanityCheckRules; + overrideConfig: OverrideConfig; +}; + +/** + * buildAPIProject + */ +const buildAPIProject = async ( + context: $TSContext, + opts: ProjectOptions, +): Promise => { + const schema = opts.projectConfig.schema.toString(); + // Skip building the project if the schema is blank + if (!schema) { + return undefined; + } + + const builtProject = await _buildProject(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, opts.minify); + await sanityCheckProject( + currentCloudLocation, + buildLocation, + opts.rootStackFileName, + opts.sanityCheckRules.diffRules, + opts.sanityCheckRules.projectRules, + ); + } + + // TODO: update local env on api compile + // await _updateCurrentMeta(opts); + + return builtProject; +}; + +const _buildProject = async (opts: ProjectOptions): Promise => { + const userProjectConfig = opts.projectConfig; + const stackMapping = userProjectConfig.config.StackMapping; + const userDefinedSlots = { + ...parseUserDefinedSlots(userProjectConfig.pipelineFunctions), + ...parseUserDefinedSlots(userProjectConfig.resolvers), + }; + + // Create the transformer instances, we've to make sure we're not reusing them within the same CLI command + // because the StackMapping feature already builds the project once. + const transformers = await opts.transformersFactory(opts.transformersFactoryArgs); + const transform = new GraphQLTransform({ + transformers, + stackMapping, + transformConfig: userProjectConfig.config, + authConfig: opts.authConfig, + buildParameters: opts.buildParameters, + stacks: opts.projectConfig.stacks || {}, + featureFlags: new AmplifyCLIFeatureFlagAdapter(), + sandboxModeEnabled: opts.sandboxModeEnabled, + userDefinedSlots, + resolverConfig: opts.resolverConfig, + overrideConfig: opts.overrideConfig, + }); + + const schema = userProjectConfig.schema.toString(); + const transformOutput = transform.transform(schema); + + return mergeUserConfigWithTransformOutput(userProjectConfig, transformOutput, opts); +}; 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 new file mode 100644 index 0000000000..3c23a4ebff --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/transform-graphql-schema.ts @@ -0,0 +1,18 @@ +import { DeploymentResources as DeploymentResourcesV2 } from '@aws-amplify/graphql-transformer-core'; +import { DeploymentResources as DeploymentResourcesV1 } from 'graphql-transformer-core'; +import { $TSAny, $TSContext, ApiCategoryFacade } from 'amplify-cli-core'; +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: $TSAny, +): Promise => { + const transformerVersion = await ApiCategoryFacade.getTransformerVersion(context); + return transformerVersion === 2 + ? transformGraphQLSchemaV2(context, options) + : transformGraphQLSchemaV1(context, options); +}; diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts index e5f84e78ab..144441cf6d 100644 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts +++ b/packages/amplify-category-api/src/graphql-transformer/transformer-version.ts @@ -2,8 +2,8 @@ import { $TSContext, pathManager, stateManager, + FeatureFlags, } from 'amplify-cli-core'; -import { FeatureFlags } from 'amplify-cli-core'; /** * Shorthand for Feature flag retrieval. 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 new file mode 100644 index 0000000000..4d55860888 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/user-defined-slots.ts @@ -0,0 +1,71 @@ +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 new file mode 100644 index 0000000000..4de9bcd9f2 --- /dev/null +++ b/packages/amplify-category-api/src/graphql-transformer/utils.ts @@ -0,0 +1,321 @@ +import fs from 'fs-extra'; +import * as path from 'path'; +import { TransformerProjectConfig, DeploymentResources } from '@aws-amplify/graphql-transformer-core'; +import rimraf from 'rimraf'; +import { $TSContext, AmplifyCategories, CloudformationProviderFacade, JSONUtilities, pathManager, stateManager } from 'amplify-cli-core'; +import { CloudFormation, Fn } from 'cloudform'; +import { ResourceConstants } from 'graphql-transformer-common'; +import { pullAllBy, find } from 'lodash'; +import { printer } from 'amplify-prompts'; + +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; +} + +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) { + adminRoles.push(...customRoleConfig.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.functions; + const resolvers = transformOutput.resolvers; + const pipelineFunctions = transformOutput.pipelineFunctions; + + 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'); + + let 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: string = 'rootStack.json', + buildParameters: Object, + minify = false, +) { + fs.ensureDirSync(directory); + // Delete the last deployments resources except for tsconfig if present + emptyBuildDirPreserveTsconfig(directory); + + // Write the schema to disk + const schema = deployment.schema; + 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, { minify })); + } + + // 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.rootStack; + const rootStackPath = path.normalize(directory + `/${rootStackFileName}`); + const rootStackString = minify ? JSON.stringify(rootStack) : 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); + } + }); +}; From 61777aeb86c6e53dbeb8a9562240b88c22839d6c Mon Sep 17 00:00:00 2001 From: John Hockett Date: Fri, 13 May 2022 14:34:46 -0700 Subject: [PATCH 578/587] chore: bump internal dependencies (#10392) * chore: bump dependencies * chore: rebase and bump dependencies --- packages/amplify-category-api/package.json | 46 +++++++++++----------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 0a973aee18..b8e96c9319 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -21,7 +21,7 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-transformer-migrator": "^1.2.36", + "@aws-amplify/graphql-transformer-migrator": "^1.2.37", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -83,29 +83,29 @@ "lodash": "^4.17.21", "ora": "^4.0.3", "uuid": "^8.3.2", - "@aws-amplify/graphql-auth-transformer": "^0.9.0", - "@aws-amplify/graphql-default-value-transformer": "^0.5.22", - "@aws-amplify/graphql-function-transformer": "^0.7.16", - "@aws-amplify/graphql-http-transformer": "^0.8.16", - "@aws-amplify/graphql-index-transformer": "^0.11.7", - "@aws-amplify/graphql-maps-to-transformer": "^1.1.14", - "@aws-amplify/graphql-model-transformer": "^0.14.0", - "@aws-amplify/graphql-predictions-transformer": "^0.6.16", - "@aws-amplify/graphql-relational-transformer": "^0.9.0", - "@aws-amplify/graphql-searchable-transformer": "^0.14.0", - "@aws-amplify/graphql-transformer-core": "^0.17.0", - "@aws-amplify/graphql-transformer-interfaces": "^1.14.0", - "graphql-auth-transformer": "^7.2.32", - "graphql-connection-transformer": "^5.2.32", - "graphql-dynamodb-transformer": "^7.2.32", - "graphql-elasticsearch-transformer": "^5.2.32", - "graphql-function-transformer": "^3.3.23", - "graphql-http-transformer": "^5.2.32", - "graphql-key-transformer": "^3.2.32", - "graphql-predictions-transformer": "^3.2.32", + "@aws-amplify/graphql-auth-transformer": "^0.9.1", + "@aws-amplify/graphql-default-value-transformer": "^0.5.23", + "@aws-amplify/graphql-function-transformer": "^0.7.17", + "@aws-amplify/graphql-http-transformer": "^0.8.17", + "@aws-amplify/graphql-index-transformer": "^0.11.8", + "@aws-amplify/graphql-maps-to-transformer": "^1.1.15", + "@aws-amplify/graphql-model-transformer": "^0.14.1", + "@aws-amplify/graphql-predictions-transformer": "^0.6.17", + "@aws-amplify/graphql-relational-transformer": "^0.9.1", + "@aws-amplify/graphql-searchable-transformer": "^0.14.1", + "@aws-amplify/graphql-transformer-core": "^0.17.1", + "@aws-amplify/graphql-transformer-interfaces": "^1.14.1", + "graphql-auth-transformer": "^7.2.33", + "graphql-connection-transformer": "^5.2.33", + "graphql-dynamodb-transformer": "^7.2.33", + "graphql-elasticsearch-transformer": "^5.2.33", + "graphql-function-transformer": "^3.3.24", + "graphql-http-transformer": "^5.2.33", + "graphql-key-transformer": "^3.2.33", + "graphql-predictions-transformer": "^3.2.33", "graphql-transformer-common": "^4.23.0", - "graphql-transformer-core": "^7.5.0", - "graphql-versioned-transformer": "^5.2.32", + "graphql-transformer-core": "^7.5.1", + "graphql-versioned-transformer": "^5.2.33", "import-from": "^3.0.0", "import-global": "^0.1.0", "rimraf": "^3.0.0", From 2ca26c9f66fabd6c988ee585e23f3312956498b6 Mon Sep 17 00:00:00 2001 From: Zeyu Li Date: Fri, 13 May 2022 14:35:18 -0700 Subject: [PATCH 579/587] fix: opensearch instance type check during push (#10389) * fix: opensearch instance type check during push * fix: rm tranformer version check * add legacy es instance tests * fix: unit test --- .../graphql-push-schema-checks.test.ts | 79 ++++++++++++++++--- .../src/graphql-transformer/api-utils.ts | 10 +-- 2 files changed, 75 insertions(+), 14 deletions(-) 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 index 68eb483da6..449939fc49 100644 --- 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 @@ -1,4 +1,4 @@ -import { stateManager, FeatureFlags, getGraphQLTransformerOpenSearchProductionDocLink } from 'amplify-cli-core'; +import { stateManager, getGraphQLTransformerOpenSearchProductionDocLink, ApiCategoryFacade } from 'amplify-cli-core'; import { printer } from 'amplify-prompts'; import { searchablePushChecks } from '../../graphql-transformer/api-utils'; @@ -7,13 +7,15 @@ jest.mock('amplify-prompts'); const printerMock = printer as jest.Mocked; const stateManagerMock = stateManager as jest.Mocked; -const FeatureFlagsMock = FeatureFlags as jest.Mocked; +const getTransformerVersionMock = ApiCategoryFacade.getTransformerVersion as jest.MockedFunction 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))); -FeatureFlags.getNumber = jest.fn().mockReturnValue(2); describe('graphql schema checks', () => { const contextMock = { amplify: { @@ -26,7 +28,6 @@ describe('graphql schema checks', () => { }); it('should warn users if they use not recommended open search instance without overrides', async () => { - printerMock.warn.mockImplementation(jest.fn()); stateManagerMock.getTeamProviderInfo.mockReturnValue({}); contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); const map = { Post: ['model', 'searchable'] }; @@ -37,7 +38,26 @@ describe('graphql schema checks', () => { }); it('should warn users if they use not recommended open search instance with overrides', async () => { - printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + test: { + categories: { + api: { + test_api_name: { + OpenSearchInstanceType: 't2.small.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); + const map = { Post: ['model', 'searchable'] }; + await searchablePushChecks(contextMock, map, 'test_api_name'); + expect(printerMock.warn).lastCalledWith( + 'Your instance type for OpenSearch is t2.small.elasticsearch, you may experience performance issues or data loss. Consider reconfiguring with the instructions here mockDocsLink', + ); + }); + + it('should warn users if they use not recommended elastic search instance with overrides', async () => { stateManagerMock.getTeamProviderInfo.mockReturnValue({ test: { categories: { @@ -58,7 +78,24 @@ describe('graphql schema checks', () => { }); it('should NOT warn users if they use recommended open search instance', async () => { - printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + test: { + categories: { + api: { + test_api_name: { + OpenSearchInstanceType: 't2.medium.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.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 () => { stateManagerMock.getTeamProviderInfo.mockReturnValue({ test: { categories: { @@ -77,7 +114,33 @@ describe('graphql schema checks', () => { }); it('should NOT warn users if they use recommended open search instance on the environment', async () => { - printerMock.warn.mockImplementation(jest.fn()); + stateManagerMock.getTeamProviderInfo.mockReturnValue({ + dev: { + categories: { + api: { + test_api_name: { + OpenSearchInstanceType: 't2.small.elasticsearch', + }, + }, + }, + }, + prod: { + categories: { + api: { + test_api_name: { + OpenSearchInstanceType: 't2.medium.elasticsearch', + }, + }, + }, + }, + }); + contextMock.amplify.getEnvInfo.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 () => { stateManagerMock.getTeamProviderInfo.mockReturnValue({ dev: { categories: { @@ -105,7 +168,6 @@ describe('graphql schema checks', () => { }); it('should NOT warn users if they do NOT use searchable', async () => { - printerMock.warn.mockImplementation(jest.fn()); stateManagerMock.getTeamProviderInfo.mockReturnValue({}); contextMock.amplify.getEnvInfo.mockReturnValue({ envName: 'test' }); const map = { Post: ['model'] }; @@ -114,7 +176,6 @@ describe('graphql schema checks', () => { }); it('should warn users if they use not recommended open search instance with overrides', async () => { - printerMock.warn.mockImplementation(jest.fn()); stateManagerMock.getTeamProviderInfo.mockReturnValue({ test: { categories: {}, diff --git a/packages/amplify-category-api/src/graphql-transformer/api-utils.ts b/packages/amplify-category-api/src/graphql-transformer/api-utils.ts index 2c8640bfa0..661608fd97 100644 --- a/packages/amplify-category-api/src/graphql-transformer/api-utils.ts +++ b/packages/amplify-category-api/src/graphql-transformer/api-utils.ts @@ -8,11 +8,11 @@ export async function searchablePushChecks(context, map, apiName): Promise if (searchableModelTypes.length) { const currEnv = context.amplify.getEnvInfo().envName; const teamProviderInfo = stateManager.getTeamProviderInfo(); - const instanceType = _.get( - teamProviderInfo, - [currEnv, 'categories', 'api', apiName, ResourceConstants.PARAMETERS.ElasticsearchInstanceType], - 't2.small.elasticsearch', - ); + const getInstanceType = (instanceTypeParam: string) => _.get(teamProviderInfo, [currEnv, 'categories', 'api', apiName, 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); From b72f9e7870640fc11897ef7e1b60e24e97f9052f Mon Sep 17 00:00:00 2001 From: Edward Foyle Date: Fri, 13 May 2022 14:37:58 -0700 Subject: [PATCH 580/587] chore: lint files that touch `team-provider-info.json` (#10418) * chore: lint files that touch TPI * chore: remove no-await-in-loop overrides * chore: fix a few more files * chore: fix test * chore: address PR comments * chore: revert yarn lock changes Co-authored-by: Christopher Sundersingh <83315412+sundersc@users.noreply.github.com> --- .../commands/api/add-graphql-datasource.ts | 68 ++++--- packages/amplify-category-api/src/index.ts | 166 +++++++++++------- .../provider-utils/supported-datasources.ts | 2 +- 3 files changed, 142 insertions(+), 94 deletions(-) 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 index ae779b7ca3..31179381d3 100644 --- a/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts +++ b/packages/amplify-category-api/src/commands/api/add-graphql-datasource.ts @@ -1,5 +1,7 @@ import { mergeTypeDefs } from '@graphql-tools/merge'; -import { $TSAny, $TSContext, exitOnNextTick, FeatureFlags, pathManager, ResourceDoesNotExistError, stateManager } from 'amplify-cli-core'; +import { + $TSAny, $TSContext, exitOnNextTick, FeatureFlags, pathManager, ResourceDoesNotExistError, stateManager, +} from 'amplify-cli-core'; import { printer } from 'amplify-prompts'; import * as fs from 'fs-extra'; import * as graphql from 'graphql'; @@ -11,7 +13,7 @@ import { import inquirer from 'inquirer'; import _ from 'lodash'; import * as path from 'path'; -import { supportedDatasources } from '../../provider-utils/supported-datasources'; +import { supportedDataSources } from '../../provider-utils/supported-datasources'; const subcommand = 'add-graphql-datasource'; const categories = 'categories'; @@ -20,11 +22,14 @@ const providerName = 'awscloudformation'; export const name = subcommand; -export const run = async (context: $TSContext) => { +/** + * Entry point for adding RDS data source + */ +export const run = async (context: $TSContext): Promise => { try { const AWS = await getAwsClient(context, 'list'); - const result: $TSAny = await datasourceSelectionPrompt(context, supportedDatasources); + const result: $TSAny = await datasourceSelectionPrompt(context, supportedDataSources); const providerController = await import(path.join('..', '..', 'provider-utils', result.providerName, 'index')); @@ -42,10 +47,10 @@ export const run = async (context: $TSContext) => { * Write the new env specific datasource information into * the team-provider-info file */ - const currEnv = context.amplify.getEnvInfo().envName; + const currentEnv = context.amplify.getEnvInfo().envName; const teamProviderInfo = stateManager.getTeamProviderInfo(); - _.set(teamProviderInfo, [currEnv, categories, category, resourceName], { + _.set(teamProviderInfo, [currentEnv, categories, category, resourceName], { rdsRegion: answers.region, rdsClusterIdentifier: answers.dbClusterArn, rdsSecretStoreArn: answers.secretStoreArn, @@ -56,7 +61,7 @@ export const run = async (context: $TSContext) => { const backendConfig = stateManager.getBackendConfig(); - backendConfig[category][resourceName]['rdsInit'] = true; + backendConfig[category][resourceName].rdsInit = true; stateManager.setBackendConfig(undefined, backendConfig); @@ -73,8 +78,9 @@ export const run = async (context: $TSContext) => { /** * Instantiate a new Relational Schema Transformer and perform - * the db instrospection to get the GraphQL Schema and Template Context + * 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(); @@ -99,10 +105,10 @@ export const run = async (context: $TSContext) => { if (fs.existsSync(graphqlSchemaFilePath)) { const typesToBeMerged = [rdsGraphQLSchemaDoc]; - const currGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); + const currentGraphQLSchemaDoc = readSchema(graphqlSchemaFilePath); - if (currGraphQLSchemaDoc) { - typesToBeMerged.unshift(currGraphQLSchemaDoc); + if (currentGraphQLSchemaDoc) { + typesToBeMerged.unshift(currentGraphQLSchemaDoc); } else { printer.warn(`Graphql Schema file "${graphqlSchemaFilePath}" is empty.`); printer.blankLine(); @@ -159,24 +165,24 @@ export const run = async (context: $TSContext) => { } }; -async function datasourceSelectionPrompt(context: $TSContext, supportedDatasources) { +// 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}`; + 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, + provider: supportedDataSources[datasource].provider, datasource, - providerName: supportedDatasources[datasource].provider, + providerName: supportedDataSources[datasource].provider, }, }); }); if (options.length === 0) { - const errMessage = `No datasources defined by configured providers for category: ${category}`; + const errMessage = `No data sources defined by configured providers for category: ${category}`; printer.error(errMessage); @@ -197,33 +203,37 @@ async function datasourceSelectionPrompt(context: $TSContext, supportedDatasourc const question = [ { name: 'datasource', - message: 'Please select from one of the below mentioned datasources', + message: 'Please select from one of the below mentioned data sources', type: 'list', choices: options, }, ]; return inquirer.prompt(question).then(answer => answer.datasource); -} +}; -async function getAwsClient(context: $TSContext, action: string) { +const getAwsClient = async (context: $TSContext, action: string): Promise<$TSAny> => { const providerPlugins = context.amplify.getProviderPlugins(context); + // eslint-disable-next-line const provider = require(providerPlugins[providerName]); - return await provider.getConfiguredAWSClient(context, 'aurora-serverless', action); -} + return provider.getConfiguredAWSClient(context, 'aurora-serverless', action); +}; -export function readSchema(graphqlSchemaFilePath: string) { +/** + * 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 currGraphQLSchemaDoc: graphql.DocumentNode; + let currentGraphQLSchemaDoc: graphql.DocumentNode; try { - currGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); + currentGraphQLSchemaDoc = graphql.parse(graphqlSchemaRaw); } catch (err) { const relativePathToInput = path.relative(process.cwd(), graphqlSchemaRaw); @@ -234,5 +244,5 @@ export function readSchema(graphqlSchemaFilePath: string) { throw error; } - return currGraphQLSchemaDoc; -} + return currentGraphQLSchemaDoc; +}; diff --git a/packages/amplify-category-api/src/index.ts b/packages/amplify-category-api/src/index.ts index f81d2b2a02..8e492388b0 100644 --- a/packages/amplify-category-api/src/index.ts +++ b/packages/amplify-category-api/src/index.ts @@ -1,10 +1,10 @@ import { + $TSAny, $TSContext, $TSObject, AmplifyCategories, AmplifySupportedService, buildOverrideDir, - exitOnNextTick, pathManager, stateManager, } from 'amplify-cli-core'; @@ -13,7 +13,7 @@ import { validateAddApiRequest, validateUpdateApiRequest } from 'amplify-util-he import * as fs from 'fs-extra'; import * as path from 'path'; import { run } from './commands/api/console'; -import { getAppSyncAuthConfig, getAppSyncResourceName } from './provider-utils/awscloudformation//utils/amplify-meta-utils'; +import { getAppSyncAuthConfig, getAppSyncResourceName } 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'; @@ -21,9 +21,11 @@ import { askAuthQuestions } from './provider-utils/awscloudformation/service-wal 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'; + export { NETWORK_STACK_LOGICAL_ID } from './category-constants'; -export { addAdminQueriesApi, updateAdminQueriesApi } from './provider-utils/awscloudformation/'; +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'; @@ -42,45 +44,60 @@ export * from './graphql-transformer'; const category = AmplifyCategories.API; const categories = 'categories'; -export async function console(context: $TSContext) { +/** + * Open the AppSync/API Gateway AWS console + */ +export const console = async (context: $TSContext): Promise => { await run(context); -} +}; -export async function migrate(context: $TSContext, serviceName?: string) { +/** + * 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) { - 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') + 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), ); - if (providerController) { - 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; + } 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; } -} +}; -export async function initEnv(context: $TSContext) { +/** + * Setup new environment with rds datasource + */ +export const initEnv = async (context: $TSContext): Promise => { const datasource = 'Aurora Serverless'; const service = 'service'; const rdsInit = 'rdsInit'; @@ -138,50 +155,54 @@ export async function initEnv(context: $TSContext) { /** * Check team provider info to ensure it hasn't already been created for current env */ - const currEnv = amplify.getEnvInfo().envName; + const currentEnv = amplify.getEnvInfo().envName; const teamProviderInfo = stateManager.getTeamProviderInfo(); if ( - teamProviderInfo[currEnv][categories] && - teamProviderInfo[currEnv][categories][category] && - teamProviderInfo[currEnv][categories][category][resourceName] && - teamProviderInfo[currEnv][categories][category][resourceName] && - teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] + teamProviderInfo[currentEnv][categories] + && teamProviderInfo[currentEnv][categories][category] + && teamProviderInfo[currentEnv][categories][category][resourceName] + && teamProviderInfo[currentEnv][categories][category][resourceName] + && teamProviderInfo[currentEnv][categories][category][resourceName][rdsRegion] ) { return; } - /** - * Execute the walkthrough - */ - return providerController + // execute the walkthrough + await providerController .addDatasource(context, category, datasource) .then(answers => { /** * Write the new answers to the team provider info */ - if (!teamProviderInfo[currEnv][categories]) { - teamProviderInfo[currEnv][categories] = {}; + if (!teamProviderInfo[currentEnv][categories]) { + teamProviderInfo[currentEnv][categories] = {}; } - if (!teamProviderInfo[currEnv][categories][category]) { - teamProviderInfo[currEnv][categories][category] = {}; + if (!teamProviderInfo[currentEnv][categories][category]) { + teamProviderInfo[currentEnv][categories][category] = {}; } - if (!teamProviderInfo[currEnv][categories][category][resourceName]) { - teamProviderInfo[currEnv][categories][category][resourceName] = {}; + if (!teamProviderInfo[currentEnv][categories][category][resourceName]) { + teamProviderInfo[currentEnv][categories][category][resourceName] = {}; } - teamProviderInfo[currEnv][categories][category][resourceName][rdsRegion] = answers.region; - teamProviderInfo[currEnv][categories][category][resourceName][rdsClusterIdentifier] = answers.dbClusterArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; - teamProviderInfo[currEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; + teamProviderInfo[currentEnv][categories][category][resourceName][rdsRegion] = answers.region; + teamProviderInfo[currentEnv][categories][category][resourceName][rdsClusterIdentifier] = answers.dbClusterArn; + teamProviderInfo[currentEnv][categories][category][resourceName][rdsSecretStoreArn] = answers.secretStoreArn; + teamProviderInfo[currentEnv][categories][category][resourceName][rdsDatabaseName] = answers.databaseName; stateManager.setTeamProviderInfo(undefined, teamProviderInfo); }) .then(() => { context.amplify.executeProviderUtils(context, 'awscloudformation', 'compileSchema', { forceCompile: true }); }); -} +}; -export async function getPermissionPolicies(context: $TSContext, resourceOpsMapping: $TSObject) { +/** + * Get permissions for depending on this resource + */ +export const getPermissionPolicies = async ( + context: $TSContext, + resourceOpsMapping: $TSObject, +): Promise<{ permissionPolicies: $TSAny[]; resourceAttributes: $TSAny[]; }> => { const amplifyMeta = stateManager.getMeta(); const permissionPolicies = []; const resourceAttributes = []; @@ -210,9 +231,12 @@ export async function getPermissionPolicies(context: $TSContext, resourceOpsMapp }), ); return { permissionPolicies, resourceAttributes }; -} +}; -export async function executeAmplifyCommand(context: $TSContext) { +/** + * 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); @@ -233,35 +257,46 @@ export async function executeAmplifyCommand(context: $TSContext) { } process.exitCode = 1; } -} +}; -export const executeAmplifyHeadlessCommand = async (context: $TSContext, headlessPayload: string) => { +/** + * 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': + 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`); } }; -export async function handleAmplifyEvent(context: $TSContext, args) { +/** + * Not yet implemented + */ +export const handleAmplifyEvent = async (_: $TSContext, args): Promise => { printer.info(`${category} handleAmplifyEvent to be implemented`); printer.info(`Received event args ${args}`); -} +}; -export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TSObject) { +/** + * 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: $TSObject) => { const { authType, printLeadText, authSettings } = args; const meta = stateManager.getMeta(); const apiName = getAppSyncResourceName(meta); if (!apiName) { - return; + return undefined; } const authConfig = getAppSyncAuthConfig(meta); @@ -284,9 +319,12 @@ export async function addGraphQLAuthorizationMode(context: $TSContext, args: $TS ); return addAuthConfig; -} +}; -export async function transformCategoryStack(context: $TSContext, resource: $TSObject) { +/** + * Synthesize the CFN template for the API + */ +export const transformCategoryStack = async (context: $TSContext, resource: $TSObject): Promise => { if (resource.service === AmplifySupportedService.APPSYNC) { if (canResourceBeTransformed(resource.resourceName)) { const backendDir = pathManager.getBackendDirPath(); @@ -301,7 +339,7 @@ export async function transformCategoryStack(context: $TSContext, resource: $TSO forceCompile: true, overrideConfig: { overrideFlag: isBuild, - overrideDir: overrideDir, + overrideDir, resourceName: resource.resourceName, }, }, @@ -314,8 +352,8 @@ export async function transformCategoryStack(context: $TSContext, resource: $TSO apigwStack.transform(); } } -} +}; -function canResourceBeTransformed(resourceName: string) { - return stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); -} +const canResourceBeTransformed = ( + resourceName: string, +): boolean => stateManager.resourceInputsJsonExists(undefined, AmplifyCategories.API, resourceName); diff --git a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts index b0e2a08bf6..08fb905ac6 100644 --- a/packages/amplify-category-api/src/provider-utils/supported-datasources.ts +++ b/packages/amplify-category-api/src/provider-utils/supported-datasources.ts @@ -1,4 +1,4 @@ -export const supportedDatasources = { +export const supportedDataSources = { 'Aurora Serverless': { inputs: [ { From 80a02fd6dcca4ab45de3850d5e9a7119ba796cc5 Mon Sep 17 00:00:00 2001 From: Pavel Lazar <85319655+lazpavel@users.noreply.github.com> Date: Tue, 17 May 2022 13:50:08 -0400 Subject: [PATCH 581/587] chore(amplify-provider-awscloudformation): change transformers order (#10427) --- .../src/graphql-transformer/transformer-factory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts b/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts index 1dd04b75b4..f817b2f688 100644 --- a/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts +++ b/packages/amplify-category-api/src/graphql-transformer/transformer-factory.ts @@ -87,10 +87,10 @@ const getTransformerFactoryV2 = ( new PredictionsTransformerV2(options?.storageConfig), new PrimaryKeyTransformerV2(), indexTransformer, - new BelongsToTransformerV2(), new HasManyTransformerV2(), hasOneTransformer, new ManyToManyTransformerV2(modelTransformer, indexTransformer, hasOneTransformer, authTransformer), + new BelongsToTransformerV2(), new DefaultValueTransformerV2(), authTransformer, new MapsToTransformerV2(), From 596a5e14f199fdda7fd39975f7150f0633582e01 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Tue, 24 May 2022 00:49:06 +0000 Subject: [PATCH 582/587] chore(release): Publish [ci skip] - amplify-app@4.2.32 - amplify-category-analytics@4.0.5 - @aws-amplify/amplify-category-api@2.1.1 - @aws-amplify/amplify-category-auth@2.9.0 - @aws-amplify/amplify-category-custom@2.3.31 - amplify-category-function@4.0.5 - amplify-category-geo@2.6.1 - amplify-category-hosting@3.2.30 - amplify-category-interactions@4.0.5 - amplify-category-predictions@4.0.5 - @aws-amplify/amplify-category-storage@3.3.1 - amplify-category-xr@3.2.30 - amplify-cli-core@2.8.0 - @aws-amplify/cli-extensibility-helper@2.3.27 - @aws-amplify/cli@8.3.0 - @aws-amplify/cli-internal@8.3.0 - amplify-console-hosting@2.2.30 - amplify-console-integration-tests@2.2.39 - amplify-container-hosting@2.4.35 - amplify-dotnet-function-template-provider@2.2.34 - amplify-dynamodb-simulator@2.3.0 - amplify-e2e-core@3.2.0 - amplify-e2e-tests@3.10.0 - amplify-frontend-flutter@1.3.4 - amplify-frontend-ios@3.4.4 - amplify-frontend-javascript@3.4.5 - amplify-go-function-runtime-provider@2.2.30 - amplify-graphql-migration-tests@2.2.41 - amplify-java-function-runtime-provider@2.2.30 - amplify-migration-tests@4.5.0 - amplify-nodejs-function-runtime-provider@2.2.30 - amplify-nodejs-function-template-provider@2.4.0 - amplify-provider-awscloudformation@6.2.0 - amplify-python-function-runtime-provider@2.2.30 - amplify-util-import@2.2.30 - amplify-util-mock@4.4.2 - @aws-amplify/amplify-util-uibuilder@1.2.25 --- packages/amplify-category-api/CHANGELOG.md | 11 ++++++ packages/amplify-category-api/package.json | 46 +++++++++++----------- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index bbac0eda97..082b68aa1e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index b8e96c9319..126d0ebd1a 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.1.0", + "version": "2.1.1", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -21,6 +21,18 @@ "access": "public" }, "dependencies": { + "@aws-amplify/graphql-auth-transformer": "^0.9.1", + "@aws-amplify/graphql-default-value-transformer": "^0.5.23", + "@aws-amplify/graphql-function-transformer": "^0.7.17", + "@aws-amplify/graphql-http-transformer": "^0.8.17", + "@aws-amplify/graphql-index-transformer": "^0.11.8", + "@aws-amplify/graphql-maps-to-transformer": "^1.1.15", + "@aws-amplify/graphql-model-transformer": "^0.14.1", + "@aws-amplify/graphql-predictions-transformer": "^0.6.17", + "@aws-amplify/graphql-relational-transformer": "^0.9.1", + "@aws-amplify/graphql-searchable-transformer": "^0.14.1", + "@aws-amplify/graphql-transformer-core": "^0.17.1", + "@aws-amplify/graphql-transformer-interfaces": "^1.14.1", "@aws-amplify/graphql-transformer-migrator": "^1.2.37", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", @@ -68,33 +80,17 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.7.0", + "amplify-cli-core": "2.8.0", "amplify-headless-interface": "1.14.3", "amplify-prompts": "2.1.0", - "amplify-provider-awscloudformation": "6.1.4", + "amplify-provider-awscloudformation": "6.2.0", "amplify-util-headless-input": "1.9.4", "chalk": "^4.1.1", + "cloudform": "^4.2.0", + "cloudform-types": "^4.2.0", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-relational-schema-transformer": "^2.21.6", - "inquirer": "^7.3.3", - "js-yaml": "^4.0.0", - "lodash": "^4.17.21", - "ora": "^4.0.3", - "uuid": "^8.3.2", - "@aws-amplify/graphql-auth-transformer": "^0.9.1", - "@aws-amplify/graphql-default-value-transformer": "^0.5.23", - "@aws-amplify/graphql-function-transformer": "^0.7.17", - "@aws-amplify/graphql-http-transformer": "^0.8.17", - "@aws-amplify/graphql-index-transformer": "^0.11.8", - "@aws-amplify/graphql-maps-to-transformer": "^1.1.15", - "@aws-amplify/graphql-model-transformer": "^0.14.1", - "@aws-amplify/graphql-predictions-transformer": "^0.6.17", - "@aws-amplify/graphql-relational-transformer": "^0.9.1", - "@aws-amplify/graphql-searchable-transformer": "^0.14.1", - "@aws-amplify/graphql-transformer-core": "^0.17.1", - "@aws-amplify/graphql-transformer-interfaces": "^1.14.1", "graphql-auth-transformer": "^7.2.33", "graphql-connection-transformer": "^5.2.33", "graphql-dynamodb-transformer": "^7.2.33", @@ -103,14 +99,18 @@ "graphql-http-transformer": "^5.2.33", "graphql-key-transformer": "^3.2.33", "graphql-predictions-transformer": "^3.2.33", + "graphql-relational-schema-transformer": "^2.21.6", "graphql-transformer-common": "^4.23.0", "graphql-transformer-core": "^7.5.1", "graphql-versioned-transformer": "^5.2.33", "import-from": "^3.0.0", "import-global": "^0.1.0", + "inquirer": "^7.3.3", + "js-yaml": "^4.0.0", + "lodash": "^4.17.21", + "ora": "^4.0.3", "rimraf": "^3.0.0", - "cloudform": "^4.2.0", - "cloudform-types": "^4.2.0" + "uuid": "^8.3.2" }, "devDependencies": { "@aws-cdk/assertions": "~1.124.0", From 2a611e4f9d22455896b9254ef3aa17b14d943ea0 Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 27 May 2022 11:05:45 +0000 Subject: [PATCH 583/587] chore(release): Publish [ci skip] - amplify-app@4.2.33 - amplify-category-analytics@4.0.6 - @aws-amplify/amplify-category-api@2.1.2 - @aws-amplify/amplify-category-auth@2.9.1 - @aws-amplify/amplify-category-custom@2.3.32 - amplify-category-function@4.0.6 - amplify-category-geo@2.6.2 - amplify-category-hosting@3.2.31 - amplify-category-interactions@4.0.6 - amplify-category-predictions@4.0.6 - @aws-amplify/amplify-category-storage@3.3.2 - amplify-category-xr@3.2.31 - amplify-cli-core@2.8.1 - @aws-amplify/cli-extensibility-helper@2.3.28 - @aws-amplify/cli@8.3.1 - @aws-amplify/cli-internal@8.3.1 - amplify-console-hosting@2.2.31 - amplify-console-integration-tests@2.2.40 - amplify-container-hosting@2.4.36 - amplify-dotnet-function-template-provider@2.2.35 - amplify-dynamodb-simulator@2.3.1 - amplify-e2e-core@3.2.1 - amplify-e2e-tests@3.10.1 - amplify-frontend-ios@3.4.5 - amplify-frontend-javascript@3.4.6 - amplify-go-function-runtime-provider@2.2.31 - amplify-java-function-runtime-provider@2.2.31 - amplify-migration-tests@4.5.1 - amplify-nodejs-function-runtime-provider@2.2.31 - amplify-nodejs-function-template-provider@2.4.1 - amplify-provider-awscloudformation@6.2.1 - amplify-python-function-runtime-provider@2.2.31 - amplify-util-import@2.2.31 - amplify-util-mock@4.4.3 - @aws-amplify/amplify-util-uibuilder@1.2.26 --- packages/amplify-category-api/CHANGELOG.md | 8 ++++++++ packages/amplify-category-api/package.json | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 082b68aa1e..8f4578245e 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,14 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [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) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 126d0ebd1a..7cab523f0d 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.1.1", + "version": "2.1.2", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -80,10 +80,10 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.8.0", + "amplify-cli-core": "2.8.1", "amplify-headless-interface": "1.14.3", "amplify-prompts": "2.1.0", - "amplify-provider-awscloudformation": "6.2.0", + "amplify-provider-awscloudformation": "6.2.1", "amplify-util-headless-input": "1.9.4", "chalk": "^4.1.1", "cloudform": "^4.2.0", From a179a32bd86333a0a32cee2dfc7b60da792b72c5 Mon Sep 17 00:00:00 2001 From: MURAKAMI Masahiko Date: Wed, 1 Jun 2022 02:11:00 +0900 Subject: [PATCH 584/587] feat: allow 3rd-party plugins to CDK override (#9601) --- .../appsync-api-input-state.test.ts | 18 ++++++++++++++++-- .../utils/get-appsync-auth-config.test.ts | 18 ++++++++++++++++-- .../transform-graphql-schema-v2.ts | 4 ++-- .../appsync-api-input-state.ts | 13 ++++++++++--- .../awscloudformation/apigw-input-state.ts | 7 ++++++- .../cfn-api-artifact-handler.ts | 13 +++---------- .../utils/check-appsync-api-migration.ts | 2 +- .../utils/get-appsync-auth-config.ts | 5 +++-- .../utils/get-appsync-resolver-config.ts | 5 +++-- 9 files changed, 60 insertions(+), 25 deletions(-) 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 index 97269c82e9..69faba39d3 100644 --- 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 @@ -1,3 +1,4 @@ +import { $TSContext } from 'amplify-cli-core'; import { AppsyncApiInputState } from '../../../../provider-utils/awscloudformation/api-input-manager/appsync-api-input-state'; jest.mock('fs-extra'); @@ -35,14 +36,27 @@ jest.mock('amplify-cli-core', () => ({ }, })); +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(resourceName); + 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(resourceName); + const apiState = new AppsyncApiInputState(mockContext, resourceName); expect(apiState.isCLIInputsValid()).rejects.toThrowError(); }); 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 index 3441f4df77..7dbfe74d3b 100644 --- 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 @@ -1,3 +1,4 @@ +import { $TSContext } from 'amplify-cli-core'; import { getAuthConfig } from '../../../../provider-utils/awscloudformation/utils/get-appsync-auth-config'; const getCLIInputPayload_mock = jest @@ -46,10 +47,23 @@ jest.mock('../../../../provider-utils/awscloudformation/api-input-manager/appsyn }; }); +const mockContext: $TSContext = { + amplify: { + getCategoryPluginInfo: (_context: $TSContext, category: string) => { + return { + packageLocation: `@aws-amplify/amplify-category-${category}`, + }; + }, + }, + input: { + options: {}, + }, +} as unknown as $TSContext; + test('test function with default auth config', async () => { - expect(await getAuthConfig('mockapiResource')).toMatchSnapshot(); + expect(await getAuthConfig(mockContext, 'mockapiResource')).toMatchSnapshot(); }); test('test function with default and additional auth config', async () => { - expect(await getAuthConfig('mockapiResource')).toMatchSnapshot(); + expect(await getAuthConfig(mockContext, 'mockapiResource')).toMatchSnapshot(); }); 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 index 425806e0f6..4064ee9791 100644 --- 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 @@ -161,7 +161,7 @@ export const transformGraphQLSchemaV2 = async (context: $TSContext, options): Pr AmplifyCategories.API, AmplifySupportedService.APPSYNC, 'getAuthConfig', - [resources[0].resourceName], + [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)) { @@ -259,7 +259,7 @@ export const transformGraphQLSchemaV2 = async (context: $TSContext, options): Pr AmplifyCategories.API, AmplifySupportedService.APPSYNC, 'getResolverConfig', - [resources[0].resourceName], + [context, resources[0].resourceName], ); } 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 index 1d0af5e205..4c930016a0 100644 --- 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 @@ -1,4 +1,11 @@ -import { AmplifyCategories, AmplifySupportedService, CLIInputSchemaValidator, JSONUtilities, pathManager } from 'amplify-cli-core'; +import { + $TSContext, + AmplifyCategories, + AmplifySupportedService, + CLIInputSchemaValidator, + JSONUtilities, + pathManager, +} from 'amplify-cli-core'; import * as fs from 'fs-extra'; import * as path from 'path'; import { AppSyncCLIInputs } from '../service-walkthrough-types/appsync-user-input-types'; @@ -10,7 +17,7 @@ export class AppsyncApiInputState { #service: string; //AWS service for the resource #buildFilePath: string; - constructor(resourceName: string) { + constructor(private readonly context: $TSContext, resourceName: string) { this.#category = AmplifyCategories.API; this.#service = AmplifySupportedService.APPSYNC; this.#resourceName = resourceName; @@ -21,7 +28,7 @@ export class AppsyncApiInputState { } public async isCLIInputsValid(cliInputs: AppSyncCLIInputs = this.getCLIInputPayload()): Promise { - const schemaValidator = new CLIInputSchemaValidator('appsync', this.#category, 'AppSyncCLIInputs'); + const schemaValidator = new CLIInputSchemaValidator(this.context, 'appsync', this.#category, 'AppSyncCLIInputs'); return schemaValidator.validateInput(JSON.stringify(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 index 321c1b0fb7..6a886d4c30 100644 --- 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 @@ -145,7 +145,12 @@ export class ApigwInputState { cliInputs = this.getCliInputPayload(); } - const schemaValidator = new CLIInputSchemaValidator(AmplifySupportedService.APIGW, AmplifyCategories.API, 'APIGatewayCLIInputs'); + const schemaValidator = new CLIInputSchemaValidator( + this.context, + AmplifySupportedService.APIGW, + AmplifyCategories.API, + 'APIGatewayCLIInputs', + ); schemaValidator.validateInput(JSONUtilities.stringify(cliInputs)); } 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 index 37d78a3d00..e62b084113 100644 --- 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 @@ -314,20 +314,13 @@ class CfnApiArtifactHandler implements ApiArtifactHandler { }; } // deploy appsync inputs - const cliState = new AppsyncApiInputState(serviceConfig.apiName); + const cliState = new AppsyncApiInputState(this.context, serviceConfig.apiName); await cliState.saveCLIInputPayload(appsyncCLIInputs); return appsyncCLIInputs; }; - /** - * If the resource is migrated, updates cli-inputs.json with the specified updates - * If not migrated, this method is a noop (but still returns the schema path) - * @param updates The updates to apply - * @param apiName The api name - * @returns The gqlSchemaPath - */ - private updateAppsyncCLIInputs = async (updates: AppSyncServiceModification, apiName: string): Promise => { - const cliState = new AppsyncApiInputState(apiName); + 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; 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 index 576956442d..6f49e0cccb 100644 --- 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 @@ -4,7 +4,7 @@ import { AppsyncApiInputState } from '../api-input-manager/appsync-api-input-sta import { migrateResourceToSupportOverride } from './migrate-api-override-resource'; export const checkAppsyncApiResourceMigration = async (context: $TSContext, apiName: string, isUpdate: boolean): Promise => { - const cliState = new AppsyncApiInputState(apiName); + 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; 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 index 7fb7eb88b2..93e289854f 100644 --- 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 @@ -1,3 +1,4 @@ +import { $TSContext } from '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'; @@ -6,8 +7,8 @@ import { appSyncAuthTypeToAuthConfig } from './auth-config-to-app-sync-auth-type * @param resourceName * @returns authConfig */ -export const getAuthConfig = async (resourceName: string) => { - const cliState = new AppsyncApiInputState(resourceName); +export const getAuthConfig = async (context: $TSContext, resourceName: string) => { + const cliState = new AppsyncApiInputState(context, resourceName); if (cliState.cliInputFileExists()) { const appsyncInputs = cliState.getCLIInputPayload().serviceConfiguration; return { 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 index 089952ffbc..a8b442dcce 100644 --- 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 @@ -1,3 +1,4 @@ +import { $TSContext } from 'amplify-cli-core'; import { AppsyncApiInputState } from '../api-input-manager/appsync-api-input-state'; import { conflictResolutionToResolverConfig } from './resolver-config-to-conflict-resolution-bi-di-mapper'; @@ -6,8 +7,8 @@ import { conflictResolutionToResolverConfig } from './resolver-config-to-conflic * @param resourceName * @returns resolverConfig */ -export const getResolverConfig = async (resourceName: string) => { - const cliState = new AppsyncApiInputState(resourceName); +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); From 413d1b46407cc62b2c58d1a30c6c3c6be287b6d4 Mon Sep 17 00:00:00 2001 From: Al Harris <91494052+alharris-at@users.noreply.github.com> Date: Tue, 31 May 2022 15:16:10 -0700 Subject: [PATCH 585/587] chore: bump api category package versions (#10502) --- packages/amplify-category-api/package.json | 50 +++++++++++----------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 7cab523f0d..3d707ca9e8 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -21,19 +21,19 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-auth-transformer": "^0.9.1", - "@aws-amplify/graphql-default-value-transformer": "^0.5.23", - "@aws-amplify/graphql-function-transformer": "^0.7.17", - "@aws-amplify/graphql-http-transformer": "^0.8.17", - "@aws-amplify/graphql-index-transformer": "^0.11.8", - "@aws-amplify/graphql-maps-to-transformer": "^1.1.15", - "@aws-amplify/graphql-model-transformer": "^0.14.1", - "@aws-amplify/graphql-predictions-transformer": "^0.6.17", - "@aws-amplify/graphql-relational-transformer": "^0.9.1", - "@aws-amplify/graphql-searchable-transformer": "^0.14.1", - "@aws-amplify/graphql-transformer-core": "^0.17.1", - "@aws-amplify/graphql-transformer-interfaces": "^1.14.1", - "@aws-amplify/graphql-transformer-migrator": "^1.2.37", + "@aws-amplify/graphql-auth-transformer": "^0.9.2", + "@aws-amplify/graphql-default-value-transformer": "^0.5.24", + "@aws-amplify/graphql-function-transformer": "^0.7.18", + "@aws-amplify/graphql-http-transformer": "^0.8.18", + "@aws-amplify/graphql-index-transformer": "^0.11.9", + "@aws-amplify/graphql-maps-to-transformer": "^1.1.16", + "@aws-amplify/graphql-model-transformer": "^0.14.2", + "@aws-amplify/graphql-predictions-transformer": "^0.6.18", + "@aws-amplify/graphql-relational-transformer": "^0.9.2", + "@aws-amplify/graphql-searchable-transformer": "^0.14.2", + "@aws-amplify/graphql-transformer-core": "^0.17.2", + "@aws-amplify/graphql-transformer-interfaces": "^1.14.2", + "@aws-amplify/graphql-transformer-migrator": "^1.2.38", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -91,18 +91,18 @@ "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-auth-transformer": "^7.2.33", - "graphql-connection-transformer": "^5.2.33", - "graphql-dynamodb-transformer": "^7.2.33", - "graphql-elasticsearch-transformer": "^5.2.33", - "graphql-function-transformer": "^3.3.24", - "graphql-http-transformer": "^5.2.33", - "graphql-key-transformer": "^3.2.33", - "graphql-predictions-transformer": "^3.2.33", - "graphql-relational-schema-transformer": "^2.21.6", - "graphql-transformer-common": "^4.23.0", - "graphql-transformer-core": "^7.5.1", - "graphql-versioned-transformer": "^5.2.33", + "graphql-auth-transformer": "^7.2.34", + "graphql-connection-transformer": "^5.2.34", + "graphql-dynamodb-transformer": "^7.2.34", + "graphql-elasticsearch-transformer": "^5.2.34", + "graphql-function-transformer": "^3.3.25", + "graphql-http-transformer": "^5.2.34", + "graphql-key-transformer": "^3.2.34", + "graphql-predictions-transformer": "^3.2.34", + "graphql-relational-schema-transformer": "^2.21.7", + "graphql-transformer-common": "^4.23.1", + "graphql-transformer-core": "^7.5.2", + "graphql-versioned-transformer": "^5.2.34", "import-from": "^3.0.0", "import-global": "^0.1.0", "inquirer": "^7.3.3", From 7acb3a91fea7fadb404a9fa26d412c4aa4a9263d Mon Sep 17 00:00:00 2001 From: aws-amplify-bot Date: Fri, 3 Jun 2022 17:50:14 +0000 Subject: [PATCH 586/587] chore(release): Publish [ci skip] - amplify-app@4.2.34 - amplify-appsync-simulator@2.4.0 - amplify-category-analytics@4.0.7 - @aws-amplify/amplify-category-api@2.2.0 - @aws-amplify/amplify-category-auth@2.10.0 - @aws-amplify/amplify-category-custom@2.3.33 - amplify-category-function@4.0.7 - amplify-category-geo@2.7.0 - amplify-category-hosting@3.2.32 - amplify-category-interactions@4.0.7 - amplify-category-predictions@4.0.7 - @aws-amplify/amplify-category-storage@3.4.0 - amplify-category-xr@3.2.32 - amplify-cli-core@2.9.0 - @aws-amplify/cli-extensibility-helper@2.3.29 - amplify-cli-logger@1.2.0 - @aws-amplify/cli@8.4.0 - @aws-amplify/cli-internal@8.4.0 - amplify-console-hosting@2.2.32 - amplify-console-integration-tests@2.2.41 - amplify-container-hosting@2.4.37 - amplify-dotnet-function-template-provider@2.2.36 - amplify-dynamodb-simulator@2.3.2 - amplify-e2e-core@3.3.0 - amplify-e2e-tests@3.11.0 - amplify-frontend-ios@3.4.6 - amplify-frontend-javascript@3.5.0 - amplify-go-function-runtime-provider@2.2.32 - amplify-graphql-migration-tests@2.2.42 - amplify-headless-interface@1.15.0 - amplify-java-function-runtime-provider@2.2.32 - amplify-migration-tests@4.6.0 - amplify-nodejs-function-runtime-provider@2.2.32 - amplify-nodejs-function-template-provider@2.4.2 - amplify-prompts@2.2.0 - amplify-provider-awscloudformation@6.3.0 - amplify-python-function-runtime-provider@2.3.0 - amplify-util-headless-input@1.9.5 - amplify-util-import@2.2.32 - amplify-util-mock@4.4.4 - @aws-amplify/amplify-util-uibuilder@1.2.27 --- packages/amplify-category-api/CHANGELOG.md | 11 +++++++++++ packages/amplify-category-api/package.json | 12 ++++++------ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/packages/amplify-category-api/CHANGELOG.md b/packages/amplify-category-api/CHANGELOG.md index 8f4578245e..cf4cebe478 100644 --- a/packages/amplify-category-api/CHANGELOG.md +++ b/packages/amplify-category-api/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +# [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 diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3d707ca9e8..3745580b44 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -1,6 +1,6 @@ { "name": "@aws-amplify/amplify-category-api", - "version": "2.1.2", + "version": "2.2.0", "description": "amplify-cli api plugin", "repository": { "type": "git", @@ -80,11 +80,11 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.8.1", - "amplify-headless-interface": "1.14.3", - "amplify-prompts": "2.1.0", - "amplify-provider-awscloudformation": "6.2.1", - "amplify-util-headless-input": "1.9.4", + "amplify-cli-core": "2.9.0", + "amplify-headless-interface": "1.15.0", + "amplify-prompts": "2.2.0", + "amplify-provider-awscloudformation": "6.3.0", + "amplify-util-headless-input": "1.9.5", "chalk": "^4.1.1", "cloudform": "^4.2.0", "cloudform-types": "^4.2.0", From 506bc457e7a09a13102205232d4ed6585a844838 Mon Sep 17 00:00:00 2001 From: Alexander Harris Date: Fri, 3 Jun 2022 11:50:25 -0700 Subject: [PATCH 587/587] chore: update package.json for caret versions, and tsconfig for references --- packages/amplify-category-api/package.json | 62 ++--- packages/amplify-category-api/tsconfig.json | 14 -- yarn.lock | 243 +++++++++++++++++++- 3 files changed, 265 insertions(+), 54 deletions(-) diff --git a/packages/amplify-category-api/package.json b/packages/amplify-category-api/package.json index 3745580b44..369a964053 100644 --- a/packages/amplify-category-api/package.json +++ b/packages/amplify-category-api/package.json @@ -4,7 +4,7 @@ "description": "amplify-cli api plugin", "repository": { "type": "git", - "url": "https://github.com/aws-amplify/amplify-cli.git", + "url": "https://github.com/aws-amplify/amplify-category-api.git", "directory": "packages/amplify-category-api" }, "author": "Amazon Web Services", @@ -21,19 +21,19 @@ "access": "public" }, "dependencies": { - "@aws-amplify/graphql-auth-transformer": "^0.9.2", - "@aws-amplify/graphql-default-value-transformer": "^0.5.24", - "@aws-amplify/graphql-function-transformer": "^0.7.18", - "@aws-amplify/graphql-http-transformer": "^0.8.18", - "@aws-amplify/graphql-index-transformer": "^0.11.9", - "@aws-amplify/graphql-maps-to-transformer": "^1.1.16", - "@aws-amplify/graphql-model-transformer": "^0.14.2", - "@aws-amplify/graphql-predictions-transformer": "^0.6.18", - "@aws-amplify/graphql-relational-transformer": "^0.9.2", - "@aws-amplify/graphql-searchable-transformer": "^0.14.2", - "@aws-amplify/graphql-transformer-core": "^0.17.2", - "@aws-amplify/graphql-transformer-interfaces": "^1.14.2", - "@aws-amplify/graphql-transformer-migrator": "^1.2.38", + "@aws-amplify/graphql-auth-transformer": "0.9.2", + "@aws-amplify/graphql-default-value-transformer": "0.5.24", + "@aws-amplify/graphql-function-transformer": "0.7.18", + "@aws-amplify/graphql-http-transformer": "0.8.18", + "@aws-amplify/graphql-index-transformer": "0.11.9", + "@aws-amplify/graphql-maps-to-transformer": "1.1.16", + "@aws-amplify/graphql-model-transformer": "0.14.2", + "@aws-amplify/graphql-predictions-transformer": "0.6.18", + "@aws-amplify/graphql-relational-transformer": "0.9.2", + "@aws-amplify/graphql-searchable-transformer": "0.14.2", + "@aws-amplify/graphql-transformer-core": "0.17.2", + "@aws-amplify/graphql-transformer-interfaces": "1.14.2", + "@aws-amplify/graphql-transformer-migrator": "1.2.38", "@aws-cdk/assets": "~1.124.0", "@aws-cdk/aws-apigateway": "~1.124.0", "@aws-cdk/aws-apigatewayv2": "~1.124.0", @@ -80,29 +80,29 @@ "@aws-cdk/region-info": "~1.124.0", "@graphql-tools/merge": "^6.0.18", "@octokit/rest": "^18.0.9", - "amplify-cli-core": "2.9.0", - "amplify-headless-interface": "1.15.0", - "amplify-prompts": "2.2.0", - "amplify-provider-awscloudformation": "6.3.0", - "amplify-util-headless-input": "1.9.5", + "amplify-cli-core": "^2.9.0", + "amplify-headless-interface": "^1.15.0", + "amplify-prompts": "^2.2.0", + "amplify-provider-awscloudformation": "^6.3.0", + "amplify-util-headless-input": "^1.9.5", "chalk": "^4.1.1", "cloudform": "^4.2.0", "cloudform-types": "^4.2.0", "constructs": "^3.3.125", "fs-extra": "^8.1.0", "graphql": "^14.5.8", - "graphql-auth-transformer": "^7.2.34", - "graphql-connection-transformer": "^5.2.34", - "graphql-dynamodb-transformer": "^7.2.34", - "graphql-elasticsearch-transformer": "^5.2.34", - "graphql-function-transformer": "^3.3.25", - "graphql-http-transformer": "^5.2.34", - "graphql-key-transformer": "^3.2.34", - "graphql-predictions-transformer": "^3.2.34", - "graphql-relational-schema-transformer": "^2.21.7", - "graphql-transformer-common": "^4.23.1", - "graphql-transformer-core": "^7.5.2", - "graphql-versioned-transformer": "^5.2.34", + "graphql-auth-transformer": "7.2.34", + "graphql-connection-transformer": "5.2.34", + "graphql-dynamodb-transformer": "7.2.34", + "graphql-elasticsearch-transformer": "5.2.34", + "graphql-function-transformer": "3.3.25", + "graphql-http-transformer": "5.2.34", + "graphql-key-transformer": "3.2.34", + "graphql-predictions-transformer": "3.2.34", + "graphql-relational-schema-transformer": "2.21.7", + "graphql-transformer-common": "4.23.1", + "graphql-transformer-core": "7.5.2", + "graphql-versioned-transformer": "5.2.34", "import-from": "^3.0.0", "import-global": "^0.1.0", "inquirer": "^7.3.3", diff --git a/packages/amplify-category-api/tsconfig.json b/packages/amplify-category-api/tsconfig.json index 5b558858ae..4689ad577b 100644 --- a/packages/amplify-category-api/tsconfig.json +++ b/packages/amplify-category-api/tsconfig.json @@ -16,19 +16,5 @@ "resources/awscloudformation/overrides-resource", "scripts", "src/__tests__" - ], - "references": [ - { - "path": "../amplify-cli-core" - }, - { - "path": "../amplify-headless-interface" - }, - { - "path": "../amplify-prompts" - }, - { - "path": "../amplify-util-headless-input" - } ] } diff --git a/yarn.lock b/yarn.lock index 52ab3b306e..ae92a1f30a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -42,6 +42,20 @@ ora "^4.0.3" uuid "^8.3.2" +"@aws-amplify/amplify-category-custom@2.3.33": + version "2.3.33" + resolved "https://registry.npmjs.org/@aws-amplify/amplify-category-custom/-/amplify-category-custom-2.3.33.tgz#ab86f9016d5fed1dc5e83232c95b8007ad7048c4" + integrity sha512-NjkKnrbulIcV72Bg0VpRshKoU9i0x96+LLNtipj+62IyjkqfVLNMb0VLxo8nDM/27INc84RsxhP2ALpc8SAqEw== + dependencies: + amplify-cli-core "2.9.0" + amplify-prompts "2.2.0" + execa "^5.1.1" + fs-extra "^8.1.0" + glob "^7.2.0" + inquirer "^7.3.3" + ora "^4.0.3" + uuid "^8.3.2" + "@aws-amplify/analytics@5.2.9": version "5.2.9" resolved "https://registry.npmjs.org/@aws-amplify/analytics/-/analytics-5.2.9.tgz#2fdd2b6ffb147a15dc4eff7f87d29266c6bdd283" @@ -140,6 +154,24 @@ amplify-cli-core "2.8.0" amplify-prompts "2.1.0" +"@aws-amplify/cli-extensibility-helper@2.3.29": + version "2.3.29" + resolved "https://registry.npmjs.org/@aws-amplify/cli-extensibility-helper/-/cli-extensibility-helper-2.3.29.tgz#c057c1147a0871efe2cc3295529f2297e6e76754" + integrity sha512-DTFTA1WkfToE6bA0ZZjfX3zBIwK0Z9guR1m+wutUiDHZcd6JBZUOPmEdLPzcJ8ruhyJbRYla6GEbstJO9XSTEQ== + dependencies: + "@aws-amplify/amplify-category-custom" "2.3.33" + "@aws-cdk/aws-apigateway" "~1.124.0" + "@aws-cdk/aws-appsync" "~1.124.0" + "@aws-cdk/aws-cognito" "~1.124.0" + "@aws-cdk/aws-dynamodb" "~1.124.0" + "@aws-cdk/aws-elasticsearch" "~1.124.0" + "@aws-cdk/aws-iam" "~1.124.0" + "@aws-cdk/aws-lambda" "~1.124.0" + "@aws-cdk/aws-s3" "~1.124.0" + "@aws-cdk/core" "~1.124.0" + amplify-cli-core "2.9.0" + amplify-prompts "2.2.0" + "@aws-amplify/core@4.5.6": version "4.5.6" resolved "https://registry.npmjs.org/@aws-amplify/core/-/core-4.5.6.tgz#92dc2801fe8f26f58b680232a903856f2ac9870d" @@ -298,6 +330,21 @@ "@aws-cdk/cx-api" "1.124.0" constructs "^3.3.69" +"@aws-cdk/assertions@~1.124.0": + version "1.124.0" + resolved "https://registry.npmjs.org/@aws-cdk/assertions/-/assertions-1.124.0.tgz#4d61226f341cf4f8ba66238cf46fa9150cc87afb" + integrity sha512-jvJf701HizOu3gZHFeC0YQHED2P9aRzKuBk76kA07pAVxxLN7AWTbPrMBtC0ToCVnhazZ1sftxjnLOkxLyyloA== + dependencies: + "@aws-cdk/cloud-assembly-schema" "1.124.0" + "@aws-cdk/core" "1.124.0" + "@aws-cdk/cx-api" "1.124.0" + colors "^1.4.0" + constructs "^3.3.69" + diff "^5.0.0" + fast-deep-equal "^3.1.3" + string-width "^4.2.2" + table "^6.7.1" + "@aws-cdk/assets@1.124.0", "@aws-cdk/assets@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/assets/-/assets-1.124.0.tgz#eaeacef8f2c03b93e3b742b6fe767b69e3cad4b3" @@ -366,7 +413,7 @@ "@aws-cdk/core" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-autoscaling-common@1.124.0": +"@aws-cdk/aws-autoscaling-common@1.124.0", "@aws-cdk/aws-autoscaling-common@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-autoscaling-common/-/aws-autoscaling-common-1.124.0.tgz#c8e6e1b3d87336fb63b585a7f5d1f84e563ac285" integrity sha512-Ef+YT0GSXtkc0jTwXmNqjbUtjHXgIg5FSt4lkfWRe2DzG/AeCEZDY0s+yUJMn6tXk1ubmqgIZO/i0VhTq8nW/g== @@ -375,7 +422,7 @@ "@aws-cdk/core" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-autoscaling-hooktargets@1.124.0": +"@aws-cdk/aws-autoscaling-hooktargets@1.124.0", "@aws-cdk/aws-autoscaling-hooktargets@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-autoscaling-hooktargets/-/aws-autoscaling-hooktargets-1.124.0.tgz#b3441a97898a8846055929074943bdac599f4305" integrity sha512-g0q+Jv124/krjMqT8U5gAKGHJwZkg5/yiswfWIy4aqEOieSwOwii4YuFUUIyghe779ua1yXFyEWnSfYAymXWgA== @@ -444,7 +491,7 @@ "@aws-cdk/cx-api" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-cloudfront@1.124.0": +"@aws-cdk/aws-cloudfront@1.124.0", "@aws-cdk/aws-cloudfront@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-cloudfront/-/aws-cloudfront-1.124.0.tgz#81dd569112799ca5720ecb5efe502bddf06cd503" integrity sha512-vd0vSEfKVWRtUMOWi5micPuC3qhLC7z7Dre/+X7N/YNqA+U+NX/g5k7jd00UdRnBiSxE34WRezHKsADUw8Tz6w== @@ -882,7 +929,7 @@ "@aws-cdk/cx-api" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-route53-targets@1.124.0": +"@aws-cdk/aws-route53-targets@1.124.0", "@aws-cdk/aws-route53-targets@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-route53-targets/-/aws-route53-targets-1.124.0.tgz#fa1ddcce2af9c552574ab96d1af946ca717b9021" integrity sha512-6+hN0zYlDmdXUZHmn5zVFD/sfH788212nLfRUo3V4Lg/XsV4vS3OV8b8wsctZCehuF1lagSIIF7rQJlGoYSBnA== @@ -939,7 +986,7 @@ "@aws-cdk/cx-api" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-sam@1.124.0": +"@aws-cdk/aws-sam@1.124.0", "@aws-cdk/aws-sam@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-sam/-/aws-sam-1.124.0.tgz#cc20765fb556f1691ca64963a146c1fb106da66b" integrity sha512-5yQsH3FNp+Mc4FdNwtrG1uRGqzXFSZEcds0FeVs338wDYLPDMnBe4kZzmOO4hY7d7siKP3E5tn+v8cSGvTUiSA== @@ -1029,7 +1076,7 @@ "@aws-cdk/core" "1.124.0" constructs "^3.3.69" -"@aws-cdk/aws-ssm@1.124.0": +"@aws-cdk/aws-ssm@1.124.0", "@aws-cdk/aws-ssm@~1.124.0": version "1.124.0" resolved "https://registry.npmjs.org/@aws-cdk/aws-ssm/-/aws-ssm-1.124.0.tgz#54c6f6959ea0327b38a865bec76445aa23bbda51" integrity sha512-41mopAh9ZTg3SL04P0WOO1d3sCDYJL3A/fPWCxDuzizSojdI2EWqvKf/5Lu1NY1jYZG+2ls7xqgG4b8x9BDILw== @@ -4785,7 +4832,16 @@ "@graphql-tools/utils" "8.6.12" tslib "~2.4.0" -"@graphql-tools/schema@8.3.13", "@graphql-tools/schema@^8.3.1": +"@graphql-tools/merge@^6.0.18": + version "6.2.17" + resolved "https://registry.npmjs.org/@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/schema@8.3.13", "@graphql-tools/schema@^8.0.2", "@graphql-tools/schema@^8.3.1": version "8.3.13" resolved "https://registry.npmjs.org/@graphql-tools/schema/-/schema-8.3.13.tgz#099460459d7821dd8deb34952900fe300085ba0b" integrity sha512-e+bx1VHj1i5v4HmhCYCar0lqdoLmkRi/CfV07rTqHR6CRDbIb/S/qDCajHLt7FCovQ5ozlI5sRVbBhzfq5H0PQ== @@ -4816,6 +4872,13 @@ value-or-promise "^1.0.11" ws "^8.3.0" +"@graphql-tools/utils@8.0.2": + version "8.0.2" + resolved "https://registry.npmjs.org/@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.6.12", "@graphql-tools/utils@^8.5.1": version "8.6.12" resolved "https://registry.npmjs.org/@graphql-tools/utils/-/utils-8.6.12.tgz#0a550dc0331fd9b097fe7223d65cbbee720556e4" @@ -6738,6 +6801,35 @@ amplify-cli-core@2.8.0, amplify-cli-core@^2.6.0: typescript-json-schema "~0.52.0" which "^2.0.2" +amplify-cli-core@2.9.0, amplify-cli-core@^2.9.0: + version "2.9.0" + resolved "https://registry.npmjs.org/amplify-cli-core/-/amplify-cli-core-2.9.0.tgz#6995bb17e45d0b8f3b7471300e78f950e9494f82" + integrity sha512-9ScW1ahYT0hDIRMOu+rZ454ooo11dNFhH5UYQc6qTUbt12l3AsHDBTylwRSBH7hECd1xQiXqsdmMKhIUlZDtvw== + dependencies: + "@aws-amplify/graphql-transformer-core" "^0.17.2" + "@aws-amplify/graphql-transformer-interfaces" "^1.14.2" + ajv "^6.12.6" + amplify-cli-logger "1.2.0" + amplify-prompts "2.2.0" + chalk "^4.1.1" + ci-info "^2.0.0" + cloudform-types "^4.2.0" + dotenv "^8.2.0" + execa "^5.1.1" + fs-extra "^8.1.0" + globby "^11.0.3" + graphql-transformer-core "^7.5.2" + hjson "^3.2.1" + js-yaml "^4.0.0" + lodash "^4.17.21" + node-fetch "^2.6.7" + open "^8.4.0" + ora "^4.0.3" + proxy-agent "^5.0.0" + semver "^7.3.5" + typescript-json-schema "~0.52.0" + which "^2.0.2" + amplify-cli-logger@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/amplify-cli-logger/-/amplify-cli-logger-1.1.3.tgz#f08c9b0f389442b6ace7226e6d15c35727bc1dae" @@ -6746,6 +6838,14 @@ amplify-cli-logger@1.1.3: winston "^3.3.3" winston-daily-rotate-file "^4.5.0" +amplify-cli-logger@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/amplify-cli-logger/-/amplify-cli-logger-1.2.0.tgz#635d22732ac4a6e958d33038ca0b331cfc90e95c" + integrity sha512-MidSMWUyWwPtqtkLvmlLe46P36AqY4TRFggoXuTk//wGtN1wfGCuwTI47aoyBhFoHYiXHRIyo/AXd/fLX8iJAQ== + dependencies: + winston "^3.3.3" + winston-daily-rotate-file "^4.5.0" + amplify-cli-shared-interfaces@1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/amplify-cli-shared-interfaces/-/amplify-cli-shared-interfaces-1.1.0.tgz#105c8645c50bb469272badf2501505793c3974de" @@ -6777,6 +6877,11 @@ amplify-function-plugin-interface@1.9.5, amplify-function-plugin-interface@^1.9. resolved "https://registry.npmjs.org/amplify-function-plugin-interface/-/amplify-function-plugin-interface-1.9.5.tgz#caa95891f7976d29a3d43c51f7c6a372178b9a81" integrity sha512-x49gI8U1863JC7akkUTQ5WrAhOPD8/PRx9LCwRshl1RJNMH4AaF40Gx+ueDVV/SLAsFc2GM0xoigxsvX+Cu4qQ== +amplify-headless-interface@1.15.0, amplify-headless-interface@^1.15.0: + version "1.15.0" + resolved "https://registry.npmjs.org/amplify-headless-interface/-/amplify-headless-interface-1.15.0.tgz#a72d001d11d230ab48844b6e57b5f5c9f1cb030e" + integrity sha512-6U22nhKLu67i6/zbBXZO+1TYmLXym+/e9fnwqeOhnctMCybU56RdWvj4/MhQIywn4DyOTHvYBkRT5o4f1hFSPg== + amplify-headless-interface@^1.14.2: version "1.14.3" resolved "https://registry.npmjs.org/amplify-headless-interface/-/amplify-headless-interface-1.14.3.tgz#0bf0fb115db3f4756eb8c348fc24112ef398d7e7" @@ -6804,6 +6909,15 @@ amplify-prompts@2.1.0, amplify-prompts@^2.0.0, amplify-prompts@^2.0.1: chalk "^4.1.1" enquirer "^2.3.6" +amplify-prompts@2.2.0, amplify-prompts@^2.2.0: + version "2.2.0" + resolved "https://registry.npmjs.org/amplify-prompts/-/amplify-prompts-2.2.0.tgz#288a52ee990eb19a51eed28c20bd43703980ec78" + integrity sha512-JZv9GTVz3//s8QlhNBZRuYcUCoxdAEJU6q2tivl2hN0XK3pckeofaXqv6Fi8e9c8NfUyA/u+JVRR7vE4QIMtyw== + dependencies: + amplify-cli-shared-interfaces "1.1.0" + chalk "^4.1.1" + enquirer "^2.3.6" + amplify-provider-awscloudformation@^6.1.3: version "6.2.0" resolved "https://registry.npmjs.org/amplify-provider-awscloudformation/-/amplify-provider-awscloudformation-6.2.0.tgz#5f327e3ab798aa03c69d69e1bf114a3bf665d9e9" @@ -6892,6 +7006,94 @@ amplify-provider-awscloudformation@^6.1.3: vm2 "^3.9.8" xstate "^4.14.0" +amplify-provider-awscloudformation@^6.3.0: + version "6.3.0" + resolved "https://registry.npmjs.org/amplify-provider-awscloudformation/-/amplify-provider-awscloudformation-6.3.0.tgz#409aac4d4fdbc37bf1470bed53c955d4f8046e01" + integrity sha512-WsPWS0hJE159Lvm9U7cDgB/aJz+DbzPgoxkdkKh8muadRP48/FnazJrIZj/pRioQPvexS8R+MjJrTty/Rd7PNQ== + dependencies: + "@aws-amplify/amplify-category-custom" "2.3.33" + "@aws-amplify/cli-extensibility-helper" "2.3.29" + "@aws-amplify/graphql-transformer-core" "^0.17.2" + "@aws-amplify/graphql-transformer-interfaces" "^1.14.2" + "@aws-cdk/assert" "~1.124.0" + "@aws-cdk/assets" "~1.124.0" + "@aws-cdk/aws-apigatewayv2" "~1.124.0" + "@aws-cdk/aws-autoscaling" "~1.124.0" + "@aws-cdk/aws-batch" "~1.124.0" + "@aws-cdk/aws-cloudformation" "~1.124.0" + "@aws-cdk/aws-cloudwatch" "~1.124.0" + "@aws-cdk/aws-codebuild" "~1.124.0" + "@aws-cdk/aws-codecommit" "~1.124.0" + "@aws-cdk/aws-codedeploy" "~1.124.0" + "@aws-cdk/aws-codepipeline" "~1.124.0" + "@aws-cdk/aws-codepipeline-actions" "~1.124.0" + "@aws-cdk/aws-ec2" "~1.124.0" + "@aws-cdk/aws-ecr" "~1.124.0" + "@aws-cdk/aws-ecr-assets" "~1.124.0" + "@aws-cdk/aws-ecs" "~1.124.0" + "@aws-cdk/aws-elasticloadbalancing" "~1.124.0" + "@aws-cdk/aws-elasticloadbalancingv2" "~1.124.0" + "@aws-cdk/aws-events" "~1.124.0" + "@aws-cdk/aws-events-targets" "~1.124.0" + "@aws-cdk/aws-iam" "~1.124.0" + "@aws-cdk/aws-kinesis" "~1.124.0" + "@aws-cdk/aws-kinesisfirehose" "~1.124.0" + "@aws-cdk/aws-kms" "~1.124.0" + "@aws-cdk/aws-lambda" "~1.124.0" + "@aws-cdk/aws-logs" "~1.124.0" + "@aws-cdk/aws-route53" "~1.124.0" + "@aws-cdk/aws-s3" "~1.124.0" + "@aws-cdk/aws-s3-assets" "~1.124.0" + "@aws-cdk/aws-secretsmanager" "~1.124.0" + "@aws-cdk/aws-servicecatalog" "~1.124.0" + "@aws-cdk/aws-servicediscovery" "~1.124.0" + "@aws-cdk/aws-sns" "~1.124.0" + "@aws-cdk/aws-sns-subscriptions" "~1.124.0" + "@aws-cdk/aws-sqs" "~1.124.0" + "@aws-cdk/aws-stepfunctions" "~1.124.0" + "@aws-cdk/core" "~1.124.0" + "@aws-cdk/custom-resources" "~1.124.0" + "@aws-cdk/region-info" "~1.124.0" + "@octokit/rest" "^18.0.9" + ajv "^6.12.6" + amplify-cli-core "2.9.0" + amplify-cli-logger "1.2.0" + amplify-codegen "^3.0.0" + amplify-prompts "2.2.0" + amplify-util-import "2.2.32" + archiver "^5.3.0" + aws-sdk "^2.1113.0" + bottleneck "2.19.5" + chalk "^4.1.1" + cloudform "^4.2.0" + cloudform-types "^4.2.0" + columnify "^1.5.4" + constructs "^3.3.125" + cors "^2.8.5" + deep-diff "^1.0.2" + extract-zip "^2.0.1" + folder-hash "^4.0.2" + fs-extra "^8.1.0" + glob "^7.2.0" + graphql "^14.5.8" + graphql-transformer-core "^7.5.2" + ignore "^5.2.0" + ini "^1.3.5" + inquirer "^7.3.3" + is-wsl "^2.2.0" + jose "^4.3.7" + lodash "^4.17.21" + lodash.throttle "^4.1.1" + moment "^2.24.0" + netmask "^2.0.2" + node-fetch "^2.6.7" + ora "^4.0.3" + promise-sequential "^1.1.1" + proxy-agent "^5.0.0" + rimraf "^3.0.0" + vm2 "^3.9.8" + xstate "^4.14.0" + amplify-storage-simulator@^1.6.7: version "1.6.7" resolved "https://registry.npmjs.org/amplify-storage-simulator/-/amplify-storage-simulator-1.6.7.tgz#4967fd4f9903910ab096ebd09d56e53de6398238" @@ -6910,6 +7112,14 @@ amplify-storage-simulator@^1.6.7: xml "^1.0.1" xml-js "^1.6.11" +amplify-util-headless-input@^1.9.5: + version "1.9.5" + resolved "https://registry.npmjs.org/amplify-util-headless-input/-/amplify-util-headless-input-1.9.5.tgz#30cec34338140b1938b7bddf2e7d07095941b58b" + integrity sha512-dAXewft+FW80TQ4Iwq/f45jDyNn6rFivGOo6cQd7xIQgKmBPwyz24+/5KL363AwX+gkXFFPizacTgMAqigwjcw== + dependencies: + ajv "^6.12.6" + amplify-headless-interface "1.15.0" + amplify-util-import@2.2.30: version "2.2.30" resolved "https://registry.npmjs.org/amplify-util-import/-/amplify-util-import-2.2.30.tgz#fc20b0dcf1f8d52086c8cf2c3d79d6a7e5e4b76c" @@ -6918,6 +7128,14 @@ amplify-util-import@2.2.30: amplify-cli-core "2.8.0" aws-sdk "^2.1113.0" +amplify-util-import@2.2.32: + version "2.2.32" + resolved "https://registry.npmjs.org/amplify-util-import/-/amplify-util-import-2.2.32.tgz#ae984043f8fd946fca968ee5372f6c8c8427c71b" + integrity sha512-BJ8+Ffc+SBBBBnYcuoJcf6y2UdIzUgKtIA0Rm2oybLeBZ4wQ2kl3vpU/5KDDJDbCv+RTH2it7KTzs8JmCJKAeg== + dependencies: + amplify-cli-core "2.9.0" + aws-sdk "^2.1113.0" + amplify-velocity-template@1.4.8: version "1.4.8" resolved "https://registry.npmjs.org/amplify-velocity-template/-/amplify-velocity-template-1.4.8.tgz#78b67a58485bae952bf4b031228ba179f54b5fe4" @@ -10901,7 +11119,7 @@ glob@^7.0.0, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, gl once "^1.3.0" path-is-absolute "^1.0.0" -global-dirs@^0.1.1: +global-dirs@^0.1.0, global-dirs@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445" integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU= @@ -11397,7 +11615,7 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" -import-from@3.0.0: +import-from@3.0.0, import-from@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/import-from/-/import-from-3.0.0.tgz#055cfec38cd5a27d8057ca51376d7d3bf0891966" integrity sha512-CiuXOFFSzkU5x/CR0+z7T91Iht4CXgfCxVOFRhh2Zyhg5wOpWvvDLQUsWl+gcN+QscYBjez8hDCt85O7RLDttQ== @@ -11409,6 +11627,13 @@ import-from@4.0.0: resolved "https://registry.npmjs.org/import-from/-/import-from-4.0.0.tgz#2710b8d66817d232e16f4166e319248d3d5492e2" integrity sha512-P9J71vT5nLlDeV8FHs5nNxaLbrpfAV5cF5srvbZfpwpcJoM/xZR3hiv+q+SAnuSmuGbXMWud063iIMx/V/EWZQ== +import-global@^0.1.0: + version "0.1.0" + resolved "https://registry.npmjs.org/import-global/-/import-global-0.1.0.tgz#97b38fd444114eec16824a935f8da575b57aa1ce" + integrity sha512-8+hPJLML+m1ym9NSeZXTXFkY5+ml0fYFAzO5yhZiaFQvk9kO0NkE7vd7e7kCVjkTmAxsDPbrWwLQACMwGTDgIg== + dependencies: + global-dirs "^0.1.0" + import-local@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4"