Skip to content

Commit ab7533d

Browse files
authored
add output and configuration for customer owned lambdas (#1029)
* add output and configuration for customer owned lambdas * add back removed code * refactor logic to add to backend output * small api update * prevent prototype-polluting assignment * prevent prototype-polluting assignment * small updates to deployed backend client * update changeset * use maps for lazyLists * fix lint * add test to throw when trying to enter a different version than existing version * poke ci * remove function outputs accumulator * remove comment * nit fixes * add tests * rename customerFunctions to definedFunctions * nit fixes
1 parent 88c1b28 commit ab7533d

File tree

23 files changed

+499
-21
lines changed

23 files changed

+499
-21
lines changed

.changeset/brave-carrots-glow.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@aws-amplify/deployed-backend-client': minor
3+
'@aws-amplify/backend-output-schemas': minor
4+
'@aws-amplify/backend-output-storage': minor
5+
'@aws-amplify/backend-function': minor
6+
'@aws-amplify/backend-storage': patch
7+
'@aws-amplify/auth-construct-alpha': patch
8+
'@aws-amplify/platform-core': patch
9+
'@aws-amplify/plugin-types': patch
10+
'@aws-amplify/backend': patch
11+
---
12+
13+
Add output and configuration for customer owned lambdas

packages/auth-construct/src/construct.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,7 @@ void describe('Auth construct', () => {
533533
const stubBackendOutputStorageStrategy: BackendOutputStorageStrategy<BackendOutputEntry> =
534534
{
535535
addBackendOutputEntry: storeOutputMock,
536+
appendToBackendOutputList: storeOutputMock,
536537
};
537538

538539
void beforeEach(() => {

packages/backend-function/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
},
1919
"license": "Apache-2.0",
2020
"dependencies": {
21+
"@aws-amplify/backend-output-schemas": "^0.6.0",
2122
"@aws-amplify/backend-output-storage": "^0.3.1-beta.0",
2223
"@aws-amplify/plugin-types": "^0.8.0",
2324
"execa": "^8.0.1"

packages/backend-function/src/factory.test.ts

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,17 +24,18 @@ const createStackAndSetContext = (): Stack => {
2424
};
2525

2626
void describe('AmplifyFunctionFactory', () => {
27+
let rootStack: Stack;
2728
let getInstanceProps: ConstructFactoryGetInstanceProps;
2829

2930
beforeEach(() => {
30-
const stack = createStackAndSetContext();
31+
rootStack = createStackAndSetContext();
3132

3233
const constructContainer = new ConstructContainerStub(
33-
new StackResolverStub(stack)
34+
new StackResolverStub(rootStack)
3435
);
3536

3637
const outputStorageStrategy = new StackMetadataBackendOutputStorageStrategy(
37-
stack
38+
rootStack
3839
);
3940

4041
getInstanceProps = {
@@ -304,4 +305,35 @@ void describe('AmplifyFunctionFactory', () => {
304305
});
305306
});
306307
});
308+
309+
void describe('storeOutput', () => {
310+
void it('stores output using the provided strategy', () => {
311+
const functionFactory = defineFunction({
312+
entry: './test-assets/default-lambda/handler.ts',
313+
name: 'testLambdaName',
314+
});
315+
functionFactory.getInstance(getInstanceProps);
316+
const template = Template.fromStack(rootStack);
317+
// Getting output value is messy due to usage of Lazy to defer output value
318+
const outputValue =
319+
template.findOutputs('definedFunctions').definedFunctions.Value;
320+
assert.deepStrictEqual(outputValue, {
321+
['Fn::Join']: [
322+
'',
323+
[
324+
'["',
325+
{
326+
['Fn::GetAtt']: [
327+
/* eslint-disable spellcheck/spell-checker */
328+
'functionNestedStackfunctionNestedStackResource1351588B',
329+
'Outputs.functiontestLambdaNamelambda36106226Ref',
330+
/* eslint-enable spellcheck/spell-checker */
331+
],
332+
},
333+
'"]',
334+
],
335+
],
336+
});
337+
});
338+
});
307339
});

packages/backend-function/src/factory.ts

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
BackendOutputStorageStrategy,
23
BackendSecret,
34
BackendSecretResolver,
45
ConstructContainerEntryGenerator,
@@ -21,6 +22,10 @@ import { FunctionEnvironmentTranslator } from './function_env_translator.js';
2122
import { Policy } from 'aws-cdk-lib/aws-iam';
2223
import { readFileSync } from 'fs';
2324
import { EOL } from 'os';
25+
import {
26+
FunctionOutput,
27+
functionOutputKey,
28+
} from '@aws-amplify/backend-output-schemas';
2429

2530
/**
2631
* Entry point for defining a function in the Amplify ecosystem
@@ -95,9 +100,13 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
95100
*/
96101
getInstance = ({
97102
constructContainer,
103+
outputStorageStrategy,
98104
}: ConstructFactoryGetInstanceProps): AmplifyFunction => {
99105
if (!this.generator) {
100-
this.generator = new FunctionGenerator(this.hydrateDefaults());
106+
this.generator = new FunctionGenerator(
107+
this.hydrateDefaults(),
108+
outputStorageStrategy
109+
);
101110
}
102111
return constructContainer.getOrCompute(this.generator) as AmplifyFunction;
103112
};
@@ -206,7 +215,10 @@ type HydratedFunctionProps = Required<FunctionProps>;
206215
class FunctionGenerator implements ConstructContainerEntryGenerator {
207216
readonly resourceGroupName = 'function';
208217

209-
constructor(private readonly props: HydratedFunctionProps) {}
218+
constructor(
219+
private readonly props: HydratedFunctionProps,
220+
private readonly outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
221+
) {}
210222

211223
generateContainerEntry = ({
212224
scope,
@@ -216,7 +228,8 @@ class FunctionGenerator implements ConstructContainerEntryGenerator {
216228
scope,
217229
this.props.name,
218230
this.props,
219-
backendSecretResolver
231+
backendSecretResolver,
232+
this.outputStorageStrategy
220233
);
221234
};
222235
}
@@ -231,7 +244,8 @@ class AmplifyFunction
231244
scope: Construct,
232245
id: string,
233246
props: HydratedFunctionProps,
234-
backendSecretResolver: BackendSecretResolver
247+
backendSecretResolver: BackendSecretResolver,
248+
outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
235249
) {
236250
super(scope, id);
237251

@@ -284,6 +298,8 @@ class AmplifyFunction
284298
this.resources = {
285299
lambda: functionLambda,
286300
};
301+
302+
this.storeOutput(outputStorageStrategy);
287303
}
288304

289305
getResourceAccessAcceptor = () => ({
@@ -305,6 +321,20 @@ class AmplifyFunction
305321
});
306322
},
307323
});
324+
325+
/**
326+
* Store storage outputs using provided strategy
327+
*/
328+
private storeOutput = (
329+
outputStorageStrategy: BackendOutputStorageStrategy<FunctionOutput>
330+
): void => {
331+
outputStorageStrategy.appendToBackendOutputList(functionOutputKey, {
332+
version: '1',
333+
payload: {
334+
definedFunctions: this.resources.lambda.functionName,
335+
},
336+
});
337+
};
308338
}
309339

