Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,8 @@ export class BackendSynthesizer {
const defineBackendProperties = [];
const nodes = [];

// Gen 2 requires different names / casing for password rules

const mappedPolicyType: Record<string, string> = {
MinimumLength: 'minimumLength',
RequireUppercase: 'requireUppercase',
Expand All @@ -704,30 +706,46 @@ export class BackendSynthesizer {
TemporaryPasswordValidityDays: 'temporaryPasswordValidityDays',
};

// What it does: If you have auth, storage, or custom resources, adds:
// import { RemovalPolicy, Tags } from 'aws-cdk-lib';

if (renderArgs.auth || renderArgs.storage?.hasS3Bucket || renderArgs.customResources) {
imports.push(
this.createImportStatement([factory.createIdentifier('RemovalPolicy'), factory.createIdentifier('Tags')], 'aws-cdk-lib'),
);
}

// What it does: If you have auth configured:
// Adds import: import { auth } from './auth/resource';
// Adds auth to the backend definition

if (renderArgs.auth) {
imports.push(this.createImportStatement([authFunctionIdentifier], renderArgs.auth.importFrom));
const auth = factory.createShorthandPropertyAssignment(authFunctionIdentifier);
defineBackendProperties.push(auth);
}

// Same as auth

if (renderArgs.data) {
imports.push(this.createImportStatement([dataFunctionIdentifier], renderArgs.data.importFrom));
const data = factory.createShorthandPropertyAssignment(dataFunctionIdentifier);
defineBackendProperties.push(data);
}

// Same as auth

if (renderArgs.storage?.hasS3Bucket) {
imports.push(this.createImportStatement([storageFunctionIdentifier], renderArgs.storage.importFrom));
const storage = factory.createShorthandPropertyAssignment(storageFunctionIdentifier);
defineBackendProperties.push(storage);
}

// Context: Gen 1 might have multiple Lambda functions
// What it does: For each function (e.g., myFunction):
// Adds import: import { myFunction } from './function/myFunction/resource';
// Adds function to backend: defineBackend({ auth, myFunction, ... })

if (renderArgs.function) {
const functionNameCategories = renderArgs.function.functionNamesAndCategories;
for (const [functionName, category] of functionNameCategories) {
Expand All @@ -737,6 +755,8 @@ export class BackendSynthesizer {
}
}

// Dynamo table cannot be migrated

if (renderArgs.storage?.dynamoDB) {
nodes.push(
factory.createThrowStatement(
Expand All @@ -749,6 +769,8 @@ export class BackendSynthesizer {
);
}

// Adds core import: import { defineBackend } from '@aws-amplify/backend';

imports.push(this.createImportStatement([backendFunctionIdentifier], '@aws-amplify/backend'));

if (renderArgs.unsupportedCategories) {
Expand Down Expand Up @@ -797,24 +819,33 @@ export class BackendSynthesizer {
}
}

// Adds CI detection: import ci from 'ci-info';

const ciInfoImportStatement = factory.createImportDeclaration(
undefined,
factory.createImportClause(false, factory.createIdentifier('ci'), undefined),
factory.createStringLiteral('ci-info'),
);

// Creates environment name logic (sandbox vs production)

imports.push(ciInfoImportStatement);
const envNameStatements = this.createAmplifyEnvNameLogic();
errors.push(...envNameStatements);

// Creates the main line: const backend = defineBackend({ auth, data, storage })

const callBackendFn = this.defineBackendCall(backendFunctionIdentifier, defineBackendProperties);
const backendVariable = factory.createVariableDeclaration('backend', undefined, undefined, callBackendFn);
const backendStatement = factory.createVariableStatement(
[],
factory.createVariableDeclarationList([backendVariable], ts.NodeFlags.Const),
);

// CDK OVERRIDES
// When you have advanced user pool settings AND you're creating new auth (not importing existing)
if (renderArgs.auth?.userPoolOverrides && !renderArgs?.auth?.referenceAuth) {
// Generates const cfnUserPool = backend.auth.resources.cfnResources.cfnUserPool;
const cfnUserPoolVariableStatement = this.createVariableStatement(
this.createVariableDeclaration('cfnUserPool', 'auth.resources.cfnResources.cfnUserPool'),
);
Expand All @@ -823,6 +854,10 @@ export class BackendSynthesizer {
passwordPolicy: {},
};
for (const [overridePath, value] of Object.entries(renderArgs.auth.userPoolOverrides)) {
// Gen 1 name: myapp-dev
// Splits it: ['myapp', 'dev']
// Takes base: myapp
// Generates: cfnUserPool.userPoolName = \myapp-${AMPLIFY_GEN_1_ENV_NAME}`;`
if (overridePath.includes('userPoolName')) {
assert(value);
assert(typeof value === 'string');
Expand All @@ -838,15 +873,25 @@ export class BackendSynthesizer {
);

nodes.push(userPoolAssignment);
// Input: Policies.PasswordPolicy.MinimumLength = 8
// Splits: ['Policies', 'PasswordPolicy', 'MinimumLength']
// Gets: MinimumLength
// Maps to: minimumLength
// Stores: policies.passwordPolicy.minimumLength = 8
} else if (overridePath.includes('PasswordPolicy')) {
const policyKey = overridePath.split('.')[2];
if (value !== undefined && policyKey in mappedPolicyType) {
policies.passwordPolicy[mappedPolicyType[policyKey] as string] = value;
}
} else {
// Handle everything else
// This is where username attributes get handled!
// Input: usernameAttributes: ['username']
// Generates: cfnUserPool.usernameAttributes = ['username'];
nodes.push(this.setPropertyValue(factory.createIdentifier('cfnUserPool'), overridePath, value));
}
}
// Generates: cfnUserPool.policies = { passwordPolicy: { minimumLength: 8 } };
nodes.push(
this.setPropertyValue(
factory.createIdentifier('cfnUserPool'),
Expand All @@ -856,6 +901,7 @@ export class BackendSynthesizer {
);
}

// Identity pool overrides
if (renderArgs.auth?.guestLogin === false || (renderArgs.auth?.identityPoolName && !renderArgs?.auth?.referenceAuth)) {
const cfnIdentityPoolVariableStatement = this.createVariableStatement(
this.createVariableDeclaration('cfnIdentityPool', 'auth.resources.cfnResources.cfnIdentityPool'),
Expand All @@ -880,6 +926,7 @@ export class BackendSynthesizer {
}
}

// User pool client overrides
if (
(renderArgs.auth?.oAuthFlows || renderArgs.auth?.readAttributes || renderArgs.auth?.writeAttributes) &&
!renderArgs?.auth?.referenceAuth
Expand Down Expand Up @@ -920,12 +967,17 @@ export class BackendSynthesizer {
}

// Since Gen2 only supports 1 user pool client by default, we need to add CDK overrides for the additional user pool client from Gen1
// If Gen 1 had separate mobile and web clients, Gen 2 needs to recreate that setup.
if (renderArgs.auth?.userPoolClient) {
const userPoolVariableStatement = this.createVariableStatement(this.createVariableDeclaration('userPool', 'auth.resources.userPool'));
nodes.push(userPoolVariableStatement);
nodes.push(this.createUserPoolClientAssignment(renderArgs.auth?.userPoolClient, imports));
}

// Stores basic S3 bucket info
// const s3Bucket = backend.storage.resources.cfnResources.cfnBucket;
// s3Bucket.bucketName = `myapp-storage-${AMPLIFY_GEN_1_ENV_NAME}`;

if (renderArgs.storage && renderArgs.storage.hasS3Bucket) {
assert(renderArgs.storage.bucketName);
const cfnStorageVariableStatement = this.createVariableStatement(
Expand All @@ -946,6 +998,7 @@ export class BackendSynthesizer {
nodes.push(bucketNameAssignment);
}

// Features that Gen1 just doesn't support for storage
if (
renderArgs.storage?.accelerateConfiguration ||
renderArgs.storage?.versionConfiguration ||
Expand Down Expand Up @@ -1019,6 +1072,7 @@ export class BackendSynthesizer {
);
}

// I DONT UNDERSTAND THIS PART YET
if (
renderArgs.auth?.userPoolClient &&
renderArgs.auth.userPoolClient.SupportedIdentityProviders &&
Expand Down Expand Up @@ -1064,6 +1118,7 @@ export class BackendSynthesizer {
nodes.push(tagAssignment);
}

// returns backend.ts file
return factory.createNodeArray([...imports, newLineIdentifier, ...errors, newLineIdentifier, backendStatement, ...nodes], true);
}
}
Loading
Loading