@aws-amplify/cli-internal
Version:
Amplify CLI
229 lines • 12.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Gen1App = exports.KNOWN_FEATURES = exports.KNOWN_RESOURCE_KEYS = void 0;
const node_path_1 = __importDefault(require("node:path"));
const node_os_1 = __importDefault(require("node:os"));
const promises_1 = __importDefault(require("node:fs/promises"));
const node_fs_1 = require("node:fs");
const unzipper_1 = __importDefault(require("unzipper"));
const client_s3_1 = require("@aws-sdk/client-s3");
const amplify_cli_core_1 = require("@aws-amplify/amplify-cli-core");
const aws_clients_1 = require("./aws-clients");
const aws_fetcher_1 = require("./aws-fetcher");
const amplify_cli_core_2 = require("@aws-amplify/amplify-cli-core");
const client_amplify_1 = require("@aws-sdk/client-amplify");
const resource_types_1 = require("./resource-types");
exports.KNOWN_RESOURCE_KEYS = [
'auth:Cognito',
'auth:Cognito-UserPool-Groups',
'storage:S3',
'storage:DynamoDB',
'api:AppSync',
'api:API Gateway',
'analytics:Kinesis',
'function:Lambda',
'geo:Map',
'geo:PlaceIndex',
'geo:GeofenceCollection',
'custom:customCDK',
];
var KNOWN_FEATURES;
(function (KNOWN_FEATURES) {
KNOWN_FEATURES["OVERRIDES"] = "overrides";
KNOWN_FEATURES["CUSTOM_FUNCTION_POLICIES"] = "custom-policies";
KNOWN_FEATURES["CONFLICT_RESOLUTION"] = "conflict-resolution";
})(KNOWN_FEATURES = exports.KNOWN_FEATURES || (exports.KNOWN_FEATURES = {}));
class Gen1App {
constructor(props) {
this.appId = props.app.appId;
this.appName = props.app.name;
this.envName = props.envName;
this.clients = props.clients;
this.ccbDir = props.ccbDir;
this.aws = new aws_fetcher_1.AwsFetcher(this.clients);
this._meta = amplify_cli_core_1.JSONUtilities.readJson(node_path_1.default.join(this.ccbDir, 'amplify-meta.json'), { throwIfNotExist: true });
this.rootStackName = this._meta.providers.awscloudformation.StackName;
this.deploymentBucket = this._meta.providers.awscloudformation.DeploymentBucketName;
this.region = this._meta.providers.awscloudformation.Region;
this.statefulResourceTypes = [...Array.from(resource_types_1.DEFAULT_STATEFUL_RESOURCES)];
if (props.additionalStatefulResourceTypes) {
this.statefulResourceTypes.push(...props.additionalStatefulResourceTypes);
}
}
static async create(context, additionalStatefulResourceTypesPath) {
const clients = await aws_clients_1.AwsClients.create(context);
const tpiRelPath = `./${node_path_1.default.relative(process.cwd(), amplify_cli_core_2.pathManager.getTeamProviderInfoFilePath())}`;
if (!amplify_cli_core_2.stateManager.teamProviderInfoExists()) {
throw new amplify_cli_core_1.AmplifyError('TeamProviderInfoNotFoundError', {
message: `Unable to find '${tpiRelPath}' - Are you sure you're on the right branch?`,
resolution: 'Checkout to the Gen1 branch and rerun the command',
});
}
const tpi = amplify_cli_core_2.stateManager.getTeamProviderInfo();
const appId = Object.values(tpi)[0].awscloudformation.AmplifyAppId;
const app = await clients.amplify.send(new client_amplify_1.GetAppCommand({ appId }));
const envName = await Gen1App.currentEnvName(app.app);
const envInfo = tpi[envName];
if (!envInfo) {
throw new amplify_cli_core_1.AmplifyError('TpiEnvironmentNotFoundError', {
message: `Environment ${envName} does not exist in ${tpiRelPath}`,
resolution: `Checkout to the branch corresponding to environment ${envName} and rerun the command`,
});
}
const cfnProvider = envInfo.awscloudformation;
if (!(cfnProvider === null || cfnProvider === void 0 ? void 0 : cfnProvider.StackName) || !(cfnProvider === null || cfnProvider === void 0 ? void 0 : cfnProvider.DeploymentBucketName)) {
throw new amplify_cli_core_1.AmplifyError('InvalidTpiEnvironmentError', {
message: `Missing StackName or DeploymentBucketName for environment '${envName}' in '${tpiRelPath}'`,
});
}
const additionalStatefulResourceTypes = additionalStatefulResourceTypesPath
? JSON.parse(await promises_1.default.readFile(additionalStatefulResourceTypesPath, { encoding: 'utf-8' }))
: undefined;
if (additionalStatefulResourceTypes && !Array.isArray(additionalStatefulResourceTypes)) {
throw new amplify_cli_core_1.AmplifyError('InputValidationError', {
message: `Invalid file structure: ${additionalStatefulResourceTypesPath}. Must be a JSON array.`,
});
}
const ccbDir = await Gen1App.downloadCloudBackend(clients.s3, cfnProvider.DeploymentBucketName);
return new Gen1App({ ccbDir, clients, envName, app: app.app, additionalStatefulResourceTypes });
}
categoryMeta(category) {
const block = this._meta[category];
if (block && typeof block === 'object' && Object.keys(block).length > 0) {
return block;
}
return undefined;
}
resourceMeta(resource) {
const category = this.categoryMeta(resource.category);
if (!category) {
throw new amplify_cli_core_1.AmplifyError('CategoryMetaNotFoundError', {
message: `Category '${resource.category}' not found in amplify-meta.json`,
});
}
const entry = category[resource.resourceName];
if (!entry || typeof entry !== 'object') {
throw new amplify_cli_core_1.AmplifyError('ResourceMetaNotFoundError', {
message: `Resource '${resource.resourceName}' not found in '${resource.category}' category in amplify-meta.json`,
});
}
return entry;
}
discover() {
const meta = this._meta;
const skip = new Set(['providers', 'hosting']);
const resources = [];
for (const [category, block] of Object.entries(meta)) {
if (skip.has(category) || !block || typeof block !== 'object')
continue;
for (const [resourceName, resourceMeta] of Object.entries(block)) {
if (!resourceMeta || typeof resourceMeta !== 'object') {
throw new amplify_cli_core_1.AmplifyError('ResourceMetaNotFoundError', { message: `Unable to find meta entry for resource ${resourceName}` });
}
const service = resourceMeta.service;
if (!service) {
throw new amplify_cli_core_1.AmplifyError('ResourceMetaNotFoundError', {
message: `Resource '${resourceName}' in category '${category}' is missing the 'service' field in amplify-meta.json`,
});
}
const rawKey = `${category}:${service}`;
const key = exports.KNOWN_RESOURCE_KEYS.includes(rawKey) ? rawKey : 'UNKNOWN';
resources.push({ category, resourceName, service, key });
}
}
return resources;
}
resourceMetaOutput(resource, outputKey) {
var _a, _b, _c;
const value = (_c = (_b = (_a = this._meta[resource.category]) === null || _a === void 0 ? void 0 : _a[resource.resourceName]) === null || _b === void 0 ? void 0 : _b.output) === null || _c === void 0 ? void 0 : _c[outputKey];
if (value === undefined) {
throw new amplify_cli_core_1.AmplifyError('ResourceMetaOutputNotFoundError', {
message: `Missing output '${outputKey}' for resource '${resource.resourceName}' in category '${resource.category}'`,
});
}
return value;
}
singleResourceName(category, service) {
const categoryBlock = this.categoryMeta(category);
if (!categoryBlock) {
throw new amplify_cli_core_1.AmplifyError('CategoryMetaNotFoundError', { message: `Category '${category}' not found in amplify-meta.json` });
}
const names = Object.keys(categoryBlock).filter((name) => categoryBlock[name].service === service);
if (names.length !== 1) {
throw new amplify_cli_core_1.AmplifyError('ResourceMetaNotFoundError', {
message: `Expected exactly one '${service}' resource in '${category}', found ${names.length}: ${names.join(', ')}`,
});
}
return names[0];
}
json(relativePath) {
return amplify_cli_core_1.JSONUtilities.readJson(node_path_1.default.join(this.ccbDir, relativePath), { throwIfNotExist: true });
}
file(relativePath) {
return (0, node_fs_1.readFileSync)(node_path_1.default.join(this.ccbDir, relativePath), 'utf8');
}
fileExists(relativePath) {
try {
(0, node_fs_1.readFileSync)(node_path_1.default.join(this.ccbDir, relativePath));
return true;
}
catch (_a) {
return false;
}
}
ensureCliInputs(category, resourceName) {
const relativePath = node_path_1.default.join(category, resourceName, 'cli-inputs.json');
const fullPath = node_path_1.default.join(this.ccbDir, relativePath);
try {
amplify_cli_core_1.JSONUtilities.readJson(fullPath, { throwIfNotExist: true });
}
catch (_a) {
throw new amplify_cli_core_1.AmplifyError('CliInputsFileNotFoundError', {
message: `Unable to find ${relativePath}. Your app was created with an old Gen1 CLI version (<=v6) that did not produce this file.`,
resolution: 'You must first migrate to the latest Gen1 CLI version by following https://docs.amplify.aws/gen1/javascript/tools/cli/migration/override/',
});
}
}
cliInputs(category, resourceName) {
const relativePath = node_path_1.default.join(category, resourceName, 'cli-inputs.json');
const fullPath = node_path_1.default.join(this.ccbDir, relativePath);
return amplify_cli_core_1.JSONUtilities.readJson(fullPath, { throwIfNotExist: true });
}
static async currentEnvName(app) {
var _a;
const migratingEnvName = ((_a = app.environmentVariables) !== null && _a !== void 0 ? _a : {})['GEN2_MIGRATION_ENVIRONMENT_NAME'];
const localEnvName = amplify_cli_core_2.stateManager.getCurrentEnvName();
if (!localEnvName && !migratingEnvName) {
throw new amplify_cli_core_1.AmplifyError('EnvironmentNotInitializedError', {
message: `No environment configured for app '${app.name}'`,
resolution: 'Run "amplify pull" to configure an environment.',
});
}
if (migratingEnvName && localEnvName && migratingEnvName !== localEnvName) {
throw new amplify_cli_core_1.AmplifyError('TpiEnvironmentMismatchError', {
message: `Environment mismatch: Your local env (${localEnvName}) does
not match the environment you marked for migration (${migratingEnvName})`,
});
}
return localEnvName !== null && localEnvName !== void 0 ? localEnvName : migratingEnvName;
}
static async downloadCloudBackend(s3Client, bucket) {
const tmpDir = await promises_1.default.mkdtemp(node_path_1.default.join(node_os_1.default.tmpdir(), 'amplify-ccb-'));
const zipKey = '#current-cloud-backend.zip';
const zipPath = node_path_1.default.join(tmpDir, zipKey);
const response = await s3Client.send(new client_s3_1.GetObjectCommand({ Key: zipKey, Bucket: bucket }));
if (!response.Body) {
throw new amplify_cli_core_1.AmplifyError('S3ObjectNotFoundError', { message: 'S3 GetObject response body is empty' });
}
await promises_1.default.writeFile(zipPath, response.Body);
const directory = await unzipper_1.default.Open.file(zipPath);
const ccbDir = node_path_1.default.join(tmpDir, 'current-cloud-backend');
await directory.extract({ path: ccbDir });
return ccbDir;
}
}
exports.Gen1App = Gen1App;
//# sourceMappingURL=gen1-app.js.map