Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Introduce and enforce new stack structure #2158

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions packages/backend-ai/src/conversation/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
import path from 'path';
import { CallerDirectoryExtractor } from '@aws-amplify/platform-core';
import { AiModel } from '@aws-amplify/data-schema-types';
import { Stack } from 'aws-cdk-lib';

class ConversationHandlerFunctionGenerator
implements ConstructContainerEntryGenerator
Expand Down Expand Up @@ -72,11 +73,14 @@ class DefaultConversationHandlerFunctionFactory
private readonly callerStack: string | undefined
) {}

getInstance = ({
constructContainer,
outputStorageStrategy,
resourceNameValidator,
}: ConstructFactoryGetInstanceProps): ConversationHandlerFunction => {
getInstance = (
{
constructContainer,
outputStorageStrategy,
resourceNameValidator,
}: ConstructFactoryGetInstanceProps,
stack?: Stack
): ConversationHandlerFunction => {
resourceNameValidator?.validate(this.props.name);
if (!this.generator) {
const props = { ...this.props };
Expand All @@ -87,7 +91,8 @@ class DefaultConversationHandlerFunctionFactory
);
}
return constructContainer.getOrCompute(
this.generator
this.generator,
stack
) as ConversationHandlerFunction;
};

Expand Down
18 changes: 14 additions & 4 deletions packages/backend-auth/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,8 @@ export class AmplifyAuthFactory implements ConstructFactory<BackendAuth> {
* Get a singleton instance of AmplifyAuth
*/
getInstance = (
getInstanceProps: ConstructFactoryGetInstanceProps
getInstanceProps: ConstructFactoryGetInstanceProps,
stack?: Stack
): BackendAuth => {
const { constructContainer, importPathVerifier, resourceNameValidator } =
getInstanceProps;
Expand All @@ -111,9 +112,16 @@ export class AmplifyAuthFactory implements ConstructFactory<BackendAuth> {
resourceNameValidator?.validate(this.props.name);
}
if (!this.generator) {
this.generator = new AmplifyAuthGenerator(this.props, getInstanceProps);
this.generator = new AmplifyAuthGenerator(
this.props,
getInstanceProps,
stack
);
}
return constructContainer.getOrCompute(this.generator) as BackendAuth;
return constructContainer.getOrCompute(
this.generator,
stack
) as BackendAuth;
};
}