310340
const isWholeNumberBetweenInclusive = (

packages/backend-function/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
"extends": "../../tsconfig.base.json",
33
"compilerOptions": { "rootDir": "src", "outDir": "lib" },
44
"references": [
5+
{ "path": "../backend-output-schemas" },
56
{ "path": "../backend-output-storage" },
67
{ "path": "../plugin-types" },
78
{ "path": "../backend-platform-test-stubs" },

packages/backend-output-schemas/API.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ export type CustomOutput = z.infer<typeof versionedCustomOutputSchema>;
5454
// @public
5555
export const customOutputKey = "AWS::Amplify::Custom";
5656

57+
// @public (undocumented)
58+
export type FunctionOutput = z.infer<typeof versionedFunctionOutputSchema>;
59+
60+
// @public
61+
export const functionOutputKey = "AWS::Amplify::Function";
62+
5763
// @public (undocumented)
5864
export type GraphqlOutput = z.infer<typeof versionedGraphqlOutputSchema>;
5965

@@ -329,6 +335,26 @@ export const unifiedBackendOutputSchema: z.ZodObject<{
329335
customOutputs: string;
330336
};
331337
}>]>>;
338+
"AWS::Amplify::Function": z.ZodOptional<z.ZodDiscriminatedUnion<"version", [z.ZodObject<{
339+
version: z.ZodLiteral<"1">;
340+
payload: z.ZodObject<{
341+
definedFunctions: z.ZodString;
342+
}, "strip", z.ZodTypeAny, {
343+
definedFunctions: string;
344+
}, {
345+
definedFunctions: string;
346+
}>;
347+
}, "strip", z.ZodTypeAny, {
348+
version: "1";
349+
payload: {
350+
definedFunctions: string;
351+
};
352+
}, {
353+
version: "1";
354+
payload: {
355+
definedFunctions: string;
356+
};
357+
}>]>>;
332358
}, "strip", z.ZodTypeAny, {
333359
"AWS::Amplify::Platform"?: {
334360
version: "1";
@@ -391,6 +417,12 @@ export const unifiedBackendOutputSchema: z.ZodObject<{
391417
customOutputs: string;
392418
};
393419
} | undefined;
420+
"AWS::Amplify::Function"?: {
421+
version: "1";
422+
payload: {
423+
definedFunctions: string;
424+
};
425+
} | undefined;
394426
}, {
395427
"AWS::Amplify::Platform"?: {
396428
version: "1";
@@ -453,6 +485,12 @@ export const unifiedBackendOutputSchema: z.ZodObject<{
453485
customOutputs: string;
454486
};
455487
} | undefined;
488+
"AWS::Amplify::Function"?: {
489+
version: "1";
490+
payload: {
491+
definedFunctions: string;
492+
};
493+
} | undefined;
456494
}>;
457495

