UNPKG

@aws-amplify/amplify-category-api

Version:
170 lines (152 loc) 6.38 kB
import { App, CfnParameter, Stack } from 'aws-cdk-lib'; import { Construct } from 'constructs'; import type { AssetProvider, NestedStackProvider, S3Asset, AssetProps, SynthParameters, TransformParameterProvider, } from '@aws-amplify/graphql-transformer-interfaces'; import { DeploymentResources, Template } from './deployment-resources'; import { TransformerStackSythesizer } from './stack-synthesizer'; import { TransformerNestedStack } from './nested-stack'; import { TransformerRootStack } from './root-stack'; import { AmplifyApiGraphQlResourceStackTemplate } from './amplify-api-resource-stack-types'; import { AmplifyS3Asset } from './amplify-s3-asset'; export type OverrideConfig = { overrideFlag: boolean; applyOverride: (scope: Construct) => AmplifyApiGraphQlResourceStackTemplate; }; /** * Stack Manager plugin which supports the Amplify CLI transformer behavior today. Manages Transformer stacks, nested stacks, * and synthesizers, then provides mechanisms for synthesis. */ export class TransformManager { private readonly app: App = new App(); public readonly rootStack: TransformerRootStack; private readonly stackSynthesizer = new TransformerStackSythesizer(); private readonly childStackSynthesizers: Map<string, TransformerStackSythesizer> = new Map(); private synthParameters: SynthParameters; private paramMap: Map<string, CfnParameter>; constructor( private readonly overrideConfig: OverrideConfig | undefined, hasIamAuth: boolean, hasUserPoolAuth: boolean, adminRoles: string[], identityPoolId: string, ) { this.rootStack = new TransformerRootStack(this.app, 'transformer-root-stack', { synthesizer: this.stackSynthesizer, }); this.generateParameters(hasIamAuth, hasUserPoolAuth, adminRoles, identityPoolId); } getTransformScope(): Construct { return this.rootStack; } /** * Retrieve the nestedStackProvider for a Transformer Managed Stack */ getNestedStackProvider(): NestedStackProvider { return { provide: (scope: Construct, name: string): Stack => { const synthesizer = new TransformerStackSythesizer(); const newStack = new TransformerNestedStack(scope, name, { synthesizer, }); this.childStackSynthesizers.set(name, synthesizer); return newStack; }, }; } getAssetProvider(): AssetProvider { return { provide: (scope: Construct, id: string, props: AssetProps): S3Asset => new AmplifyS3Asset(scope, id, props), }; } private generateParameters(hasIamAuth: boolean, hasUserPoolAuth: boolean, adminRoles: string[], identityPoolId: string): void { this.paramMap = new Map(); const envParameter = new CfnParameter(this.rootStack, 'env', { default: 'NONE', type: 'String', }); this.paramMap.set('env', envParameter); const apiNameParameter = new CfnParameter(this.rootStack, 'AppSyncApiName', { default: 'AppSyncSimpleTransform', type: 'String', }); this.paramMap.set('AppSyncApiName', apiNameParameter); this.synthParameters = { amplifyEnvironmentName: envParameter.valueAsString, apiName: apiNameParameter.valueAsString, adminRoles, identityPoolId, }; if (hasIamAuth) { const authenticatedUserRoleNameParameter = new CfnParameter(this.rootStack, 'authRoleName', { type: 'String' }); this.synthParameters.authenticatedUserRoleName = authenticatedUserRoleNameParameter.valueAsString; this.paramMap.set('authRoleName', authenticatedUserRoleNameParameter); const unauthenticatedUserRoleNameParameter = new CfnParameter(this.rootStack, 'unauthRoleName', { type: 'String' }); this.synthParameters.unauthenticatedUserRoleName = unauthenticatedUserRoleNameParameter.valueAsString; this.paramMap.set('unauthRoleName', unauthenticatedUserRoleNameParameter); } if (hasUserPoolAuth) { const userPoolIdParameter = new CfnParameter(this.rootStack, 'AuthCognitoUserPoolId', { type: 'String' }); this.synthParameters.userPoolId = userPoolIdParameter.valueAsString; this.paramMap.set('AuthCognitoUserPoolId', userPoolIdParameter); } } getParameterProvider(): TransformParameterProvider { return { provide: (name: string): CfnParameter | void => this.paramMap.get(name), }; } getSynthParameters(): SynthParameters { return this.synthParameters; } generateDeploymentResources(): Omit<DeploymentResources, 'userOverriddenSlots'> { if (this.overrideConfig?.overrideFlag) { this.overrideConfig.applyOverride(this.rootStack); } this.app.synth({ force: true, skipValidation: true }); const templates = this.getCloudFormationTemplates(); const rootStackTemplate = templates.get('transformer-root-stack'); const childStacks: Record<string, Template> = {}; for (const [templateName, template] of templates.entries()) { if (templateName !== 'transformer-root-stack') { childStacks[templateName] = template; } } const fileAssets = this.getMappingTemplates(); const pipelineFunctions: Record<string, string> = {}; const resolvers: Record<string, string> = {}; const functions: Record<string, string> = {}; for (const [templateName, template] of fileAssets) { if (templateName.startsWith('pipelineFunctions/')) { pipelineFunctions[templateName.replace('pipelineFunctions/', '')] = template; } else if (templateName.startsWith('resolvers/')) { resolvers[templateName.replace('resolvers/', '')] = template; } else if (templateName.startsWith('functions/')) { functions[templateName.replace('functions/', '')] = template; } } const schema = fileAssets.get('schema.graphql') || ''; return { functions, pipelineFunctions, resolvers, schema, stacks: childStacks, rootStack: rootStackTemplate!, stackMapping: {}, }; } private getCloudFormationTemplates = (): Map<string, Template> => { let stacks = this.stackSynthesizer.collectStacks(); this.childStackSynthesizers.forEach((synthesizer) => { stacks = new Map([...stacks.entries(), ...synthesizer.collectStacks()]); }); return stacks; }; private getMappingTemplates = (): Map<string, string> => this.stackSynthesizer.collectMappingTemplates(); }