From 49abcbd04c56170aa9290636fee60a336a016429 Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Fri, 20 Dec 2024 02:36:13 +0300 Subject: [PATCH 01/13] feature(function): add custom provided function support to defineFunction --- packages/backend-function/src/factory.test.ts | 32 ++++ packages/backend-function/src/factory.ts | 110 ++++++-------- .../src/function_construct_base.ts | 58 +++++++ packages/backend-function/src/index.ts | 2 + .../src/provided_function_factory.ts | 143 ++++++++++++++++++ .../src/resource_access_acceptor.ts | 43 ++++++ .../amplify/func-src/handler_provider.ts | 7 + .../amplify/function.ts | 10 ++ 8 files changed, 340 insertions(+), 65 deletions(-) create mode 100644 packages/backend-function/src/function_construct_base.ts create mode 100644 packages/backend-function/src/provided_function_factory.ts create mode 100644 packages/backend-function/src/resource_access_acceptor.ts create mode 100644 packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provider.ts diff --git a/packages/backend-function/src/factory.test.ts b/packages/backend-function/src/factory.test.ts index 6bb63f14d2a..22801619b0a 100644 --- a/packages/backend-function/src/factory.test.ts +++ b/packages/backend-function/src/factory.test.ts @@ -20,6 +20,7 @@ import { Policy, PolicyStatement } from 'aws-cdk-lib/aws-iam'; import fsp from 'fs/promises'; import path from 'node:path'; import { AmplifyUserError } from '@aws-amplify/platform-core'; +import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; const createStackAndSetContext = (): Stack => { const app = new App(); @@ -750,4 +751,35 @@ void describe('AmplifyFunctionFactory', () => { ); }); }); + + void describe('provided function runtime property', () => { + void it('sets valid runtime', () => { + const lambda = defineFunction((scope) => { + return new NodejsFunction(scope, 'nodejs-provided', { + entry: + './packages/backend-function/src/test-assets/default-lambda/handler.ts', + runtime: Runtime.NODEJS_22_X, + }); + }).getInstance(getInstanceProps); + const template = Template.fromStack(lambda.stack); + + template.hasResourceProperties('AWS::Lambda::Function', { + Runtime: Runtime.NODEJS_22_X.name, + }); + }); + + void it('provided function defaults to oldest runtime', () => { + const lambda = defineFunction((scope) => { + return new NodejsFunction(scope, 'nodejs-provided', { + entry: + './packages/backend-function/src/test-assets/default-lambda/handler.ts', + }); + }).getInstance(getInstanceProps); + const template = Template.fromStack(lambda.stack); + + template.hasResourceProperties('AWS::Lambda::Function', { + Runtime: Runtime.NODEJS_16_X.name, + }); + }); + }); }); diff --git a/packages/backend-function/src/factory.ts b/packages/backend-function/src/factory.ts index 7f2f04b0815..06119bf1474 100644 --- a/packages/backend-function/src/factory.ts +++ b/packages/backend-function/src/factory.ts @@ -1,8 +1,4 @@ -import { - FunctionOutput, - functionOutputKey, -} from '@aws-amplify/backend-output-schemas'; -import { AttributionMetadataStorage } from '@aws-amplify/backend-output-storage'; +import { FunctionOutput } from '@aws-amplify/backend-output-schemas'; import { AmplifyUserError, CallerDirectoryExtractor, @@ -20,18 +16,18 @@ import { GenerateContainerEntryProps, LogLevel, LogRetention, + ResourceAccessAcceptor, ResourceAccessAcceptorFactory, ResourceNameValidator, ResourceProvider, - SsmEnvironmentEntry, StackProvider, } from '@aws-amplify/plugin-types'; import { Duration, Size, Stack, Tags } from 'aws-cdk-lib'; import { Rule } from 'aws-cdk-lib/aws-events'; import * as targets from 'aws-cdk-lib/aws-events-targets'; -import { Policy } from 'aws-cdk-lib/aws-iam'; import { CfnFunction, + IFunction, ILayerVersion, LayerVersion, Runtime, @@ -40,7 +36,6 @@ import { NodejsFunction, OutputFormat } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Construct } from 'constructs'; import { readFileSync } from 'fs'; import { createRequire } from 'module'; -import { fileURLToPath } from 'node:url'; import { EOL } from 'os'; import * as path from 'path'; import { FunctionEnvironmentTranslator } from './function_env_translator.js'; @@ -48,8 +43,12 @@ import { FunctionEnvironmentTypeGenerator } from './function_env_type_generator. import { FunctionLayerArnParser } from './layer_parser.js'; import { convertLoggingOptionsToCDK } from './logging_options_parser.js'; import { convertFunctionSchedulesToRuleSchedules } from './schedule_parser.js'; - -const functionStackType = 'function-Lambda'; +import { + ProvidedFunctionFactory, + ProvidedFunctionProps, +} from './provided_function_factory.js'; +import { AmplifyFunctionBase } from './function_construct_base.js'; +import { FunctionResourceAccessAcceptor } from './resource_access_acceptor.js'; export type AddEnvironmentFactory = { addEnvironment: (key: string, value: string | BackendSecret) => void; @@ -70,17 +69,38 @@ export type FunctionSchedule = TimeInterval | CronSchedule; export type FunctionLogLevel = LogLevel; export type FunctionLogRetention = LogRetention; -/** - * Entry point for defining a function in the Amplify ecosystem - */ -export const defineFunction = ( - props: FunctionProps = {} +export function defineFunction( + props?: FunctionProps ): ConstructFactory< ResourceProvider & ResourceAccessAcceptorFactory & AddEnvironmentFactory & StackProvider -> => new FunctionFactory(props, new Error().stack); +>; +export function defineFunction( + provider: (scope: Construct) => IFunction, + providerProps?: ProvidedFunctionProps +): ConstructFactory< + ResourceProvider & + ResourceAccessAcceptorFactory & + StackProvider +>; +/** + * Entry point for defining a function in the Amplify ecosystem + */ +// This is the "implementation overload", it's not visible in public api. +// We have to use function notation instead of arrow notation. +// Arrow notation does not support overloads. +// eslint-disable-next-line no-restricted-syntax +export function defineFunction( + propsOrProvider: FunctionProps | ((scope: Construct) => IFunction) = {}, + providerProps?: ProvidedFunctionProps +): unknown { + if (propsOrProvider && typeof propsOrProvider === 'function') { + return new ProvidedFunctionFactory(propsOrProvider, providerProps); + } + return new FunctionFactory(propsOrProvider, new Error().stack); +} export type FunctionProps = { /** @@ -477,14 +497,10 @@ class FunctionGenerator implements ConstructContainerEntryGenerator { } class AmplifyFunction - extends Construct - implements - ResourceProvider, - ResourceAccessAcceptorFactory, - AddEnvironmentFactory + extends AmplifyFunctionBase + implements AddEnvironmentFactory { readonly resources: FunctionResources; - readonly stack: Stack; private readonly functionEnvironmentTranslator: FunctionEnvironmentTranslator; constructor( scope: Construct, @@ -493,9 +509,7 @@ class AmplifyFunction backendSecretResolver: BackendSecretResolver, outputStorageStrategy: BackendOutputStorageStrategy ) { - super(scope, id); - - this.stack = Stack.of(scope); + super(scope, id, outputStorageStrategy); const runtime = nodeVersionMap[props.runtime]; @@ -616,52 +630,18 @@ class AmplifyFunction }, }; - this.storeOutput(outputStorageStrategy); - - new AttributionMetadataStorage().storeAttributionMetadata( - Stack.of(this), - functionStackType, - fileURLToPath(new URL('../package.json', import.meta.url)) - ); + this.storeOutput(); } addEnvironment = (key: string, value: string | BackendSecret) => { this.functionEnvironmentTranslator.addEnvironmentEntry(key, value); }; - getResourceAccessAcceptor = () => ({ - identifier: `${this.node.id}LambdaResourceAccessAcceptor`, - acceptResourceAccess: ( - policy: Policy, - ssmEnvironmentEntries: SsmEnvironmentEntry[] - ) => { - const role = this.resources.lambda.role; - if (!role) { - // This should never happen since we are using the Function L2 construct - throw new Error( - 'No execution role found to attach lambda permissions to' - ); - } - policy.attachToRole(role); - ssmEnvironmentEntries.forEach(({ name, path }) => { - this.functionEnvironmentTranslator.addSsmEnvironmentEntry(name, path); - }); - }, - }); - - /** - * Store storage outputs using provided strategy - */ - private storeOutput = ( - outputStorageStrategy: BackendOutputStorageStrategy - ): void => { - outputStorageStrategy.appendToBackendOutputList(functionOutputKey, { - version: '1', - payload: { - definedFunctions: this.resources.lambda.functionName, - }, - }); - }; + getResourceAccessAcceptor = (): ResourceAccessAcceptor => + new FunctionResourceAccessAcceptor( + this, + this.functionEnvironmentTranslator + ); } const isWholeNumberBetweenInclusive = ( diff --git a/packages/backend-function/src/function_construct_base.ts b/packages/backend-function/src/function_construct_base.ts new file mode 100644 index 00000000000..73de12e5dba --- /dev/null +++ b/packages/backend-function/src/function_construct_base.ts @@ -0,0 +1,58 @@ +import { Construct } from 'constructs'; +import { + BackendOutputStorageStrategy, + FunctionResources, + ResourceAccessAcceptor, + ResourceAccessAcceptorFactory, + ResourceProvider, +} from '@aws-amplify/plugin-types'; +import { Stack } from 'aws-cdk-lib'; +import { + FunctionOutput, + functionOutputKey, +} from '@aws-amplify/backend-output-schemas'; +import { AttributionMetadataStorage } from '@aws-amplify/backend-output-storage'; +import { fileURLToPath } from 'node:url'; + +const functionStackType = 'function-Lambda'; + +/** + * A base class for function constructs. + */ +export abstract class AmplifyFunctionBase + extends Construct + implements ResourceProvider, ResourceAccessAcceptorFactory +{ + readonly stack: Stack; + abstract resources: FunctionResources; + + abstract getResourceAccessAcceptor: () => ResourceAccessAcceptor; + + /** + * Creates base function construct. + */ + protected constructor( + scope: Construct, + id: string, + private readonly outputStorageStrategy: BackendOutputStorageStrategy + ) { + super(scope, id); + + this.stack = Stack.of(scope); + + new AttributionMetadataStorage().storeAttributionMetadata( + Stack.of(this), + functionStackType, + fileURLToPath(new URL('../package.json', import.meta.url)) + ); + } + + protected storeOutput = (): void => { + this.outputStorageStrategy.appendToBackendOutputList(functionOutputKey, { + version: '1', + payload: { + definedFunctions: this.resources.lambda.functionName, + }, + }); + }; +} diff --git a/packages/backend-function/src/index.ts b/packages/backend-function/src/index.ts index cb95b1ef8d8..8d9b853ad39 100644 --- a/packages/backend-function/src/index.ts +++ b/packages/backend-function/src/index.ts @@ -1 +1,3 @@ export * from './factory.js'; +import { ProvidedFunctionProps } from './provided_function_factory.js'; +export { ProvidedFunctionProps }; diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts new file mode 100644 index 00000000000..370998e8cd0 --- /dev/null +++ b/packages/backend-function/src/provided_function_factory.ts @@ -0,0 +1,143 @@ +import { + AmplifyFunction, + AmplifyResourceGroupName, + BackendOutputStorageStrategy, + ConstructContainerEntryGenerator, + ConstructFactory, + ConstructFactoryGetInstanceProps, + FunctionResources, + GenerateContainerEntryProps, + ResourceAccessAcceptor, +} from '@aws-amplify/plugin-types'; +import { Construct } from 'constructs'; +import { CfnFunction, IFunction } from 'aws-cdk-lib/aws-lambda'; +import { FunctionOutput } from '@aws-amplify/backend-output-schemas'; +import { Tags } from 'aws-cdk-lib'; +import { AmplifyUserError, TagName } from '@aws-amplify/platform-core'; +import { AmplifyFunctionBase } from './function_construct_base.js'; +import { FunctionResourceAccessAcceptor } from './resource_access_acceptor.js'; + +export type ProvidedFunctionProps = { + /** + * Group the function with existing Amplify resources or separate the function into its own group. + * @default 'function' // grouping with other Amplify functions + * @example + * resourceGroupName: 'auth' // to group an auth trigger with an auth resource + */ + resourceGroupName?: AmplifyResourceGroupName; +}; + +/** + * Adapts provided CDK function as Amplify function. + */ +export class ProvidedFunctionFactory + implements ConstructFactory +{ + private generator: ConstructContainerEntryGenerator; + + /** + * Creates provided function factory. + */ + constructor( + private readonly functionProvider: (scope: Construct) => IFunction, + private readonly props?: ProvidedFunctionProps + ) {} + + /** + * Creates a function instance. + */ + getInstance(props: ConstructFactoryGetInstanceProps): AmplifyFunction { + if (!this.generator) { + this.generator = new ProvidedFunctionGenerator( + this.functionProvider, + props.outputStorageStrategy, + this.props + ); + } + return props.constructContainer.getOrCompute( + this.generator + ) as AmplifyFunction; + } +} + +class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { + readonly resourceGroupName: AmplifyResourceGroupName; + + constructor( + private readonly functionProvider: (scope: Construct) => IFunction, + private readonly outputStorageStrategy: BackendOutputStorageStrategy, + props?: ProvidedFunctionProps + ) { + this.resourceGroupName = props?.resourceGroupName ?? 'function'; + } + + generateContainerEntry = ({ scope }: GenerateContainerEntryProps) => { + let providedFunction: IFunction; + try { + providedFunction = this.functionProvider(scope); + } catch (e) { + if ( + e instanceof Error && + (e.message.includes('docker exited with status 1') || + e.message.includes('docker ENOENT')) + ) { + throw new AmplifyUserError( + 'FunctionBundlingDockerError', + { + message: e.message, + // TODO better resolution + resolution: + 'Ensure that docker is present and works correctly. See https://some.link.about.docker.', + }, + e + ); + } else { + throw new AmplifyUserError( + 'FunctionProviderError', + { + message: e instanceof Error ? e.message : JSON.stringify(e), + // TODO better resolution + resolution: 'Ensure that function provider is working.', + }, + e instanceof Error ? e : undefined + ); + } + } + return new ProvidedAmplifyFunction( + scope, + `${providedFunction.node.id}-provided`, + this.outputStorageStrategy, + providedFunction + ); + }; +} + +class ProvidedAmplifyFunction extends AmplifyFunctionBase { + readonly resources: FunctionResources; + constructor( + scope: Construct, + id: string, + outputStorageStrategy: BackendOutputStorageStrategy, + providedFunction: IFunction + ) { + super(scope, id, outputStorageStrategy); + + const cfnFunction = providedFunction.node.findChild( + 'Resource' + ) as CfnFunction; + + Tags.of(cfnFunction).add(TagName.FRIENDLY_NAME, providedFunction.node.id); + + this.resources = { + lambda: providedFunction, + cfnResources: { + cfnFunction, + }, + }; + + this.storeOutput(); + } + + getResourceAccessAcceptor = (): ResourceAccessAcceptor => + new FunctionResourceAccessAcceptor(this); +} diff --git a/packages/backend-function/src/resource_access_acceptor.ts b/packages/backend-function/src/resource_access_acceptor.ts new file mode 100644 index 00000000000..e3ba57aaf66 --- /dev/null +++ b/packages/backend-function/src/resource_access_acceptor.ts @@ -0,0 +1,43 @@ +import { + ResourceAccessAcceptor, + SsmEnvironmentEntry, +} from '@aws-amplify/plugin-types'; +import { FunctionEnvironmentTranslator } from './function_env_translator.js'; +import { AmplifyFunctionBase } from './function_construct_base.js'; +import { Policy } from 'aws-cdk-lib/aws-iam'; + +/** + * A function resource acceptor. + */ +export class FunctionResourceAccessAcceptor implements ResourceAccessAcceptor { + readonly identifier: string; + + /** + * Creates function resource acceptor. + */ + constructor( + private readonly func: AmplifyFunctionBase, + private readonly functionEnvironmentTranslator?: FunctionEnvironmentTranslator + ) { + this.identifier = `${func.node.id}LambdaResourceAccessAcceptor`; + } + + acceptResourceAccess = ( + policy: Policy, + ssmEnvironmentEntries: SsmEnvironmentEntry[] + ) => { + const role = this.func.resources.lambda.role; + if (!role) { + // This should never happen since we are using the Function L2 construct + throw new Error( + 'No execution role found to attach lambda permissions to' + ); + } + policy.attachToRole(role); + if (this.functionEnvironmentTranslator) { + for (const { name, path } of ssmEnvironmentEntries) { + this.functionEnvironmentTranslator.addSsmEnvironmentEntry(name, path); + } + } + }; +} diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provider.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provider.ts new file mode 100644 index 00000000000..f7c71c983ca --- /dev/null +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provider.ts @@ -0,0 +1,7 @@ +/** + * This function is a simple hello world function. + * It's for not direct defineFunction, it's provided function + */ +export const handler = async () => { + return 'Hello from NodeJS Function!'; +}; diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts index a4f30ef66f1..e2be6f063d6 100644 --- a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts @@ -1,4 +1,6 @@ import { defineFunction } from '@aws-amplify/backend'; +import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; +import { Runtime } from 'aws-cdk-lib/aws-lambda'; export const funcWithSsm = defineFunction({ name: 'funcWithSsm', @@ -24,6 +26,14 @@ export const funcNoMinify = defineFunction({ }, }); +export const funcProvided = defineFunction((scope) => { + return new NodejsFunction(scope, 'funcProvided', { + entry: + './packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provided.ts', + runtime: Runtime.NODEJS_18_X, + }); +}); + export const funcCustomEmailSender = defineFunction({ name: 'funcCustomEmailSender', entry: './func-src/handler_custom_email_sender.ts', From dbdccba727792d35ea0d736133d76ed9c852febc Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Fri, 20 Dec 2024 02:38:50 +0300 Subject: [PATCH 02/13] chore: add changeset --- .changeset/long-berries-greet.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/long-berries-greet.md diff --git a/.changeset/long-berries-greet.md b/.changeset/long-berries-greet.md new file mode 100644 index 00000000000..97ed16116f5 --- /dev/null +++ b/.changeset/long-berries-greet.md @@ -0,0 +1,6 @@ +--- +'@aws-amplify/integration-tests': minor +'@aws-amplify/backend-function': minor +--- + +add custom provided function support to define function From 26ea2f2bd5532479e902b84197ed097fbf609486 Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Sun, 22 Dec 2024 22:33:45 +0300 Subject: [PATCH 03/13] chore(function): fix e2ee path and changeset --- .changeset/long-berries-greet.md | 1 - .../advanced-auth-and-functions/amplify/function.ts | 3 +-- .../advanced-auth-and-functions/amplify/test_factories.ts | 2 ++ 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.changeset/long-berries-greet.md b/.changeset/long-berries-greet.md index 97ed16116f5..7720f0e6996 100644 --- a/.changeset/long-berries-greet.md +++ b/.changeset/long-berries-greet.md @@ -1,5 +1,4 @@ --- -'@aws-amplify/integration-tests': minor '@aws-amplify/backend-function': minor --- diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts index e2be6f063d6..530046e004f 100644 --- a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts @@ -28,8 +28,7 @@ export const funcNoMinify = defineFunction({ export const funcProvided = defineFunction((scope) => { return new NodejsFunction(scope, 'funcProvided', { - entry: - './packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/func-src/handler_provided.ts', + entry: './func-src/handler_provided.ts', runtime: Runtime.NODEJS_18_X, }); }); diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/test_factories.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/test_factories.ts index 4e72f34424b..4841663dc03 100644 --- a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/test_factories.ts +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/test_factories.ts @@ -4,6 +4,7 @@ import { funcWithAwsSdk, funcWithSchedule, funcWithSsm, + funcProvided, } from './function.js'; import { auth } from './auth/resource.js'; @@ -14,4 +15,5 @@ export const authAndFunctions = { funcWithSchedule, funcNoMinify, funcCustomEmailSender, + funcProvided, }; From 9f6f2e4d4a59232f6707508aced355987a000019 Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Sun, 22 Dec 2024 22:34:37 +0300 Subject: [PATCH 04/13] chore(function): add new API.md --- packages/backend-function/API.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/packages/backend-function/API.md b/packages/backend-function/API.md index d5453c7eb39..522f636ae62 100644 --- a/packages/backend-function/API.md +++ b/packages/backend-function/API.md @@ -6,8 +6,10 @@ import { AmplifyResourceGroupName } from '@aws-amplify/plugin-types'; import { BackendSecret } from '@aws-amplify/plugin-types'; +import { Construct } from 'constructs'; import { ConstructFactory } from '@aws-amplify/plugin-types'; import { FunctionResources } from '@aws-amplify/plugin-types'; +import { IFunction } from 'aws-cdk-lib/aws-lambda'; import { LogLevel } from '@aws-amplify/plugin-types'; import { LogRetention } from '@aws-amplify/plugin-types'; import { ResourceAccessAcceptorFactory } from '@aws-amplify/plugin-types'; @@ -61,8 +63,11 @@ type DataClientError = { // @public (undocumented) type DataClientReturn = T extends DataClientEnv ? DataClientConfig : DataClientError; -// @public -export const defineFunction: (props?: FunctionProps) => ConstructFactory & ResourceAccessAcceptorFactory & AddEnvironmentFactory & StackProvider>; +// @public (undocumented) +export function defineFunction(props?: FunctionProps): ConstructFactory & ResourceAccessAcceptorFactory & AddEnvironmentFactory & StackProvider>; + +// @public (undocumented) +export function defineFunction(provider: (scope: Construct) => IFunction, providerProps?: ProvidedFunctionProps): ConstructFactory & ResourceAccessAcceptorFactory & StackProvider>; // @public (undocumented) export type FunctionBundlingOptions = { @@ -131,6 +136,11 @@ type LibraryOptions = { // @public (undocumented) export type NodeVersion = 16 | 18 | 20 | 22; +// @public (undocumented) +export type ProvidedFunctionProps = { + resourceGroupName?: AmplifyResourceGroupName; +}; + // @public (undocumented) type ResourceConfig = { API: { From cefa084d18ab0ff7de439df1bdef7c7db1f27878 Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 31 Dec 2024 10:00:28 +0300 Subject: [PATCH 05/13] fix(function): fix e2ee tests for provided function Co-authored-by: Kamil Sobol --- .../advanced-auth-and-functions/amplify/function.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts index 530046e004f..590462eef55 100644 --- a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts @@ -28,7 +28,12 @@ export const funcNoMinify = defineFunction({ export const funcProvided = defineFunction((scope) => { return new NodejsFunction(scope, 'funcProvided', { - entry: './func-src/handler_provided.ts', + entry: path.resolve( + fileURLToPath(import.meta.url), + '..', + 'func-src', + 'handler_provider.ts' + ), runtime: Runtime.NODEJS_18_X, }); }); From 53b475f77d4f0c7165dbaf5703900d3bc6509c2f Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 31 Dec 2024 10:01:23 +0300 Subject: [PATCH 06/13] chore: change changeset Co-authored-by: Kamil Sobol --- .changeset/long-berries-greet.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.changeset/long-berries-greet.md b/.changeset/long-berries-greet.md index 7720f0e6996..c0ad1b3e797 100644 --- a/.changeset/long-berries-greet.md +++ b/.changeset/long-berries-greet.md @@ -1,5 +1,6 @@ --- '@aws-amplify/backend-function': minor +'@aws-amplify/backend': minor --- add custom provided function support to define function From 89b52d4d00be0afe223b16112bac867386816736 Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 31 Dec 2024 10:04:01 +0300 Subject: [PATCH 07/13] chore(function): add without docker error message Co-authored-by: Kamil Sobol --- packages/backend-function/src/provided_function_factory.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 370998e8cd0..964903725ef 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -82,12 +82,11 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { e.message.includes('docker ENOENT')) ) { throw new AmplifyUserError( - 'FunctionBundlingDockerError', + 'CustomFunctionProviderDockerRequiredError', { message: e.message, - // TODO better resolution resolution: - 'Ensure that docker is present and works correctly. See https://some.link.about.docker.', + 'See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details about current limitations and troubleshooting steps.', }, e ); From 497da33bc4ae54ec9b8f89f09d012acc67fd5c3d Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 31 Dec 2024 10:05:09 +0300 Subject: [PATCH 08/13] chore(function): add provided function error message Co-authored-by: Kamil Sobol --- packages/backend-function/src/provided_function_factory.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 964903725ef..2647563ed47 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -92,11 +92,10 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { ); } else { throw new AmplifyUserError( - 'FunctionProviderError', + 'CustomFunctionProviderError', { message: e instanceof Error ? e.message : JSON.stringify(e), - // TODO better resolution - resolution: 'Ensure that function provider is working.', + resolution: "Ensure that callback passed to 'defineFunction' executes without error. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", }, e instanceof Error ? e : undefined ); From 70db0889e3b0dc49c4e3a99a2a09415d2adeda6b Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Thu, 2 Jan 2025 00:29:12 +0300 Subject: [PATCH 09/13] chore(function): add missing imports --- .../advanced-auth-and-functions/amplify/function.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts index 590462eef55..8784959dffc 100644 --- a/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts +++ b/packages/integration-tests/src/test-projects/advanced-auth-and-functions/amplify/function.ts @@ -1,6 +1,8 @@ import { defineFunction } from '@aws-amplify/backend'; import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs'; import { Runtime } from 'aws-cdk-lib/aws-lambda'; +import * as path from 'path'; +import { fileURLToPath } from 'url'; export const funcWithSsm = defineFunction({ name: 'funcWithSsm', From cbaa8bc452270d58887c96f1c32dbb0cbb4efc4b Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Fri, 3 Jan 2025 03:17:46 +0300 Subject: [PATCH 10/13] chore(function): fix lint error --- packages/backend-function/src/provided_function_factory.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 2647563ed47..79343cc855d 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -95,7 +95,8 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { 'CustomFunctionProviderError', { message: e instanceof Error ? e.message : JSON.stringify(e), - resolution: "Ensure that callback passed to 'defineFunction' executes without error. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", + resolution: + "Ensure that callback passed to 'defineFunction' executes without error. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", }, e instanceof Error ? e : undefined ); From 7a799236d8ec59e91ca3cfd3279a5b5eb573ef1c Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 7 Jan 2025 21:27:50 +0300 Subject: [PATCH 11/13] Update packages/backend-function/src/provided_function_factory.ts Co-authored-by: Amplifiyer <51211245+Amplifiyer@users.noreply.github.com> --- packages/backend-function/src/provided_function_factory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 79343cc855d..3a6a2d51e2f 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -82,9 +82,9 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { e.message.includes('docker ENOENT')) ) { throw new AmplifyUserError( - 'CustomFunctionProviderDockerRequiredError', + 'CustomFunctionProviderDockerError', { - message: e.message, + message: 'Failed to instantiate custom function provider', resolution: 'See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details about current limitations and troubleshooting steps.', }, From 10726dd3eadb0e23b4cb208b168ccb157a105689 Mon Sep 17 00:00:00 2001 From: Burak Karahan <2015110802008@ogrenci.karabuk.edu.tr> Date: Tue, 7 Jan 2025 21:28:03 +0300 Subject: [PATCH 12/13] Update packages/backend-function/src/provided_function_factory.ts Co-authored-by: Amplifiyer <51211245+Amplifiyer@users.noreply.github.com> --- packages/backend-function/src/provided_function_factory.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 3a6a2d51e2f..58aabffdfad 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -94,9 +94,9 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { throw new AmplifyUserError( 'CustomFunctionProviderError', { - message: e instanceof Error ? e.message : JSON.stringify(e), + message: 'Failed to instantiate custom function provider', resolution: - "Ensure that callback passed to 'defineFunction' executes without error. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", + "Check the definition of your custom function provided in `defineFunction` and refer to the logs for more information. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", }, e instanceof Error ? e : undefined ); From aa6762e07046c305aa89c300730cf9d9639edb03 Mon Sep 17 00:00:00 2001 From: Burak Karahan Date: Tue, 7 Jan 2025 23:47:55 +0300 Subject: [PATCH 13/13] chore(function): fix lint issue --- packages/backend-function/src/provided_function_factory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend-function/src/provided_function_factory.ts b/packages/backend-function/src/provided_function_factory.ts index 58aabffdfad..2d6becb0117 100644 --- a/packages/backend-function/src/provided_function_factory.ts +++ b/packages/backend-function/src/provided_function_factory.ts @@ -96,7 +96,7 @@ class ProvidedFunctionGenerator implements ConstructContainerEntryGenerator { { message: 'Failed to instantiate custom function provider', resolution: - "Check the definition of your custom function provided in `defineFunction` and refer to the logs for more information. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.", + 'Check the definition of your custom function provided in `defineFunction` and refer to the logs for more information. See https://docs.amplify.aws/react/build-a-backend/functions/custom-functions for more details.', }, e instanceof Error ? e : undefined );