458496
// @public (undocumented)
@@ -609,6 +647,28 @@ export const versionedCustomOutputSchema: z.ZodDiscriminatedUnion<"version", [z.
609647
};
610648
}>]>;
611649

650+
// @public (undocumented)
651+
export const versionedFunctionOutputSchema: z.ZodDiscriminatedUnion<"version", [z.ZodObject<{
652+
version: z.ZodLiteral<"1">;
653+
payload: z.ZodObject<{
654+
definedFunctions: z.ZodString;
655+
}, "strip", z.ZodTypeAny, {
656+
definedFunctions: string;
657+
}, {
658+
definedFunctions: string;
659+
}>;
660+
}, "strip", z.ZodTypeAny, {
661+
version: "1";
662+
payload: {
663+
definedFunctions: string;
664+
};
665+
}, {
666+
version: "1";
667+
payload: {
668+
definedFunctions: string;
669+
};
670+
}>]>;
671+
612672
// @public (undocumented)
613673
export const versionedGraphqlOutputSchema: z.ZodDiscriminatedUnion<"version", [z.ZodObject<{
614674
version: z.ZodLiteral<"1">;
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { z } from 'zod';
2+
import { functionOutputSchema as functionOutputSchemaV1 } from './v1';
3+
4+
export const versionedFunctionOutputSchema = z.discriminatedUnion('version', [
5+
functionOutputSchemaV1,
6+
// this is where additional function major version schemas would go
7+
]);
8+
9+
export type FunctionOutput = z.infer<typeof versionedFunctionOutputSchema>;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { z } from 'zod';
2+
3+
export const functionOutputSchema = z.object({
4+
version: z.literal('1'),
5+
payload: z.object({
6+
definedFunctions: z.string(), // JSON array as string
7+
}),
8+
});

packages/backend-output-schemas/src/index.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { versionedGraphqlOutputSchema } from './graphql/index.js';
44
import { versionedStorageOutputSchema } from './storage/index.js';
55
import { versionedStackOutputSchema } from './stack/index.js';
66
import { versionedCustomOutputSchema } from './custom';
7+
import { versionedFunctionOutputSchema } from './function/index.js';
78

89
/**
910
* The auth, graphql and storage exports here are duplicated from the submodule exports in the package.json file
@@ -69,6 +70,20 @@ export * from './storage/index.js';
6970
*/
7071
export const storageOutputKey = 'AWS::Amplify::Storage';
7172

73+
/**
74+
* ---------- Function exports ----------
75+
*/
76+
77+
/**
78+
* re-export the function output schema
79+
*/
80+
export * from './function/index.js';
81+
82+
/**
83+
* Expected key that function output is stored under
84+
*/
85+
export const functionOutputKey = 'AWS::Amplify::Function';
86+
7287
/**
7388
* ---------- Unified exports ----------
7489
*/
@@ -83,6 +98,7 @@ export const unifiedBackendOutputSchema = z.object({
8398
[graphqlOutputKey]: versionedGraphqlOutputSchema.optional(),
8499
[storageOutputKey]: versionedStorageOutputSchema.optional(),
85100
[customOutputKey]: versionedCustomOutputSchema.optional(),
101+
[functionOutputKey]: versionedFunctionOutputSchema.optional(),
86102
});
87103
/**
88104
* This type is a subset of the BackendOutput type that is exposed by the platform.

0 commit comments

Comments
 (0)