@aws-amplify/amplify-category-api
Version:
Amplify CLI API Category Plugin
287 lines • 16.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadCustomTransformersV2 = exports.suppressApiKeyGeneration = exports.generateTransformerOptions = exports.APPSYNC_RESOURCE_SERVICE = void 0;
const path_1 = __importDefault(require("path"));
const amplify_cli_core_1 = require("@aws-amplify/amplify-cli-core");
const graphql_transformer_core_1 = require("@aws-amplify/graphql-transformer-core");
const graphql_transformer_core_2 = require("graphql-transformer-core");
const fs_extra_1 = __importDefault(require("fs-extra"));
const graphql_transformer_common_1 = require("graphql-transformer-common");
const lodash_1 = __importDefault(require("lodash"));
const amplify_prompts_1 = require("@aws-amplify/amplify-prompts");
const context_util_1 = require("../category-utils/context-util");
const searchable_node_to_node_encryption_1 = require("../provider-utils/awscloudformation/current-backend-state/searchable-node-to-node-encryption");
const sandbox_mode_helpers_1 = require("./sandbox-mode-helpers");
const transformer_factory_1 = require("./transformer-factory");
const amplify_cli_feature_flag_adapter_1 = require("./amplify-cli-feature-flag-adapter");
const constants_1 = require("./constants");
const api_utils_1 = require("./api-utils");
const user_defined_slots_1 = require("./user-defined-slots");
const override_1 = require("./override");
exports.APPSYNC_RESOURCE_SERVICE = 'AppSync';
const warnOnAuth = (map, docLink) => {
const unAuthModelTypes = Object.keys(map).filter((type) => !map[type].includes('auth') && map[type].includes('model'));
if (unAuthModelTypes.length) {
amplify_prompts_1.printer.info(`
⚠️ WARNING: Some types do not have authorization rules configured. That means all create, read, update, and delete operations are denied on these types:`, 'yellow');
amplify_prompts_1.printer.info(unAuthModelTypes.map((type) => `\t - ${type}`).join('\n'), 'yellow');
amplify_prompts_1.printer.info(`Learn more about "@auth" authorization rules here: ${docLink}`, 'yellow');
}
};
const generateTransformerOptions = async (context, options) => {
var _a, _b, _c, _d;
let resourceName;
const backEndDir = amplify_cli_core_1.pathManager.getBackendDirPath();
const flags = context.parameters.options;
if (flags['no-gql-override']) {
return undefined;
}
let { parameters } = options;
const { forceCompile } = options;
const { resourcesToBeCreated, resourcesToBeUpdated, allResources } = await context.amplify.getResourceStatus(amplify_cli_core_1.AmplifyCategories.API);
let resources = resourcesToBeCreated.concat(resourcesToBeUpdated);
const resourceNeedCompile = allResources
.filter((r) => !resources.includes(r))
.filter((r) => {
const buildDir = path_1.default.normalize(path_1.default.join(backEndDir, amplify_cli_core_1.AmplifyCategories.API, r.resourceName, 'build'));
return !fs_extra_1.default.existsSync(buildDir);
});
resources = resources.concat(resourceNeedCompile);
if (forceCompile) {
resources = resources.concat(allResources);
}
resources = resources.filter((resource) => resource.service === exports.APPSYNC_RESOURCE_SERVICE);
const resourceDir = await context_util_1.contextUtil.getResourceDir(context, options);
let previouslyDeployedBackendDir = options.cloudBackendDirectory;
if (!previouslyDeployedBackendDir) {
if (resources.length > 0) {
const resource = resources[0];
if (resource.providerPlugin !== constants_1.PROVIDER_NAME) {
return undefined;
}
const { category } = resource;
resourceName = resource.resourceName;
const cloudBackendRootDir = amplify_cli_core_1.pathManager.getCurrentCloudBackendDirPath();
previouslyDeployedBackendDir = path_1.default.normalize(path_1.default.join(cloudBackendRootDir, category, resourceName));
}
}
const parametersFilePath = path_1.default.join(resourceDir, constants_1.PARAMETERS_FILENAME);
if (!parameters && fs_extra_1.default.existsSync(parametersFilePath)) {
try {
parameters = amplify_cli_core_1.JSONUtilities.readJson(parametersFilePath);
if (parameters[graphql_transformer_common_1.ResourceConstants.PARAMETERS.OpenSearchInstanceType]) {
parameters[graphql_transformer_common_1.ResourceConstants.PARAMETERS.OpenSearchInstanceType] = parameters[graphql_transformer_common_1.ResourceConstants.PARAMETERS.OpenSearchInstanceType].replace('.search', '.elasticsearch');
}
}
catch (e) {
parameters = {};
}
}
let { authConfig } = options;
if (lodash_1.default.isEmpty(authConfig) && !lodash_1.default.isEmpty(resources)) {
authConfig = await context.amplify.invokePluginMethod(context, amplify_cli_core_1.AmplifyCategories.API, amplify_cli_core_1.AmplifySupportedService.APPSYNC, 'getAuthConfig', [context, resources[0].resourceName]);
if (lodash_1.default.isEmpty(authConfig)) {
if (resources[0].output.securityType) {
authConfig = {
defaultAuthentication: {
authenticationType: resources[0].output.securityType,
},
additionalAuthenticationProviders: [],
};
}
else {
({ authConfig } = resources[0].output);
}
}
}
const s3Resource = s3ResourceAlreadyExists();
const storageConfig = s3Resource ? getBucketName(s3Resource) : undefined;
let deploymentRootKey = await getPreviousDeploymentRootKey(previouslyDeployedBackendDir);
if (!deploymentRootKey) {
const deploymentSubKey = await amplify_cli_core_1.CloudformationProviderFacade.hashDirectory(context, resourceDir);
deploymentRootKey = `${constants_1.ROOT_APPSYNC_S3_KEY}/${deploymentSubKey}`;
}
const projectBucket = options.dryRun ? 'fake-bucket' : getProjectBucket();
const buildParameters = {
...parameters,
S3DeploymentBucket: projectBucket,
S3DeploymentRootKey: deploymentRootKey,
};
const project = await (0, graphql_transformer_core_2.loadProject)(resourceDir);
const lastDeployedProjectConfig = fs_extra_1.default.existsSync(previouslyDeployedBackendDir)
? await (0, graphql_transformer_core_2.loadProject)(previouslyDeployedBackendDir)
: undefined;
const docLink = (0, amplify_cli_core_1.getGraphQLTransformerAuthDocLink)(2);
const sandboxModeEnabled = (0, sandbox_mode_helpers_1.schemaHasSandboxModeEnabled)(project.schema, docLink);
const directiveMap = (0, graphql_transformer_core_1.collectDirectivesByTypeNames)(project.schema);
const hasApiKey = authConfig.defaultAuthentication.authenticationType === 'API_KEY' ||
authConfig.additionalAuthenticationProviders.some((authProvider) => authProvider.authenticationType === 'API_KEY');
const showSandboxModeMessage = sandboxModeEnabled && hasApiKey;
await (0, api_utils_1.searchablePushChecks)(context, directiveMap.types, parameters[graphql_transformer_common_1.ResourceConstants.PARAMETERS.AppSyncApiName]);
if (sandboxModeEnabled && options.promptApiKeyCreation) {
const apiKeyConfig = await (0, sandbox_mode_helpers_1.showSandboxModePrompts)(context);
if (apiKeyConfig)
authConfig.additionalAuthenticationProviders.push(apiKeyConfig);
}
if (showSandboxModeMessage) {
(0, sandbox_mode_helpers_1.showGlobalSandboxModeWarning)(docLink);
}
else {
warnOnAuth(directiveMap.types, docLink);
}
const ff = new amplify_cli_feature_flag_adapter_1.AmplifyCLIFeatureFlagAdapter();
const isNewAppSyncAPI = resourcesToBeCreated.some((resource) => resource.service === 'AppSync');
const allowDestructiveUpdates = ((_b = (_a = context === null || context === void 0 ? void 0 : context.input) === null || _a === void 0 ? void 0 : _a.options) === null || _b === void 0 ? void 0 : _b[constants_1.DESTRUCTIVE_UPDATES_FLAG]) || ((_d = (_c = context === null || context === void 0 ? void 0 : context.input) === null || _c === void 0 ? void 0 : _c.options) === null || _d === void 0 ? void 0 : _d.force);
const sanityCheckRules = (0, graphql_transformer_core_2.getSanityCheckRules)(isNewAppSyncAPI, ff, allowDestructiveUpdates);
let resolverConfig = {};
if (!lodash_1.default.isEmpty(resources)) {
resolverConfig = await context.amplify.invokePluginMethod(context, amplify_cli_core_1.AmplifyCategories.API, amplify_cli_core_1.AmplifySupportedService.APPSYNC, 'getResolverConfig', [context, resources[0].resourceName]);
}
if (lodash_1.default.isEmpty(resolverConfig)) {
resolverConfig = project.config.ResolverConfig;
}
const resourceDirParts = resourceDir.split(path_1.default.sep);
const apiName = resourceDirParts[resourceDirParts.length - 1];
const userDefinedSlots = {
...(0, user_defined_slots_1.parseUserDefinedSlots)(project.pipelineFunctions),
...(0, user_defined_slots_1.parseUserDefinedSlots)(project.resolvers),
};
const overrideConfig = {
applyOverride: (scope) => (0, override_1.applyFileBasedOverride)(scope),
...options.overrideConfig,
};
return {
...options,
resourceName,
buildParameters,
projectDirectory: resourceDir,
transformersFactoryArgs: {
storageConfig,
customTransformers: await (0, exports.loadCustomTransformersV2)(resourceDir),
},
rootStackFileName: 'cloudformation-template.json',
currentCloudBackendDirectory: previouslyDeployedBackendDir,
projectConfig: project,
lastDeployedProjectConfig,
authConfig,
sandboxModeEnabled,
sanityCheckRules,
resolverConfig,
userDefinedSlots,
overrideConfig,
stacks: project.stacks,
stackMapping: project.config.StackMapping,
transformParameters: generateTransformParameters(apiName, parameters, project.config, sandboxModeEnabled),
};
};
exports.generateTransformerOptions = generateTransformerOptions;
const generateTransformParameters = (apiName, parameters, projectConfig, sandboxModeEnabled) => {
var _a;
const featureFlagProvider = new amplify_cli_feature_flag_adapter_1.AmplifyCLIFeatureFlagAdapter();
return {
shouldDeepMergeDirectiveConfigDefaults: featureFlagProvider.getBoolean('shouldDeepMergeDirectiveConfigDefaults'),
useSubUsernameForDefaultIdentityClaim: featureFlagProvider.getBoolean('useSubUsernameForDefaultIdentityClaim'),
populateOwnerFieldForStaticGroupAuth: featureFlagProvider.getBoolean('populateOwnerFieldForStaticGroupAuth'),
secondaryKeyAsGSI: featureFlagProvider.getBoolean('secondaryKeyAsGSI'),
enableAutoIndexQueryNames: featureFlagProvider.getBoolean('enableAutoIndexQueryNames'),
respectPrimaryKeyAttributesOnConnectionField: featureFlagProvider.getBoolean('respectPrimaryKeyAttributesOnConnectionField'),
subscriptionsInheritPrimaryAuth: featureFlagProvider.getBoolean('subscriptionsInheritPrimaryAuth'),
suppressApiKeyGeneration: (0, exports.suppressApiKeyGeneration)(parameters),
disableResolverDeduping: (_a = projectConfig.DisableResolverDeduping) !== null && _a !== void 0 ? _a : false,
enableSearchNodeToNodeEncryption: (0, searchable_node_to_node_encryption_1.shouldEnableNodeToNodeEncryption)(apiName, amplify_cli_core_1.pathManager.findProjectRoot(), amplify_cli_core_1.pathManager.getCurrentCloudBackendDirPath()),
sandboxModeEnabled,
enableTransformerCfnOutputs: true,
allowDestructiveGraphqlSchemaUpdates: false,
replaceTableUponGsiUpdate: false,
allowGen1Patterns: true,
enableGen2Migration: featureFlagProvider.getBoolean('enableGen2Migration'),
};
};
const suppressApiKeyGeneration = (parameters) => {
if (!('CreateAPIKey' in parameters)) {
return false;
}
return parameters.CreateAPIKey !== 1 && parameters.CreateAPIKey !== '1';
};
exports.suppressApiKeyGeneration = suppressApiKeyGeneration;
const loadCustomTransformersV2 = async (resourceDir) => {
var _a;
const customTransformersConfig = await (0, graphql_transformer_core_2.loadProject)(resourceDir);
const customTransformerList = (_a = customTransformersConfig === null || customTransformersConfig === void 0 ? void 0 : customTransformersConfig.config) === null || _a === void 0 ? void 0 : _a.transformers;
return (Array.isArray(customTransformerList) ? customTransformerList : [])
.map(transformer_factory_1.importTransformerModule)
.map((imported) => {
const CustomTransformer = imported.default;
if (typeof CustomTransformer === 'function') {
return new CustomTransformer();
}
if (typeof CustomTransformer === 'object') {
throw new Error("Custom Transformers' should implement TransformerProvider interface");
}
throw new Error("Custom Transformers' default export must be a function or an object");
})
.filter((customTransformer) => customTransformer);
};
exports.loadCustomTransformersV2 = loadCustomTransformersV2;
const getBucketName = (s3ResourceName) => {
const amplifyMeta = amplify_cli_core_1.stateManager.getMeta();
const stackName = amplifyMeta.providers.awscloudformation.StackName;
const s3ResourcePath = amplify_cli_core_1.pathManager.getResourceDirectoryPath(undefined, amplify_cli_core_1.AmplifyCategories.STORAGE, s3ResourceName);
const cliInputsPath = path_1.default.join(s3ResourcePath, 'cli-inputs.json');
let bucketParameters;
if (fs_extra_1.default.existsSync(cliInputsPath)) {
bucketParameters = amplify_cli_core_1.JSONUtilities.readJson(cliInputsPath);
}
else {
bucketParameters = amplify_cli_core_1.stateManager.getResourceParametersJson(undefined, amplify_cli_core_1.AmplifyCategories.STORAGE, s3ResourceName);
}
const bucketName = stackName.startsWith('amplify-')
? `${bucketParameters.bucketName}\${hash}-\${env}`
: `${bucketParameters.bucketName}${s3ResourceName}-\${env}`;
return { bucketName };
};
const getPreviousDeploymentRootKey = async (previouslyDeployedBackendDir) => {
let parameters;
try {
const parametersPath = path_1.default.join(previouslyDeployedBackendDir, `build/${constants_1.PARAMETERS_FILENAME}`);
const parametersExists = fs_extra_1.default.existsSync(parametersPath);
if (parametersExists) {
const parametersString = await fs_extra_1.default.readFile(parametersPath);
parameters = JSON.parse(parametersString.toString());
}
return parameters.S3DeploymentRootKey;
}
catch (err) {
return undefined;
}
};
const getProjectBucket = () => {
const meta = amplify_cli_core_1.stateManager.getMeta(undefined, { throwIfNotExist: false });
const projectBucket = (meta === null || meta === void 0 ? void 0 : meta.providers) ? meta.providers[constants_1.PROVIDER_NAME].DeploymentBucketName : '';
return projectBucket;
};
const s3ResourceAlreadyExists = () => {
try {
let resourceName;
const amplifyMeta = amplify_cli_core_1.stateManager.getMeta(undefined, { throwIfNotExist: false });
if (amplifyMeta === null || amplifyMeta === void 0 ? void 0 : amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE]) {
const categoryResources = amplifyMeta[amplify_cli_core_1.AmplifyCategories.STORAGE];
Object.keys(categoryResources).forEach((resource) => {
if (categoryResources[resource].service === amplify_cli_core_1.AmplifySupportedService.S3) {
resourceName = resource;
}
});
}
return resourceName;
}
catch (error) {
if (error.name === 'UndeterminedEnvironmentError') {
return undefined;
}
throw error;
}
};
//# sourceMappingURL=transformer-options-v2.js.map