Expand All @@ -124,6 +132,7 @@ class AmplifyAuthGenerator implements ConstructContainerEntryGenerator {
constructor(
private readonly props: AmplifyAuthProps,
private readonly getInstanceProps: ConstructFactoryGetInstanceProps,
private readonly stack?: Stack,
private readonly authAccessBuilder = _authAccessBuilder,
private readonly authAccessPolicyArbiterFactory = new AuthAccessPolicyArbiterFactory()
) {
Expand Down Expand Up @@ -169,7 +178,8 @@ class AmplifyAuthGenerator implements ConstructContainerEntryGenerator {
([triggerEvent, handlerFactory]) => {
(authConstruct.resources.userPool as UserPool).addTrigger(
UserPoolOperation.of(triggerEvent),
handlerFactory.getInstance(this.getInstanceProps).resources.lambda
handlerFactory.getInstance(this.getInstanceProps, this.stack)
.resources.lambda
);
}
);
Expand Down
12 changes: 9 additions & 3 deletions packages/backend-data/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
CDKContextKey,
TagName,
} from '@aws-amplify/platform-core';
import { Aspects, IAspect, Tags } from 'aws-cdk-lib';
import { Aspects, IAspect, Stack, Tags } from 'aws-cdk-lib';
import { convertJsResolverDefinition } from './convert_js_resolvers.js';
import { AppSyncPolicyGenerator } from './app_sync_policy_generator.js';
import {
Expand Down Expand Up @@ -77,7 +77,10 @@ export class DataFactory implements ConstructFactory<AmplifyData> {
/**
* Gets an instance of the Data construct
*/
getInstance = (props: ConstructFactoryGetInstanceProps): AmplifyData => {
getInstance = (
props: ConstructFactoryGetInstanceProps,
stack?: Stack
): AmplifyData => {
const {
constructContainer,
outputStorageStrategy,
Expand Down Expand Up @@ -106,7 +109,10 @@ export class DataFactory implements ConstructFactory<AmplifyData> {
outputStorageStrategy
);
}
return constructContainer.getOrCompute(this.generator) as AmplifyData;
return constructContainer.getOrCompute(
this.generator,
stack
) as AmplifyData;
};
}

Expand Down
18 changes: 12 additions & 6 deletions packages/backend-function/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,18 +177,24 @@ class FunctionFactory implements ConstructFactory<AmplifyFunction> {
/**
* Creates an instance of AmplifyFunction within the provided Amplify context
*/
getInstance = ({
constructContainer,
outputStorageStrategy,
resourceNameValidator,
}: ConstructFactoryGetInstanceProps): AmplifyFunction => {
getInstance = (
{
constructContainer,
outputStorageStrategy,
resourceNameValidator,
}: ConstructFactoryGetInstanceProps,
stack?: Stack
): AmplifyFunction => {
if (!this.generator) {
this.generator = new FunctionGenerator(
this.hydrateDefaults(resourceNameValidator),
outputStorageStrategy
);
}
return constructContainer.getOrCompute(this.generator) as AmplifyFunction;
return constructContainer.getOrCompute(
this.generator,
stack
) as AmplifyFunction;
};

private hydrateDefaults = (
Expand Down
6 changes: 4 additions & 2 deletions packages/backend-storage/src/factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export class AmplifyStorageFactory
* Get a singleton instance of the Bucket
*/
getInstance = (
getInstanceProps: ConstructFactoryGetInstanceProps
getInstanceProps: ConstructFactoryGetInstanceProps,
stack?: Stack
): AmplifyStorage => {
const { constructContainer, importPathVerifier, resourceNameValidator } =
getInstanceProps;
Expand All @@ -50,7 +51,8 @@ export class AmplifyStorageFactory
);
}
const amplifyStorage = constructContainer.getOrCompute(
this.generator
this.generator,
stack
) as AmplifyStorage;

/*
Expand Down
21 changes: 19 additions & 2 deletions packages/backend/API.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,16 @@ import { Stack } from 'aws-cdk-lib';

export { a }

// @public (undocumented)
export type AmplifyStackBase = {
readonly stack: Stack;
};

// @public (undocumented)
export type AmplifyStackResources = AmplifyStackBase & {
[K in keyof DefineStackProps]: Omit<ReturnType<DefineStackProps[K]['getInstance']>, keyof ResourceAccessAcceptorFactory>;
};

export { AuthCfnResources }

export { AuthResources }
Expand All @@ -47,7 +57,6 @@ export type Backend<T extends DefineBackendProps> = BackendBase & {

// @public (undocumented)
export type BackendBase = {
createStack: (name: string) => Stack;
addOutput: (clientConfigPart: DeepPartialAmplifyGeneratedConfigs<ClientConfig>) => void;
stack: Stack;
};
Expand All @@ -74,14 +83,22 @@ export { defineAuth }
export const defineBackend: <T extends DefineBackendProps>(constructFactories: T) => Backend<T>;

// @public (undocumented)
export type DefineBackendProps = Record<string, ConstructFactory<ResourceProvider & Partial<ResourceAccessAcceptorFactory<never>>>> & {
export type DefineBackendProps = Record<string, ConstructFactory<ResourceProvider<AmplifyStackResources>>> & {
[K in keyof BackendBase]?: never;
};

export { defineData }

export { defineFunction }

// @public
export const defineStack: (name: string, constructFactories: DefineStackProps) => ConstructFactory<ResourceProvider<AmplifyStackResources>>;

// @public (undocumented)
export type DefineStackProps = Record<string, ConstructFactory<ResourceProvider & Partial<ResourceAccessAcceptorFactory<never>>>> & {
[K in keyof AmplifyStackBase]?: never;
};

export { defineStorage }

export { FunctionResources }
Expand Down
6 changes: 2 additions & 4 deletions packages/backend/src/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@
} from '@aws-amplify/plugin-types';
import { Stack } from 'aws-cdk-lib';
import { ClientConfig } from '@aws-amplify/client-config';
import { AmplifyStackResources } from './stack_factory.js';

export type BackendBase = {
createStack: (name: string) => Stack;
addOutput: (
clientConfigPart: DeepPartialAmplifyGeneratedConfigs<ClientConfig>
) => void;
Expand All @@ -18,9 +18,7 @@
// Type that allows construct factories to be defined using any keys except those used in BackendHelpers
export type DefineBackendProps = Record<
string,
ConstructFactory<
ResourceProvider & Partial<ResourceAccessAcceptorFactory<never>>
>
ConstructFactory<ResourceProvider<AmplifyStackResources>>

Check failure on line 21 in packages/backend/src/backend.ts

View workflow job for this annotation

GitHub Actions / build (20)

Generic type 'AmplifyStackResources' requires 1 type argument(s).

Check failure on line 21 in packages/backend/src/backend.ts

View workflow job for this annotation

GitHub Actions / test_with_baseline_dependencies

Generic type 'AmplifyStackResources' requires 1 type argument(s).
> & { [K in keyof BackendBase]?: never };

/**
Expand Down
16 changes: 0 additions & 16 deletions packages/backend/src/backend_factory.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,22 +175,6 @@ void describe('Backend', () => {
rootStackTemplate.resourceCountIs('Custom::AmplifyBranchLinkerResource', 0);
});

void describe('createStack', () => {
void it('returns nested stack', () => {
const backend = new BackendFactory({}, rootStack);
const testStack = backend.createStack('testStack');
assert.strictEqual(rootStack.node.findChild('testStack'), testStack);
});

void it('throws if stack has already been created with specified name', () => {
const backend = new BackendFactory({}, rootStack);
backend.createStack('testStack');
assert.throws(() => backend.createStack('testStack'), {
message: 'Custom stack named testStack has already been created',
});
});
});

void it('can add custom output', () => {
const rootStack = createStackAndSetContext('sandbox');
const backend = new BackendFactory({}, rootStack);
Expand Down
9 changes: 0 additions & 9 deletions packages/backend/src/backend_factory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,14 +127,6 @@ export class BackendFactory<
);
}

/**
* Returns a CDK stack within the Amplify project that can be used for creating custom resources.
* If a stack has already been created with "name" then an error is thrown.
*/
createStack = (name: string): Stack => {
return this.stackResolver.createCustomStack(name);
};

addOutput = (
clientConfigPart: DeepPartialAmplifyGeneratedConfigs<ClientConfig>
) => {
Expand All @@ -157,7 +149,6 @@ export const defineBackend = <T extends DefineBackendProps>(
const backend = new BackendFactory(constructFactories);
return {
...backend.resources,
createStack: backend.createStack,
addOutput: backend.addOutput,
stack: backend.stack,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { getBackendIdentifier } from '../backend_identifier.js';
import { DefaultBackendSecretResolver } from './backend-secret/backend_secret_resolver.js';
import { BackendIdScopedSsmEnvironmentEntriesGenerator } from './backend_id_scoped_ssm_environment_entries_generator.js';
import { BackendIdScopedStableBackendIdentifiers } from '../backend_id_scoped_stable_backend_identifiers.js';
import { Stack } from 'aws-cdk-lib';

/**
* Serves as a DI container and shared state store for initializing Amplify constructs
Expand All @@ -33,10 +34,13 @@ export class SingletonConstructContainer implements ConstructContainer {
* Otherwise, the generator is called and the value is cached and returned
*/
getOrCompute = (
generator: ConstructContainerEntryGenerator
generator: ConstructContainerEntryGenerator,
scope?: Stack
): ResourceProvider => {
if (!this.providerCache.has(generator)) {
const scope = this.stackResolver.getStackFor(generator.resourceGroupName);
if (!scope) {
scope = this.stackResolver.getStackFor(generator.resourceGroupName);
}
const backendId = getBackendIdentifier(scope);
const ssmEnvironmentEntriesGenerator =
new BackendIdScopedSsmEnvironmentEntriesGenerator(scope, backendId);
Expand Down
3 changes: 3 additions & 0 deletions packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,6 @@ export { defineStorage } from '@aws-amplify/backend-storage';

// function
export { defineFunction } from '@aws-amplify/backend-function';

// stack
export * from './stack_factory.js';
Loading
Loading