diff --git a/package-lock.json b/package-lock.json index 9c64c526db..024b8afe60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,6 +62,10 @@ "resolved": "packages/backend-engine", "link": true }, + "node_modules/@aws-amplify/backend-function": { + "resolved": "packages/backend-function", + "link": true + }, "node_modules/@aws-amplify/backend-output-schemas": { "resolved": "packages/backend-output-schemas", "link": true @@ -74,6 +78,10 @@ "resolved": "packages/cli", "link": true }, + "node_modules/@aws-amplify/function-construct": { + "resolved": "packages/function-construct", + "link": true + }, "node_modules/@aws-amplify/graphql-construct-alpha": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/@aws-amplify/graphql-construct-alpha/-/graphql-construct-alpha-0.3.1.tgz", @@ -3380,8 +3388,9 @@ } }, "node_modules/@types/node": { - "version": "18.16.18", - "license": "MIT" + "version": "18.16.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.19.tgz", + "integrity": "sha512-IXl7o+R9iti9eBW4Wg2hx1xQDig183jj7YLn8F7udNceyfkbn1ZxmzZXuak20gR40D7pIkIY1kYGx5VIGbaHKA==" }, "node_modules/@types/normalize-package-data": { "version": "2.4.1", @@ -5323,7 +5332,6 @@ }, "node_modules/cross-spawn": { "version": "7.0.3", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6364,8 +6372,8 @@ }, "node_modules/execa": { "version": "7.1.1", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/execa/-/execa-7.1.1.tgz", + "integrity": "sha512-wH0eMf/UXckdUYnO21+HDztteVv05rq2GXksxT4fCGeHkBhw1DROXh40wcjMcRqDOWE7iPJ4n3M7e2+YFP+76Q==", "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.1", @@ -6806,8 +6814,9 @@ }, "node_modules/fs-extra": { "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -6887,7 +6896,6 @@ }, "node_modules/get-stream": { "version": "6.0.1", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -7283,7 +7291,6 @@ }, "node_modules/human-signals": { "version": "4.3.1", - "dev": true, "license": "Apache-2.0", "engines": { "node": ">=14.18.0" @@ -7650,7 +7657,6 @@ }, "node_modules/is-stream": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" @@ -7742,7 +7748,6 @@ }, "node_modules/isexe": { "version": "2.0.0", - "dev": true, "license": "ISC" }, "node_modules/isstream": { @@ -8554,7 +8559,6 @@ }, "node_modules/merge-stream": { "version": "2.0.0", - "dev": true, "license": "MIT" }, "node_modules/merge2": { @@ -8616,7 +8620,6 @@ }, "node_modules/mimic-fn": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8845,7 +8848,6 @@ }, "node_modules/npm-run-path": { "version": "5.1.0", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^4.0.0" @@ -8859,7 +8861,6 @@ }, "node_modules/npm-run-path/node_modules/path-key": { "version": "4.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -8975,7 +8976,6 @@ }, "node_modules/onetime": { "version": "6.0.0", - "dev": true, "license": "MIT", "dependencies": { "mimic-fn": "^4.0.0" @@ -9135,7 +9135,6 @@ }, "node_modules/path-key": { "version": "3.1.1", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9954,7 +9953,6 @@ }, "node_modules/shebang-command": { "version": "2.0.0", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -9965,7 +9963,6 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9997,7 +9994,6 @@ }, "node_modules/signal-exit": { "version": "3.0.7", - "dev": true, "license": "ISC" }, "node_modules/slash": { @@ -10529,7 +10525,6 @@ }, "node_modules/strip-final-newline": { "version": "3.0.0", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -11383,7 +11378,6 @@ }, "node_modules/which": { "version": "2.0.2", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -11801,6 +11795,22 @@ "constructs": "^10.0.0" } }, + "packages/backend-function": { + "name": "@aws-amplify/backend-function", + "version": "0.1.0", + "dependencies": { + "@aws-amplify/function-construct": "^0.1.0", + "execa": "^7.1.1" + }, + "devDependencies": { + "@aws-amplify/backend-engine": "^0.1.0", + "@aws-amplify/plugin-types": "^0.1.0" + }, + "peerDependencies": { + "aws-cdk-lib": "~2.68.0", + "constructs": "^10.0.0" + } + }, "packages/backend-output-schemas": { "name": "@aws-amplify/backend-output-schemas", "version": "0.1.0", @@ -11950,6 +11960,14 @@ "node": ">=12" } }, + "packages/function-construct": { + "name": "@aws-amplify/function-construct", + "version": "0.1.0", + "peerDependencies": { + "aws-cdk-lib": "~2.68.0", + "constructs": "^10.0.0" + } + }, "packages/integration-tests": { "name": "@aws-amplify/integration-tests", "version": "0.1.0", @@ -11957,6 +11975,7 @@ "@aws-amplify/backend": "0.1.0", "@aws-amplify/backend-auth": "0.1.0", "@aws-amplify/backend-storage": "0.1.0", + "fs-extra": "^11.1.1", "glob": "^10.2.7" } }, diff --git a/packages/backend-function/.npmignore b/packages/backend-function/.npmignore new file mode 100644 index 0000000000..dbde1fb5db --- /dev/null +++ b/packages/backend-function/.npmignore @@ -0,0 +1,14 @@ +# Be very careful editing this file. It is crafted to work around [this issue](https://github.com/npm/npm/issues/4479) + +# First ignore everything +**/* + +# Then add back in transpiled js and ts declaration files +!lib/**/*.js +!lib/**/*.d.ts + +# Then ignore test js and ts declaration files +*.test.js +*.test.d.ts + +# This leaves us with including only js and ts declaration files of functional code diff --git a/packages/backend-function/API.md b/packages/backend-function/API.md new file mode 100644 index 0000000000..dfc2ad1424 --- /dev/null +++ b/packages/backend-function/API.md @@ -0,0 +1,40 @@ +## API Report File for "@aws-amplify/backend-function" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { AmplifyFunction } from '@aws-amplify/function-construct'; +import { AmplifyFunctionProps } from '@aws-amplify/function-construct'; +import { ConstructFactory } from '@aws-amplify/plugin-types'; +import { ConstructFactoryGetInstanceProps } from '@aws-amplify/plugin-types'; + +// @public +export class AmplifyFunctionFactory implements ConstructFactory { + static build(props: AmplifyFunctionFactoryBuildProps): Promise; + static fromDir(props: AmplifyFunctionFactoryFromDirProps): AmplifyFunctionFactory; + getInstance({ constructContainer, }: ConstructFactoryGetInstanceProps): AmplifyFunction; +} + +// @public (undocumented) +export type AmplifyFunctionFactoryBaseProps = { + name: string; +}; + +// @public (undocumented) +export type AmplifyFunctionFactoryBuildProps = AmplifyFunctionFactoryBaseProps & Omit & { + buildCommand: string; + outDir: string; +}; + +// @public (undocumented) +export type AmplifyFunctionFactoryFromDirProps = AmplifyFunctionFactoryBaseProps & Omit & { + codePath: string; +}; + +// @public +export const Func: typeof AmplifyFunctionFactory; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/backend-function/api-extractor.json b/packages/backend-function/api-extractor.json new file mode 100644 index 0000000000..0f56de03f6 --- /dev/null +++ b/packages/backend-function/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.base.json" +} diff --git a/packages/backend-function/package.json b/packages/backend-function/package.json new file mode 100644 index 0000000000..dab6191b5d --- /dev/null +++ b/packages/backend-function/package.json @@ -0,0 +1,28 @@ +{ + "name": "@aws-amplify/backend-function", + "version": "0.1.0", + "type": "module", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "import": "./lib/index.js", + "require": "./lib/index.js" + } + }, + "types": "lib/index.d.ts", + "scripts": { + "update:api": "api-extractor run --local" + }, + "dependencies": { + "@aws-amplify/function-construct": "^0.1.0", + "execa": "^7.1.1" + }, + "devDependencies": { + "@aws-amplify/backend-engine": "^0.1.0", + "@aws-amplify/plugin-types": "^0.1.0" + }, + "peerDependencies": { + "aws-cdk-lib": "~2.68.0", + "constructs": "^10.0.0" + } +} diff --git a/packages/backend-function/src/factory.test.ts b/packages/backend-function/src/factory.test.ts new file mode 100644 index 0000000000..9836243674 --- /dev/null +++ b/packages/backend-function/src/factory.test.ts @@ -0,0 +1,74 @@ +import { beforeEach, describe, it, mock } from 'node:test'; +import { Func } from './factory.js'; +import { App, Stack } from 'aws-cdk-lib'; +import { + NestedStackResolver, + SingletonConstructContainer, + StackMetadataBackendOutputStorageStrategy, +} from '@aws-amplify/backend-engine'; +import { + BackendOutputEntry, + BackendOutputStorageStrategy, + ConstructContainer, +} from '@aws-amplify/plugin-types'; +import assert from 'node:assert'; +import { fileURLToPath } from 'url'; + +describe('AmplifyFunctionFactory', () => { + let constructContainer: ConstructContainer; + let outputStorageStrategy: BackendOutputStorageStrategy; + + beforeEach(() => { + const app = new App(); + const stack = new Stack(app, 'testStack'); + + constructContainer = new SingletonConstructContainer( + new NestedStackResolver(stack) + ); + + outputStorageStrategy = new StackMetadataBackendOutputStorageStrategy( + stack + ); + }); + + it('creates singleton function instance', () => { + const functionFactory = Func.fromDir({ + name: 'testFunc', + codePath: '../test-assets/test-lambda', + }); + const instance1 = functionFactory.getInstance({ + constructContainer, + outputStorageStrategy, + }); + const instance2 = functionFactory.getInstance({ + constructContainer, + outputStorageStrategy, + }); + assert.strictEqual(instance1, instance2); + }); + + it('executes build command from directory where constructor is used', async () => { + const commandExecutorMock = mock.fn(); + + // Casting to never is necessary because commandExecutor is a private method. + // TS yells that it's not a property on Func even though it is there + mock.method(Func, 'commandExecutor' as never, commandExecutorMock); + + ( + await Func.build({ + name: 'testFunc', + outDir: '../test-assets/test-lambda', + buildCommand: 'test command', + }) + ).getInstance({ constructContainer, outputStorageStrategy }); + + assert.strictEqual(commandExecutorMock.mock.callCount(), 1); + assert.deepStrictEqual(commandExecutorMock.mock.calls[0].arguments, [ + 'test command', + { + cwd: fileURLToPath(new URL('../src', import.meta.url)), + stdio: 'inherit', + }, + ]); + }); +}); diff --git a/packages/backend-function/src/factory.ts b/packages/backend-function/src/factory.ts new file mode 100644 index 0000000000..2b1971261d --- /dev/null +++ b/packages/backend-function/src/factory.ts @@ -0,0 +1,135 @@ +import { + ConstructContainerEntryGenerator, + ConstructFactory, + ConstructFactoryGetInstanceProps, +} from '@aws-amplify/plugin-types'; +import { + AmplifyFunction, + AmplifyFunctionProps, +} from '@aws-amplify/function-construct'; +import { Construct } from 'constructs'; +import { execaCommand } from 'execa'; +import * as path from 'path'; +import { getCallerDirectory } from './get_caller_directory.js'; + +export type AmplifyFunctionFactoryBaseProps = { + /** + * A name for the function that is used to disambiguate it from other functions in the project + */ + name: string; +}; + +export type AmplifyFunctionFactoryBuildProps = AmplifyFunctionFactoryBaseProps & + Omit & { + /** + * The command to run that generates built function code. + * This command is run from the directory where this factory is called + */ + buildCommand: string; + /** + * The buildCommand is expected to place build artifacts at this location. + * This path can be relative or absolute. If relative, the absolute path is calculated based on the directory where this factory is called + */ + outDir: string; + }; + +export type AmplifyFunctionFactoryFromDirProps = + AmplifyFunctionFactoryBaseProps & + Omit & { + /** + * The location of the pre-built function code. + * Can be a directory or a .zip file. + * Can be a relative or absolute path. If relative, the absolute path is calculated based on the directory where this factory is called. + */ + codePath: string; + }; + +type AmplifyFunctionFactoryProps = AmplifyFunctionFactoryBaseProps & + AmplifyFunctionProps; + +/** + * Create Lambda functions in the context of an Amplify backend definition + */ +export class AmplifyFunctionFactory + implements ConstructFactory +{ + // execaCommand is assigned to a static prop so that it can be mocked in tests + private static commandExecutor = execaCommand; + + private generator: ConstructContainerEntryGenerator; + /** + * Create a new AmplifyFunctionFactory + */ + private constructor(private readonly props: AmplifyFunctionFactoryProps) {} + + /** + * Create a function from a directory that contains pre-built code + */ + static fromDir( + props: AmplifyFunctionFactoryFromDirProps + ): AmplifyFunctionFactory { + const absoluteCodePath = path.isAbsolute(props.codePath) + ? props.codePath + : path.resolve(getCallerDirectory(new Error().stack), props.codePath); + return new AmplifyFunctionFactory({ + name: props.name, + absoluteCodePath, + runtime: props.runtime, + handler: props.handler, + }); + } + + /** + * Create a function by executing a build command that places build artifacts at a specified location + * + * TODO: Investigate long-term function building strategy: https://github.com/aws-amplify/samsara-cli/issues/92 + */ + static async build( + props: AmplifyFunctionFactoryBuildProps + ): Promise { + const importPath = getCallerDirectory(new Error().stack); + + await AmplifyFunctionFactory.commandExecutor(props.buildCommand, { + cwd: importPath, + stdio: 'inherit', + }); + + const absoluteCodePath = path.isAbsolute(props.outDir) + ? props.outDir + : path.resolve(importPath, props.outDir); + + return new AmplifyFunctionFactory({ + name: props.name, + absoluteCodePath, + runtime: props.runtime, + handler: props.handler, + }); + } + + /** + * Creates an instance of AmplifyFunction within the provided Amplify context + */ + getInstance({ + constructContainer, + }: ConstructFactoryGetInstanceProps): AmplifyFunction { + if (!this.generator) { + this.generator = new AmplifyFunctionGenerator(this.props); + } + return constructContainer.getOrCompute(this.generator) as AmplifyFunction; + } +} + +class AmplifyFunctionGenerator implements ConstructContainerEntryGenerator { + readonly resourceGroupName = 'function'; + + constructor(private readonly props: AmplifyFunctionFactoryProps) {} + + generateContainerEntry(scope: Construct) { + return new AmplifyFunction(scope, this.props.name, this.props); + } +} + +/** + * Alias for AmplifyFunctionFactory + */ +export const Func = AmplifyFunctionFactory; diff --git a/packages/backend-function/src/get_caller_directory.test.ts b/packages/backend-function/src/get_caller_directory.test.ts new file mode 100644 index 0000000000..a0234d9e0a --- /dev/null +++ b/packages/backend-function/src/get_caller_directory.test.ts @@ -0,0 +1,34 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert'; +import { getCallerDirectory } from './get_caller_directory.js'; + +describe('getCallerDirectory', () => { + it('throws if stack trace is undefined', () => { + assert.throws(() => getCallerDirectory(undefined)); + }); + + it('throws if stack trace has less than two frames', () => { + const tooShortStack = `Error + at AmplifyAuthFactory (/Users/alias/sandboxes/install-test/node_modules/@aws-amplify/backend-auth/src/factory.ts:28:24)`; + assert.throws(() => getCallerDirectory(tooShortStack)); + }); + + it('throws if regex match not found', () => { + const malformedStacktrace = `Error + at AmplifyAuthFactory some garbage + at more garbage + at Object. (/Users/alias/sandboxes/install-test/backend/auth.ts:5:2)`; + assert.throws(() => getCallerDirectory(malformedStacktrace)); + }); + + it('returns path of second stack frame', () => { + const validStackTrace = `Error + at AmplifyAuthFactory (/Users/alias/sandboxes/install-test/node_modules/@aws-amplify/backend-auth/src/factory.ts:28:24) + at (/Users/alias/sandboxes/install-test/backend/otherName.ts:3:21) + at Object. (/Users/alias/sandboxes/install-test/backend/auth.ts:5:2)`; + assert.strictEqual( + getCallerDirectory(validStackTrace), + '/Users/alias/sandboxes/install-test/backend' + ); + }); +}); diff --git a/packages/backend-function/src/get_caller_directory.ts b/packages/backend-function/src/get_caller_directory.ts new file mode 100644 index 0000000000..a405919f2f --- /dev/null +++ b/packages/backend-function/src/get_caller_directory.ts @@ -0,0 +1,32 @@ +import path from 'path'; + +/** + * Extracts the path of the caller of the code that generated the input stack trace. + * In other words, extracts the path from the _second_ entry in the stack trace + * (the first entry being the location where the stack trace was created and the second entry being the location that called the code that generated the stack trace) + */ +export const getCallerDirectory = (stackTrace?: string): string => { + const unresolvedImportLocationError = new Error( + 'Could not determine import path to construct absolute code path from relative path. Consider using an absolute path instead.' + ); + if (!stackTrace) { + throw unresolvedImportLocationError; + } + const stacktraceLines = + stackTrace + .split('\n') + .map((line) => line.trim()) + .filter((line) => line.startsWith('at')) || []; + if (stacktraceLines.length < 2) { + throw unresolvedImportLocationError; + } + const stackTraceImportLine = stacktraceLines[1]; // the first entry is the file where the error was initialized (our code). The second entry is where the customer called our code which is what we are interested in + // the line is something like `at (/some/path/to/file.ts:3:21)` + // this regex pulls out the file path, ie `/some/path/to/file.ts` + const extractFilePathFromStackTraceLine = /\((?[^:]*):.*\)/; + const match = stackTraceImportLine.match(extractFilePathFromStackTraceLine); + if (!match?.groups?.filepath) { + throw unresolvedImportLocationError; + } + return path.dirname(match.groups.filepath); +}; diff --git a/packages/backend-function/src/index.ts b/packages/backend-function/src/index.ts new file mode 100644 index 0000000000..cb95b1ef8d --- /dev/null +++ b/packages/backend-function/src/index.ts @@ -0,0 +1 @@ +export * from './factory.js'; diff --git a/packages/backend-function/test-assets/test-lambda/mock.txt b/packages/backend-function/test-assets/test-lambda/mock.txt new file mode 100644 index 0000000000..29cc220aee --- /dev/null +++ b/packages/backend-function/test-assets/test-lambda/mock.txt @@ -0,0 +1,2 @@ +To test out creating a lambda we need a directory that simulates the lambda content. +Obviously this is not a real lambda, but it allows CDK synth to proceed. diff --git a/packages/backend-function/tsconfig.json b/packages/backend-function/tsconfig.json new file mode 100644 index 0000000000..224f8c4883 --- /dev/null +++ b/packages/backend-function/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "rootDir": "src", "outDir": "lib" }, + "references": [ + { "path": "../function-construct" }, + { "path": "../backend-engine" }, + { "path": "../plugin-types" } + ] +} diff --git a/packages/backend-function/typedoc.json b/packages/backend-function/typedoc.json new file mode 100644 index 0000000000..35fed2c958 --- /dev/null +++ b/packages/backend-function/typedoc.json @@ -0,0 +1,3 @@ +{ + "entryPoints": ["src/index.ts"] +} diff --git a/packages/function-construct/.npmignore b/packages/function-construct/.npmignore new file mode 100644 index 0000000000..dbde1fb5db --- /dev/null +++ b/packages/function-construct/.npmignore @@ -0,0 +1,14 @@ +# Be very careful editing this file. It is crafted to work around [this issue](https://github.com/npm/npm/issues/4479) + +# First ignore everything +**/* + +# Then add back in transpiled js and ts declaration files +!lib/**/*.js +!lib/**/*.d.ts + +# Then ignore test js and ts declaration files +*.test.js +*.test.d.ts + +# This leaves us with including only js and ts declaration files of functional code diff --git a/packages/function-construct/API.md b/packages/function-construct/API.md new file mode 100644 index 0000000000..09771cae1f --- /dev/null +++ b/packages/function-construct/API.md @@ -0,0 +1,27 @@ +## API Report File for "@aws-amplify/function-construct" + +> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/). + +```ts + +import { Construct } from 'constructs'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; +import { Runtime } from 'aws-cdk-lib/aws-lambda'; + +// @public +export class AmplifyFunction extends Construct { + constructor(scope: Construct, id: string, props: AmplifyFunctionProps); + // (undocumented) + readonly lambda: IFunction; +} + +// @public (undocumented) +export type AmplifyFunctionProps = { + absoluteCodePath: string; + runtime?: Runtime; + handler?: string; +}; + +// (No @packageDocumentation comment for this package) + +``` diff --git a/packages/function-construct/api-extractor.json b/packages/function-construct/api-extractor.json new file mode 100644 index 0000000000..0f56de03f6 --- /dev/null +++ b/packages/function-construct/api-extractor.json @@ -0,0 +1,3 @@ +{ + "extends": "../../api-extractor.base.json" +} diff --git a/packages/function-construct/package.json b/packages/function-construct/package.json new file mode 100644 index 0000000000..a94a78b0e7 --- /dev/null +++ b/packages/function-construct/package.json @@ -0,0 +1,20 @@ +{ + "name": "@aws-amplify/function-construct", + "version": "0.1.0", + "type": "module", + "exports": { + ".": { + "types": "./lib/index.d.ts", + "import": "./lib/index.js", + "require": "./lib/index.js" + } + }, + "types": "lib/index.d.ts", + "scripts": { + "update:api": "api-extractor run --local" + }, + "peerDependencies": { + "aws-cdk-lib": "~2.68.0", + "constructs": "^10.0.0" + } +} diff --git a/packages/function-construct/src/construct.test.ts b/packages/function-construct/src/construct.test.ts new file mode 100644 index 0000000000..c2720c4fb8 --- /dev/null +++ b/packages/function-construct/src/construct.test.ts @@ -0,0 +1,59 @@ +import { beforeEach, describe, it } from 'node:test'; +import { App, Stack } from 'aws-cdk-lib'; +import { Template } from 'aws-cdk-lib/assertions'; +import { AmplifyFunction } from './construct.js'; +import { Runtime } from 'aws-cdk-lib/aws-lambda'; +import { fileURLToPath } from 'url'; + +const testCodePath = fileURLToPath( + new URL('../test-assets/test-lambda', import.meta.url) +); + +describe('AmplifyFunction', () => { + let stack: Stack; + beforeEach(() => { + const app = new App(); + stack = new Stack(app); + }); + it('creates lambda with specified runtime', () => { + new AmplifyFunction(stack, 'test', { + absoluteCodePath: testCodePath, + runtime: Runtime.JAVA_8, + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::Function', { + Runtime: 'java8', + }); + }); + + it('creates lambda with default runtime', () => { + new AmplifyFunction(stack, 'test', { + absoluteCodePath: testCodePath, + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::Function', { + Runtime: 'nodejs18.x', + }); + }); + + it('creates lambda with specified handler', () => { + new AmplifyFunction(stack, 'test', { + absoluteCodePath: testCodePath, + handler: 'test.main', + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::Function', { + Handler: 'test.main', + }); + }); + + it('creates lambda with default handler', () => { + new AmplifyFunction(stack, 'test', { + absoluteCodePath: testCodePath, + }); + const template = Template.fromStack(stack); + template.hasResourceProperties('AWS::Lambda::Function', { + Handler: 'index.handler', + }); + }); +}); diff --git a/packages/function-construct/src/construct.ts b/packages/function-construct/src/construct.ts new file mode 100644 index 0000000000..6d8bb4da29 --- /dev/null +++ b/packages/function-construct/src/construct.ts @@ -0,0 +1,27 @@ +import { Construct } from 'constructs'; +import { Code, Function, IFunction, Runtime } from 'aws-cdk-lib/aws-lambda'; + +export type AmplifyFunctionProps = { + absoluteCodePath: string; + runtime?: Runtime; + handler?: string; +}; + +/** + * Hello world construct implementation + */ +export class AmplifyFunction extends Construct { + readonly lambda: IFunction; + /** + * Create a new AmplifyConstruct + */ + constructor(scope: Construct, id: string, props: AmplifyFunctionProps) { + super(scope, id); + + this.lambda = new Function(this, `${id}LambdaFunction`, { + code: Code.fromAsset(props.absoluteCodePath), + runtime: props.runtime || Runtime.NODEJS_18_X, + handler: props.handler || 'index.handler', + }); + } +} diff --git a/packages/function-construct/src/index.ts b/packages/function-construct/src/index.ts new file mode 100644 index 0000000000..9d1f8f790c --- /dev/null +++ b/packages/function-construct/src/index.ts @@ -0,0 +1 @@ +export * from './construct.js'; diff --git a/packages/function-construct/test-assets/test-lambda/mock.txt b/packages/function-construct/test-assets/test-lambda/mock.txt new file mode 100644 index 0000000000..29cc220aee --- /dev/null +++ b/packages/function-construct/test-assets/test-lambda/mock.txt @@ -0,0 +1,2 @@ +To test out creating a lambda we need a directory that simulates the lambda content. +Obviously this is not a real lambda, but it allows CDK synth to proceed. diff --git a/packages/function-construct/tsconfig.json b/packages/function-construct/tsconfig.json new file mode 100644 index 0000000000..2aab102e9b --- /dev/null +++ b/packages/function-construct/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { "rootDir": "src", "outDir": "lib" }, + "references": [] +} diff --git a/packages/function-construct/typedoc.json b/packages/function-construct/typedoc.json new file mode 100644 index 0000000000..35fed2c958 --- /dev/null +++ b/packages/function-construct/typedoc.json @@ -0,0 +1,3 @@ +{ + "entryPoints": ["src/index.ts"] +} diff --git a/packages/integration-tests/package.json b/packages/integration-tests/package.json index b0d8c3ae70..925401499f 100644 --- a/packages/integration-tests/package.json +++ b/packages/integration-tests/package.json @@ -5,8 +5,9 @@ "type": "module", "devDependencies": { "@aws-amplify/backend": "0.1.0", - "@aws-amplify/backend-storage": "0.1.0", "@aws-amplify/backend-auth": "0.1.0", + "@aws-amplify/backend-storage": "0.1.0", + "fs-extra": "^11.1.1", "glob": "^10.2.7" }, "scripts": { diff --git a/packages/integration-tests/src/cdk_out_dir_validator.ts b/packages/integration-tests/src/cdk_out_dir_validator.ts index 21e4bd6bdd..aa7a3afbf0 100644 --- a/packages/integration-tests/src/cdk_out_dir_validator.ts +++ b/packages/integration-tests/src/cdk_out_dir_validator.ts @@ -1,7 +1,8 @@ import { glob } from 'glob'; import path from 'path'; import assert from 'node:assert'; -import fs from 'fs'; +import * as fse from 'fs-extra/esm'; +import * as fs from 'fs'; const UPDATE_SNAPSHOTS = process.env.UPDATE_INTEGRATION_SNAPSHOTS === 'true'; @@ -22,8 +23,8 @@ export const validateCdkOutDir = async ( // We only care about validating the CFN templates const ignoreFiles = ['tree.json', 'cdk.out', 'manifest.json']; - const actualFiles = await glob(path.join(actualDir, '*')); - const expectedFiles = await glob(path.join(expectedDir, '*')); + const actualPaths = await glob(path.join(actualDir, '*')); + const expectedPaths = await glob(path.join(expectedDir, '*')); /** * Filter out ignoreFiles and sort @@ -31,29 +32,30 @@ export const validateCdkOutDir = async ( const normalize = (paths: string[]) => paths .filter((p) => !ignoreFiles.some((ignoreFile) => p.endsWith(ignoreFile))) + .filter((p) => !path.basename(p).startsWith('asset.')) .sort(); - const normalizedActualFiles = normalize(actualFiles); - const normalizedExpectedFiles = normalize(expectedFiles); + const normalizedActualPaths = normalize(actualPaths); + const normalizedExpectedPaths = normalize(expectedPaths); if (UPDATE_SNAPSHOTS) { - normalizedActualFiles.forEach((actualFile) => { - const destination = path.resolve(expectedDir, path.basename(actualFile)); - fs.copyFileSync(actualFile, destination); + normalizedActualPaths.forEach((actualPath) => { + const destination = path.resolve(expectedDir, path.basename(actualPath)); + fse.copySync(actualPath, destination); }); return; } assert.deepStrictEqual( - normalizedActualFiles.map((fileName) => path.basename(fileName)), - normalizedExpectedFiles.map((fileName) => path.basename(fileName)) + normalizedActualPaths.map((fileName) => path.basename(fileName)), + normalizedExpectedPaths.map((fileName) => path.basename(fileName)) ); // check that JSON files parse to the same object - for (let i = 0; i < normalizedActualFiles.length; i++) { - const actualFile = normalizedActualFiles[i]; - const expectedFile = normalizedExpectedFiles[i]; - if (path.extname(normalizedActualFiles[i]) !== '.json') { + for (let i = 0; i < normalizedActualPaths.length; i++) { + const actualFile = normalizedActualPaths[i]; + const expectedFile = normalizedExpectedPaths[i]; + if (path.extname(normalizedActualPaths[i]) !== '.json') { assert.fail(`Unknown file type ${actualFile}`); } const actualObj = JSON.parse(fs.readFileSync(actualFile, 'utf-8')); diff --git a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.assets.json b/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.assets.json deleted file mode 100644 index 061655db44..0000000000 --- a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.assets.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "version": "30.1.0", - "files": { - "14f453302310e8bb66b03b6fd318b25c5cbaa317a5b93b9f7686110ebabf1ae8": { - "source": { - "path": "testProjecttestEnvironmentauth2C6E1D50.nested.template.json", - "packaging": "file" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "14f453302310e8bb66b03b6fd318b25c5cbaa317a5b93b9f7686110ebabf1ae8.json", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - }, - "44578e2a49b2f94a9fa3341cc0d90ee4b476112b88fbe686a0727e551e684591": { - "source": { - "path": "testProjecttestEnvironmentstorageD5B9103B.nested.template.json", - "packaging": "file" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "44578e2a49b2f94a9fa3341cc0d90ee4b476112b88fbe686a0727e551e684591.json", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - }, - "f6f7bb99ddf1e2d4b5f23813eccfa02b4a0199a11aa70d76e2bd30b07d2758be": { - "source": { - "path": "testProject-testEnvironment.template.json", - "packaging": "file" - }, - "destinations": { - "current_account-current_region": { - "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", - "objectKey": "f6f7bb99ddf1e2d4b5f23813eccfa02b4a0199a11aa70d76e2bd30b07d2758be.json", - "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" - } - } - } - }, - "dockerImages": {} -} diff --git a/packages/integration-tests/test-projects/auth-and-storage/auth.ts b/packages/integration-tests/test-projects/basic-auth-data-storage-function/auth.ts similarity index 100% rename from packages/integration-tests/test-projects/auth-and-storage/auth.ts rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/auth.ts diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/data.ts b/packages/integration-tests/test-projects/basic-auth-data-storage-function/data.ts new file mode 100644 index 0000000000..420e09740f --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/data.ts @@ -0,0 +1,14 @@ +import { Data } from '@aws-amplify/backend-data'; + +const schema = ` + input AMPLIFY {globalAuthRule: AuthRule = { allow: public }} # FOR TESTING ONLY! + + type Todo @model { + id: ID! + name: String! + description: String + otherField: String + } +`; + +export const data = new Data({ schema }); diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.assets.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.assets.json new file mode 100644 index 0000000000..3454ec9653 --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.assets.json @@ -0,0 +1,279 @@ +{ + "version": "30.1.0", + "files": { + "efe12e580179d925ecc56ede6195533f23db3a8e887169b63ecb5cc644193f2b": { + "source": { + "path": "asset.efe12e580179d925ecc56ede6195533f23db3a8e887169b63ecb5cc644193f2b", + "packaging": "zip" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "efe12e580179d925ecc56ede6195533f23db3a8e887169b63ecb5cc644193f2b.zip", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6449656554023e0ec45392816430f2a15cc7bd3f61ece8e5597df8547f64e766": { + "source": { + "path": "asset.6449656554023e0ec45392816430f2a15cc7bd3f61ece8e5597df8547f64e766.graphql", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6449656554023e0ec45392816430f2a15cc7bd3f61ece8e5597df8547f64e766.graphql", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "3a607c80c325a3edcae10503ccceaaad8e73d3447432eceba2dab95a3a1c4665": { + "source": { + "path": "asset.3a607c80c325a3edcae10503ccceaaad8e73d3447432eceba2dab95a3a1c4665.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "3a607c80c325a3edcae10503ccceaaad8e73d3447432eceba2dab95a3a1c4665.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "08f4d557693d96c1a4efba0f9dc91330e4b19772fd5477c156468843e3d9cb5e": { + "source": { + "path": "asset.08f4d557693d96c1a4efba0f9dc91330e4b19772fd5477c156468843e3d9cb5e.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "08f4d557693d96c1a4efba0f9dc91330e4b19772fd5477c156468843e3d9cb5e.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "4c6a2d29f01c6091bd1d9afe16e5849d456c96f17c3b215938c8067399532719": { + "source": { + "path": "asset.4c6a2d29f01c6091bd1d9afe16e5849d456c96f17c3b215938c8067399532719.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4c6a2d29f01c6091bd1d9afe16e5849d456c96f17c3b215938c8067399532719.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "3665466abf40cc747bff935f1cf2f49edd920e2cd12d45d502d3857488b3ff3e": { + "source": { + "path": "asset.3665466abf40cc747bff935f1cf2f49edd920e2cd12d45d502d3857488b3ff3e.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "3665466abf40cc747bff935f1cf2f49edd920e2cd12d45d502d3857488b3ff3e.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "cc01911d0269d4080ea57505dc445dfc315ef7ad85d3d9d4ea1357858bff451d": { + "source": { + "path": "asset.cc01911d0269d4080ea57505dc445dfc315ef7ad85d3d9d4ea1357858bff451d.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "cc01911d0269d4080ea57505dc445dfc315ef7ad85d3d9d4ea1357858bff451d.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "01dd50f40481ed4d3b0fb1a5f22dbe631b252847144e59c565ad3874813dc77c": { + "source": { + "path": "asset.01dd50f40481ed4d3b0fb1a5f22dbe631b252847144e59c565ad3874813dc77c.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "01dd50f40481ed4d3b0fb1a5f22dbe631b252847144e59c565ad3874813dc77c.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "2bf64327ca5682da4be84d0d16440204e25abc3a221195b41f2d21dfa432e5ab": { + "source": { + "path": "asset.2bf64327ca5682da4be84d0d16440204e25abc3a221195b41f2d21dfa432e5ab.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "2bf64327ca5682da4be84d0d16440204e25abc3a221195b41f2d21dfa432e5ab.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249": { + "source": { + "path": "asset.f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "06db846fd14e6fc371f22b12b5545ba8e2dbfeda85d8c8d586c71c282166657b": { + "source": { + "path": "asset.06db846fd14e6fc371f22b12b5545ba8e2dbfeda85d8c8d586c71c282166657b.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "06db846fd14e6fc371f22b12b5545ba8e2dbfeda85d8c8d586c71c282166657b.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "474bf0776ec2164a13191d1a0a9e057154931e4918fea5086f49850d02a5371b": { + "source": { + "path": "asset.474bf0776ec2164a13191d1a0a9e057154931e4918fea5086f49850d02a5371b.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "474bf0776ec2164a13191d1a0a9e057154931e4918fea5086f49850d02a5371b.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "4f7907d1209a2c9953a0c053df402c634e359546d70c7cc5c2e8e21ea734880f": { + "source": { + "path": "asset.4f7907d1209a2c9953a0c053df402c634e359546d70c7cc5c2e8e21ea734880f.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4f7907d1209a2c9953a0c053df402c634e359546d70c7cc5c2e8e21ea734880f.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "fe3c43ada4b9d681a5e2312663ef7a73386424d73b73e51f8e2e9d4b50f7c502": { + "source": { + "path": "asset.fe3c43ada4b9d681a5e2312663ef7a73386424d73b73e51f8e2e9d4b50f7c502.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "fe3c43ada4b9d681a5e2312663ef7a73386424d73b73e51f8e2e9d4b50f7c502.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "e0cff47fb007f0bbf2a4e43ca256d6aa7ec109821769fd79fa7c5e83f0e7f9fc": { + "source": { + "path": "asset.e0cff47fb007f0bbf2a4e43ca256d6aa7ec109821769fd79fa7c5e83f0e7f9fc.vtl", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "e0cff47fb007f0bbf2a4e43ca256d6aa7ec109821769fd79fa7c5e83f0e7f9fc.vtl", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "f7235586d68223a946599e8a148cf0cc1a8142b9927c234df72b83cb1cde2aa1": { + "source": { + "path": "testProjecttestEnvironmentauth2C6E1D50.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "f7235586d68223a946599e8a148cf0cc1a8142b9927c234df72b83cb1cde2aa1.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "44578e2a49b2f94a9fa3341cc0d90ee4b476112b88fbe686a0727e551e684591": { + "source": { + "path": "testProjecttestEnvironmentstorageD5B9103B.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "44578e2a49b2f94a9fa3341cc0d90ee4b476112b88fbe686a0727e551e684591.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "6bd12547173aeacd987da819a8c8b0e6651f6e6094150a6327e95708bdf251bc": { + "source": { + "path": "testProjecttestEnvironmentfunction955F813A.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "6bd12547173aeacd987da819a8c8b0e6651f6e6094150a6327e95708bdf251bc.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "dfc7748dfea2ce35483bce2eb49f0df37e91bf605fb4551782698ce231456a27": { + "source": { + "path": "testProjecttestEnvironmentdataamplifyDataRootStackTodo7247B992.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "dfc7748dfea2ce35483bce2eb49f0df37e91bf605fb4551782698ce231456a27.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "fa4fbd49c3ea59a122e67ec5d2b251d89d37a8d021ec164c641aff0d89bb39b9": { + "source": { + "path": "testProjecttestEnvironmentdata4ACFC8FD.nested.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "fa4fbd49c3ea59a122e67ec5d2b251d89d37a8d021ec164c641aff0d89bb39b9.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + }, + "4c814e4cda1b2881e731c7bac1a372bd201dff009ba0239da16c314f45ddc304": { + "source": { + "path": "testProject-testEnvironment.template.json", + "packaging": "file" + }, + "destinations": { + "current_account-current_region": { + "bucketName": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}", + "objectKey": "4c814e4cda1b2881e731c7bac1a372bd201dff009ba0239da16c314f45ddc304.json", + "assumeRoleArn": "arn:${AWS::Partition}:iam::${AWS::AccountId}:role/cdk-hnb659fds-file-publishing-role-${AWS::AccountId}-${AWS::Region}" + } + } + } + }, + "dockerImages": {} +} diff --git a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.template.json similarity index 53% rename from packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.template.json rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.template.json index c92cdfe520..e7957ea13b 100644 --- a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProject-testEnvironment.template.json +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProject-testEnvironment.template.json @@ -8,6 +8,10 @@ "storageOutput": { "version": "1", "stackOutputs": ["storageRegion", "bucketName"] + }, + "dataOutput": { + "version": "1", + "stackOutputs": ["appSyncApiEndpoint"] } } }, @@ -39,7 +43,7 @@ { "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" }, - "/14f453302310e8bb66b03b6fd318b25c5cbaa317a5b93b9f7686110ebabf1ae8.json" + "/f7235586d68223a946599e8a148cf0cc1a8142b9927c234df72b83cb1cde2aa1.json" ] ] } @@ -73,6 +77,80 @@ }, "UpdateReplacePolicy": "Delete", "DeletionPolicy": "Delete" + }, + "function1351588B": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/6bd12547173aeacd987da819a8c8b0e6651f6e6094150a6327e95708bdf251bc.json" + ] + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "data7552DF31": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/fa4fbd49c3ea59a122e67ec5d2b251d89d37a8d021ec164c641aff0d89bb39b9.json" + ] + ] + }, + "Parameters": { + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthUserPoolFF81EE45Ref": { + "Fn::GetAtt": [ + "auth179371D7", + "Outputs.testProjecttestEnvironmentauthamplifyAuthUserPoolFF81EE45Ref" + ] + }, + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthauthenticatedUserRoleA18DA667Ref": { + "Fn::GetAtt": [ + "auth179371D7", + "Outputs.testProjecttestEnvironmentauthamplifyAuthauthenticatedUserRoleA18DA667Ref" + ] + }, + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthunauthenticatedUserRoleFAB97A20Ref": { + "Fn::GetAtt": [ + "auth179371D7", + "Outputs.testProjecttestEnvironmentauthamplifyAuthunauthenticatedUserRoleFAB97A20Ref" + ] + } + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" } }, "Outputs": { @@ -101,6 +179,14 @@ "Outputs.testProjecttestEnvironmentstorageamplifyStorageamplifyStorageBucket05AB04A9Ref" ] } + }, + "appSyncApiEndpoint": { + "Value": { + "Fn::GetAtt": [ + "data7552DF31", + "Outputs.testProjecttestEnvironmentdataamplifyDataRootStackGraphQLAPI682E00A4GraphQLUrl" + ] + } } }, "Parameters": { diff --git a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json similarity index 87% rename from packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json index a129684f38..370e174cdd 100644 --- a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentauth2C6E1D50.nested.template.json @@ -76,6 +76,16 @@ "Value": { "Ref": "amplifyAuthUserPool4BA7F805" } + }, + "testProjecttestEnvironmentauthamplifyAuthauthenticatedUserRoleA18DA667Ref": { + "Value": { + "Ref": "amplifyAuthauthenticatedUserRoleD8DA3689" + } + }, + "testProjecttestEnvironmentauthamplifyAuthunauthenticatedUserRoleFAB97A20Ref": { + "Value": { + "Ref": "amplifyAuthunauthenticatedUserRole2B524D9E" + } } } } diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdata4ACFC8FD.nested.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdata4ACFC8FD.nested.template.json new file mode 100644 index 0000000000..83e6c85024 --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdata4ACFC8FD.nested.template.json @@ -0,0 +1,200 @@ +{ + "Parameters": { + "DynamoDBModelTableReadIOPS": { + "Type": "Number", + "Default": 5, + "Description": "The number of read IOPS the table should support." + }, + "DynamoDBModelTableWriteIOPS": { + "Type": "Number", + "Default": 5, + "Description": "The number of write IOPS the table should support." + }, + "DynamoDBBillingMode": { + "Type": "String", + "Default": "PAY_PER_REQUEST", + "AllowedValues": ["PAY_PER_REQUEST", "PROVISIONED"], + "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes." + }, + "DynamoDBEnablePointInTimeRecovery": { + "Type": "String", + "Default": "false", + "AllowedValues": ["true", "false"], + "Description": "Whether to enable Point in Time Recovery on the table." + }, + "DynamoDBEnableServerSideEncryption": { + "Type": "String", + "Default": "true", + "AllowedValues": ["true", "false"], + "Description": "Enable server side encryption powered by KMS." + }, + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthUserPoolFF81EE45Ref": { + "Type": "String" + }, + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthauthenticatedUserRoleA18DA667Ref": { + "Type": "String" + }, + "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthunauthenticatedUserRoleFAB97A20Ref": { + "Type": "String" + } + }, + "Resources": { + "GraphQLAPI": { + "Type": "AWS::AppSync::GraphQLApi", + "Properties": { + "AuthenticationType": "AMAZON_COGNITO_USER_POOLS", + "Name": { + "Fn::Join": ["", ["amplifyData", "-", "NONE"]] + }, + "AdditionalAuthenticationProviders": [ + { + "AuthenticationType": "AWS_IAM" + } + ], + "UserPoolConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "DefaultAction": "ALLOW", + "UserPoolId": { + "Ref": "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthUserPoolFF81EE45Ref" + } + } + } + }, + "GraphQLAPITransformerSchema3CB2AE18": { + "Type": "AWS::AppSync::GraphQLSchema", + "Properties": { + "ApiId": { + "Fn::GetAtt": ["GraphQLAPI", "ApiId"] + }, + "DefinitionS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/6449656554023e0ec45392816430f2a15cc7bd3f61ece8e5597df8547f64e766.graphql" + ] + ] + } + } + }, + "GraphQLAPINONEDS95A13CF0": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Fn::GetAtt": ["GraphQLAPI", "ApiId"] + }, + "Name": "NONE_DS", + "Type": "NONE", + "Description": "None Data Source for Pipeline functions" + } + }, + "Todo": { + "Type": "AWS::CloudFormation::Stack", + "Properties": { + "TemplateURL": { + "Fn::Join": [ + "", + [ + "https://s3.", + { + "Ref": "AWS::Region" + }, + ".", + { + "Ref": "AWS::URLSuffix" + }, + "/", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/dfc7748dfea2ce35483bce2eb49f0df37e91bf605fb4551782698ce231456a27.json" + ] + ] + }, + "Parameters": { + "DynamoDBModelTableReadIOPS": { + "Ref": "DynamoDBModelTableReadIOPS" + }, + "DynamoDBModelTableWriteIOPS": { + "Ref": "DynamoDBModelTableWriteIOPS" + }, + "DynamoDBBillingMode": { + "Ref": "DynamoDBBillingMode" + }, + "DynamoDBEnablePointInTimeRecovery": { + "Ref": "DynamoDBEnablePointInTimeRecovery" + }, + "DynamoDBEnableServerSideEncryption": { + "Ref": "DynamoDBEnableServerSideEncryption" + }, + "referencetotransformerrootstackenv10C5A902Ref": "NONE", + "referencetotransformerrootstackGraphQLAPI20497F53ApiId": { + "Fn::GetAtt": ["GraphQLAPI", "ApiId"] + }, + "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name": { + "Fn::GetAtt": ["GraphQLAPINONEDS95A13CF0", "Name"] + }, + "referencetotransformerrootstackS3DeploymentBucket7592718ARef": "cdk-${Qualifier}-assets-${AWS::AccountId}-${AWS::Region}", + "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": "CdkBootstrap-${Qualifier}-FileAssetKeyArn", + "referencetotransformerrootstackauthRoleNameFB872D50Ref": { + "Ref": "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthauthenticatedUserRoleA18DA667Ref" + }, + "referencetotransformerrootstackunauthRoleName49F3C1FERef": { + "Ref": "referencetotestProjecttestEnvironmentauthNestedStackauthNestedStackResource9B0234C2OutputstestProjecttestEnvironmentauthamplifyAuthunauthenticatedUserRoleFAB97A20Ref" + } + } + }, + "DependsOn": ["GraphQLAPITransformerSchema3CB2AE18"] + } + }, + "Outputs": { + "GraphQLAPIIdOutput": { + "Description": "Your GraphQL API ID.", + "Value": { + "Fn::GetAtt": ["GraphQLAPI", "ApiId"] + }, + "Export": { + "Name": { + "Fn::Join": [ + ":", + [ + { + "Ref": "AWS::StackName" + }, + "GraphQLApiId" + ] + ] + } + } + }, + "GraphQLAPIEndpointOutput": { + "Description": "Your GraphQL API endpoint.", + "Value": { + "Fn::GetAtt": ["GraphQLAPI", "GraphQLUrl"] + }, + "Export": { + "Name": { + "Fn::Join": [ + ":", + [ + { + "Ref": "AWS::StackName" + }, + "GraphQLApiEndpoint" + ] + ] + } + } + }, + "testProjecttestEnvironmentdataamplifyDataRootStackGraphQLAPI682E00A4GraphQLUrl": { + "Value": { + "Fn::GetAtt": ["GraphQLAPI", "GraphQLUrl"] + } + } + } +} diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdataamplifyDataRootStackTodo7247B992.nested.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdataamplifyDataRootStackTodo7247B992.nested.template.json new file mode 100644 index 0000000000..aafa4f64cb --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentdataamplifyDataRootStackTodo7247B992.nested.template.json @@ -0,0 +1,1185 @@ +{ + "Parameters": { + "DynamoDBModelTableReadIOPS": { + "Type": "Number", + "Default": 5, + "Description": "The number of read IOPS the table should support." + }, + "DynamoDBModelTableWriteIOPS": { + "Type": "Number", + "Default": 5, + "Description": "The number of write IOPS the table should support." + }, + "DynamoDBBillingMode": { + "Type": "String", + "Default": "PAY_PER_REQUEST", + "AllowedValues": ["PAY_PER_REQUEST", "PROVISIONED"], + "Description": "Configure @model types to create DynamoDB tables with PAY_PER_REQUEST or PROVISIONED billing modes." + }, + "DynamoDBEnablePointInTimeRecovery": { + "Type": "String", + "Default": "false", + "AllowedValues": ["true", "false"], + "Description": "Whether to enable Point in Time Recovery on the table." + }, + "DynamoDBEnableServerSideEncryption": { + "Type": "String", + "Default": "true", + "AllowedValues": ["true", "false"], + "Description": "Enable server side encryption powered by KMS." + }, + "referencetotransformerrootstackenv10C5A902Ref": { + "Type": "String" + }, + "referencetotransformerrootstackGraphQLAPI20497F53ApiId": { + "Type": "String" + }, + "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name": { + "Type": "String" + }, + "referencetotransformerrootstackS3DeploymentBucket7592718ARef": { + "Type": "String" + }, + "referencetotransformerrootstackS3DeploymentRootKeyA71EA735Ref": { + "Type": "String" + }, + "referencetotransformerrootstackauthRoleNameFB872D50Ref": { + "Type": "String" + }, + "referencetotransformerrootstackunauthRoleName49F3C1FERef": { + "Type": "String" + } + }, + "Conditions": { + "HasEnvironmentParameter": { + "Fn::Not": [ + { + "Fn::Equals": [ + { + "Ref": "referencetotransformerrootstackenv10C5A902Ref" + }, + "NONE" + ] + } + ] + }, + "ShouldUseServerSideEncryption": { + "Fn::Equals": [ + { + "Ref": "DynamoDBEnableServerSideEncryption" + }, + "true" + ] + }, + "ShouldUsePayPerRequestBilling": { + "Fn::Equals": [ + { + "Ref": "DynamoDBBillingMode" + }, + "PAY_PER_REQUEST" + ] + }, + "ShouldUsePointInTimeRecovery": { + "Fn::Equals": [ + { + "Ref": "DynamoDBEnablePointInTimeRecovery" + }, + "true" + ] + } + }, + "Resources": { + "TodoTable": { + "Type": "AWS::DynamoDB::Table", + "Properties": { + "KeySchema": [ + { + "AttributeName": "id", + "KeyType": "HASH" + } + ], + "AttributeDefinitions": [ + { + "AttributeName": "id", + "AttributeType": "S" + } + ], + "BillingMode": { + "Fn::If": [ + "ShouldUsePayPerRequestBilling", + "PAY_PER_REQUEST", + { + "Ref": "AWS::NoValue" + } + ] + }, + "PointInTimeRecoverySpecification": { + "Fn::If": [ + "ShouldUsePointInTimeRecovery", + { + "PointInTimeRecoveryEnabled": true + }, + { + "Ref": "AWS::NoValue" + } + ] + }, + "ProvisionedThroughput": { + "Fn::If": [ + "ShouldUsePayPerRequestBilling", + { + "Ref": "AWS::NoValue" + }, + { + "ReadCapacityUnits": { + "Ref": "DynamoDBModelTableReadIOPS" + }, + "WriteCapacityUnits": { + "Ref": "DynamoDBModelTableWriteIOPS" + } + } + ] + }, + "SSESpecification": { + "SSEEnabled": { + "Fn::If": ["ShouldUseServerSideEncryption", true, false] + } + }, + "StreamSpecification": { + "StreamViewType": "NEW_AND_OLD_IMAGES" + }, + "TableName": { + "Fn::Join": [ + "", + [ + "Todo-", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "-", + { + "Ref": "referencetotransformerrootstackenv10C5A902Ref" + } + ] + ] + } + }, + "UpdateReplacePolicy": "Delete", + "DeletionPolicy": "Delete" + }, + "TodoIAMRole2DA8E66E": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "appsync.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "RoleName": { + "Fn::Join": [ + "", + [ + "TodoIAMRolecfd440-", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "-", + { + "Ref": "referencetotransformerrootstackenv10C5A902Ref" + } + ] + ] + } + } + }, + "TodoIAMRoleDefaultPolicy7BBBF45B": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:GetRecords", + "dynamodb:GetShardIterator", + "dynamodb:Query", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:ConditionCheckItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:UpdateItem", + "dynamodb:DeleteItem", + "dynamodb:DescribeTable" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::GetAtt": ["TodoTable", "Arn"] + }, + { + "Ref": "AWS::NoValue" + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "TodoIAMRoleDefaultPolicy7BBBF45B", + "Roles": [ + { + "Ref": "TodoIAMRole2DA8E66E" + } + ] + } + }, + "DynamoDBAccess71ABE5AE": { + "Type": "AWS::IAM::Policy", + "Properties": { + "PolicyDocument": { + "Statement": [ + { + "Action": [ + "dynamodb:BatchGetItem", + "dynamodb:BatchWriteItem", + "dynamodb:PutItem", + "dynamodb:DeleteItem", + "dynamodb:GetItem", + "dynamodb:Scan", + "dynamodb:Query", + "dynamodb:UpdateItem" + ], + "Effect": "Allow", + "Resource": [ + { + "Fn::Sub": [ + "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}", + { + "tablename": { + "Fn::Join": [ + "", + [ + "Todo-", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "-", + { + "Ref": "referencetotransformerrootstackenv10C5A902Ref" + } + ] + ] + } + } + ] + }, + { + "Fn::Sub": [ + "arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${tablename}/*", + { + "tablename": { + "Fn::Join": [ + "", + [ + "Todo-", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "-", + { + "Ref": "referencetotransformerrootstackenv10C5A902Ref" + } + ] + ] + } + } + ] + } + ] + } + ], + "Version": "2012-10-17" + }, + "PolicyName": "DynamoDBAccess71ABE5AE", + "Roles": [ + { + "Ref": "TodoIAMRole2DA8E66E" + } + ] + } + }, + "TodoDataSource": { + "Type": "AWS::AppSync::DataSource", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "Name": "TodoTable", + "Type": "AMAZON_DYNAMODB", + "DynamoDBConfig": { + "AwsRegion": { + "Ref": "AWS::Region" + }, + "TableName": { + "Ref": "TodoTable" + } + }, + "ServiceRoleArn": { + "Fn::GetAtt": ["TodoIAMRole2DA8E66E", "Arn"] + } + }, + "DependsOn": ["TodoIAMRole2DA8E66E"] + }, + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name" + }, + "Name": "QuerygetTodopostAuth0Function", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/3a607c80c325a3edcae10503ccceaaad8e73d3447432eceba2dab95a3a1c4665.vtl" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson({})" + } + }, + "QueryGetTodoDataResolverFnQueryGetTodoDataResolverFnAppSyncFunctionE2B57DAD": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Name": "QueryGetTodoDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/08f4d557693d96c1a4efba0f9dc91330e4b19772fd5477c156468843e3d9cb5e.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/4c6a2d29f01c6091bd1d9afe16e5849d456c96f17c3b215938c8067399532719.vtl" + ] + ] + } + }, + "DependsOn": ["TodoDataSource"] + }, + "GetTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "getTodo", + "TypeName": "Query", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "QueryGetTodoDataResolverFnQueryGetTodoDataResolverFnAppSyncFunctionE2B57DAD", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Query\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"getTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"AMAZON_DYNAMODB\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n$util.qr($ctx.stash.put(\"tableName\", \"", + { + "Ref": "TodoTable" + }, + "\"))\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "QueryListTodosDataResolverFnQueryListTodosDataResolverFnAppSyncFunctionF825FE47": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Name": "QueryListTodosDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/3665466abf40cc747bff935f1cf2f49edd920e2cd12d45d502d3857488b3ff3e.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/cc01911d0269d4080ea57505dc445dfc315ef7ad85d3d9d4ea1357858bff451d.vtl" + ] + ] + } + }, + "DependsOn": ["TodoDataSource"] + }, + "ListTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "listTodos", + "TypeName": "Query", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "QueryListTodosDataResolverFnQueryListTodosDataResolverFnAppSyncFunctionF825FE47", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Query\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"listTodos\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"AMAZON_DYNAMODB\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n$util.qr($ctx.stash.put(\"tableName\", \"", + { + "Ref": "TodoTable" + }, + "\"))\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "MutationcreateTodoinit0FunctionMutationcreateTodoinit0FunctionAppSyncFunction54DE5B8B": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name" + }, + "Name": "MutationcreateTodoinit0Function", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/01dd50f40481ed4d3b0fb1a5f22dbe631b252847144e59c565ad3874813dc77c.vtl" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson({})" + } + }, + "MutationCreateTodoDataResolverFnMutationCreateTodoDataResolverFnAppSyncFunction900EC5CF": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Name": "MutationCreateTodoDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/2bf64327ca5682da4be84d0d16440204e25abc3a221195b41f2d21dfa432e5ab.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249.vtl" + ] + ] + } + }, + "DependsOn": ["TodoDataSource"] + }, + "CreateTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "createTodo", + "TypeName": "Mutation", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "MutationcreateTodoinit0FunctionMutationcreateTodoinit0FunctionAppSyncFunction54DE5B8B", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "MutationCreateTodoDataResolverFnMutationCreateTodoDataResolverFnAppSyncFunction900EC5CF", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Mutation\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"createTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"AMAZON_DYNAMODB\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n$util.qr($ctx.stash.put(\"tableName\", \"", + { + "Ref": "TodoTable" + }, + "\"))\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "MutationupdateTodoinit0FunctionMutationupdateTodoinit0FunctionAppSyncFunction1B95BB19": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name" + }, + "Name": "MutationupdateTodoinit0Function", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/06db846fd14e6fc371f22b12b5545ba8e2dbfeda85d8c8d586c71c282166657b.vtl" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson({})" + } + }, + "MutationUpdateTodoDataResolverFnMutationUpdateTodoDataResolverFnAppSyncFunctionBC238C49": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Name": "MutationUpdateTodoDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/474bf0776ec2164a13191d1a0a9e057154931e4918fea5086f49850d02a5371b.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249.vtl" + ] + ] + } + }, + "DependsOn": ["TodoDataSource"] + }, + "UpdateTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "updateTodo", + "TypeName": "Mutation", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "MutationupdateTodoinit0FunctionMutationupdateTodoinit0FunctionAppSyncFunction1B95BB19", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "MutationUpdateTodoDataResolverFnMutationUpdateTodoDataResolverFnAppSyncFunctionBC238C49", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Mutation\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"updateTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"AMAZON_DYNAMODB\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n$util.qr($ctx.stash.put(\"tableName\", \"", + { + "Ref": "TodoTable" + }, + "\"))\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "MutationDeleteTodoDataResolverFnMutationDeleteTodoDataResolverFnAppSyncFunction3879153F": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Name": "MutationDeleteTodoDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/4f7907d1209a2c9953a0c053df402c634e359546d70c7cc5c2e8e21ea734880f.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/f4a52b72209a9dfa197b5e7367a5c378c5bb86de6e29ddd9e48b49a3fe54b249.vtl" + ] + ] + } + }, + "DependsOn": ["TodoDataSource"] + }, + "DeleteTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "deleteTodo", + "TypeName": "Mutation", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "MutationDeleteTodoDataResolverFnMutationDeleteTodoDataResolverFnAppSyncFunction3879153F", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Mutation\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"deleteTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"AMAZON_DYNAMODB\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n$util.qr($ctx.stash.put(\"tableName\", \"", + { + "Ref": "TodoTable" + }, + "\"))\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "SubscriptionOnCreateTodoDataResolverFnSubscriptionOnCreateTodoDataResolverFnAppSyncFunction462A70C9": { + "Type": "AWS::AppSync::FunctionConfiguration", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "DataSourceName": { + "Ref": "referencetotransformerrootstackGraphQLAPINONEDS2BA9D1C8Name" + }, + "Name": "SubscriptionOnCreateTodoDataResolverFn", + "FunctionVersion": "2018-05-29", + "RequestMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/fe3c43ada4b9d681a5e2312663ef7a73386424d73b73e51f8e2e9d4b50f7c502.vtl" + ] + ] + }, + "ResponseMappingTemplateS3Location": { + "Fn::Join": [ + "", + [ + "s3://", + { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "/e0cff47fb007f0bbf2a4e43ca256d6aa7ec109821769fd79fa7c5e83f0e7f9fc.vtl" + ] + ] + } + } + }, + "SubscriptiononCreateTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "onCreateTodo", + "TypeName": "Subscription", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "SubscriptionOnCreateTodoDataResolverFnSubscriptionOnCreateTodoDataResolverFnAppSyncFunction462A70C9", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Subscription\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"onCreateTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"NONE\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "SubscriptiononUpdateTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "onUpdateTodo", + "TypeName": "Subscription", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "SubscriptionOnCreateTodoDataResolverFnSubscriptionOnCreateTodoDataResolverFnAppSyncFunction462A70C9", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Subscription\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"onUpdateTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"NONE\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + }, + "SubscriptiononDeleteTodoResolver": { + "Type": "AWS::AppSync::Resolver", + "Properties": { + "ApiId": { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "FieldName": "onDeleteTodo", + "TypeName": "Subscription", + "Kind": "PIPELINE", + "PipelineConfig": { + "Functions": [ + { + "Fn::GetAtt": [ + "QuerygetTodopostAuth0FunctionQuerygetTodopostAuth0FunctionAppSyncFunction6BE14593", + "FunctionId" + ] + }, + { + "Fn::GetAtt": [ + "SubscriptionOnCreateTodoDataResolverFnSubscriptionOnCreateTodoDataResolverFnAppSyncFunction462A70C9", + "FunctionId" + ] + } + ] + }, + "RequestMappingTemplate": { + "Fn::Join": [ + "", + [ + "$util.qr($ctx.stash.put(\"typeName\", \"Subscription\"))\n$util.qr($ctx.stash.put(\"fieldName\", \"onDeleteTodo\"))\n$util.qr($ctx.stash.put(\"conditions\", []))\n$util.qr($ctx.stash.put(\"metadata\", {}))\n$util.qr($ctx.stash.metadata.put(\"dataSourceType\", \"NONE\"))\n$util.qr($ctx.stash.metadata.put(\"apiId\", \"", + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "\"))\n$util.qr($ctx.stash.put(\"connectionAttributes\", {}))\n\n$util.qr($ctx.stash.put(\"authRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackauthRoleNameFB872D50Ref" + }, + "/CognitoIdentityCredentials\"))\n$util.qr($ctx.stash.put(\"unauthRole\", \"arn:aws:sts::", + { + "Ref": "AWS::AccountId" + }, + ":assumed-role/", + { + "Ref": "referencetotransformerrootstackunauthRoleName49F3C1FERef" + }, + "/CognitoIdentityCredentials\"))\n$util.toJson({})" + ] + ] + }, + "ResponseMappingTemplate": "$util.toJson($ctx.prev.result)" + } + } + }, + "Outputs": { + "GetAttTodoTableStreamArn": { + "Description": "Your DynamoDB table StreamArn.", + "Value": { + "Fn::GetAtt": ["TodoTable", "StreamArn"] + }, + "Export": { + "Name": { + "Fn::Join": [ + ":", + [ + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "GetAtt:TodoTable:StreamArn" + ] + ] + } + } + }, + "GetAttTodoTableName": { + "Description": "Your DynamoDB table name.", + "Value": { + "Ref": "TodoTable" + }, + "Export": { + "Name": { + "Fn::Join": [ + ":", + [ + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "GetAtt:TodoTable:Name" + ] + ] + } + } + }, + "GetAttTodoDataSourceName": { + "Description": "Your model DataSource name.", + "Value": { + "Fn::GetAtt": ["TodoDataSource", "Name"] + }, + "Export": { + "Name": { + "Fn::Join": [ + ":", + [ + { + "Ref": "referencetotransformerrootstackGraphQLAPI20497F53ApiId" + }, + "GetAtt:TodoDataSource:Name" + ] + ] + } + } + } + } +} diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentfunction955F813A.nested.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentfunction955F813A.nested.template.json new file mode 100644 index 0000000000..5fbbde8eff --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentfunction955F813A.nested.template.json @@ -0,0 +1,55 @@ +{ + "Resources": { + "testFunctestFuncLambdaFunctionServiceRole09E19D41": { + "Type": "AWS::IAM::Role", + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": { + "Service": "lambda.amazonaws.com" + } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + { + "Fn::Join": [ + "", + [ + "arn:", + { + "Ref": "AWS::Partition" + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ] + ] + } + ] + } + }, + "testFunctestFuncLambdaFunction419C520E": { + "Type": "AWS::Lambda::Function", + "Properties": { + "Code": { + "S3Bucket": { + "Fn::Sub": "cdk-hnb659fds-assets-${AWS::AccountId}-${AWS::Region}" + }, + "S3Key": "efe12e580179d925ecc56ede6195533f23db3a8e887169b63ecb5cc644193f2b.zip" + }, + "Role": { + "Fn::GetAtt": [ + "testFunctestFuncLambdaFunctionServiceRole09E19D41", + "Arn" + ] + }, + "Handler": "index.handler", + "Runtime": "nodejs18.x" + }, + "DependsOn": ["testFunctestFuncLambdaFunctionServiceRole09E19D41"] + } + } +} diff --git a/packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProjecttestEnvironmentstorageD5B9103B.nested.template.json b/packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentstorageD5B9103B.nested.template.json similarity index 100% rename from packages/integration-tests/test-projects/auth-and-storage/expected-cdk-out/testProjecttestEnvironmentstorageD5B9103B.nested.template.json rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/expected-cdk-out/testProjecttestEnvironmentstorageD5B9103B.nested.template.json diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/func-src/mock.txt b/packages/integration-tests/test-projects/basic-auth-data-storage-function/func-src/mock.txt new file mode 100644 index 0000000000..29cc220aee --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/func-src/mock.txt @@ -0,0 +1,2 @@ +To test out creating a lambda we need a directory that simulates the lambda content. +Obviously this is not a real lambda, but it allows CDK synth to proceed. diff --git a/packages/integration-tests/test-projects/basic-auth-data-storage-function/function.ts b/packages/integration-tests/test-projects/basic-auth-data-storage-function/function.ts new file mode 100644 index 0000000000..1ca2c68399 --- /dev/null +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/function.ts @@ -0,0 +1,6 @@ +import { Func } from '@aws-amplify/backend-function'; + +export const myFunc = Func.fromDir({ + name: 'testFunc', + codePath: './func-src', +}); diff --git a/packages/integration-tests/test-projects/auth-and-storage/index.ts b/packages/integration-tests/test-projects/basic-auth-data-storage-function/index.ts similarity index 63% rename from packages/integration-tests/test-projects/auth-and-storage/index.ts rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/index.ts index cbe9d4a1f5..d7af69801b 100644 --- a/packages/integration-tests/test-projects/auth-and-storage/index.ts +++ b/packages/integration-tests/test-projects/basic-auth-data-storage-function/index.ts @@ -1,8 +1,12 @@ import { Backend } from '@aws-amplify/backend'; import { auth } from './auth.js'; import { storage } from './storage.js'; +import { myFunc } from './function.js'; +import { data } from './data.js'; new Backend({ auth, storage, + myFunc, + data, }); diff --git a/packages/integration-tests/test-projects/auth-and-storage/storage.ts b/packages/integration-tests/test-projects/basic-auth-data-storage-function/storage.ts similarity index 100% rename from packages/integration-tests/test-projects/auth-and-storage/storage.ts rename to packages/integration-tests/test-projects/basic-auth-data-storage-function/storage.ts diff --git a/packages/integration-tests/tsconfig.json b/packages/integration-tests/tsconfig.json index 6c78d9d6f3..d8f0185482 100644 --- a/packages/integration-tests/tsconfig.json +++ b/packages/integration-tests/tsconfig.json @@ -3,8 +3,8 @@ "compilerOptions": { "rootDir": "src", "outDir": "lib" }, "references": [ { "path": "../backend" }, - { "path": "../backend-storage" }, - { "path": "../backend-auth" } + { "path": "../backend-auth" }, + { "path": "../backend-storage" } ], "exclude": ["**/node_modules", "**/lib", "test-projects"] }