@amplience/dc-cli
Version:
Dynamic Content CLI Tool
341 lines (340 loc) • 16.8 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = exports.separateReplicas = exports.processWebhooks = exports.filterWebhooks = exports.processIndexes = exports.getIndexExports = exports.getExportedWebhooks = exports.getExportRecordForIndex = exports.enrichIndex = exports.enrichReplica = exports.registerWebhook = exports.filterIndexesById = exports.EnrichedSearchIndex = exports.EnrichedReplica = exports.EnrichedAssignedContentType = exports.equals = exports.ensureSettings = exports.assignedContentTypeEquals = exports.replicaEquals = exports.webhookEquals = exports.builder = exports.LOG_FILENAME = exports.desc = exports.command = void 0;
const chalk_1 = __importDefault(require("chalk"));
const dc_management_sdk_js_1 = require("dc-management-sdk-js");
const AssignedContentType_1 = require("dc-management-sdk-js/build/main/lib/model/AssignedContentType");
const SearchIndexKey_1 = require("dc-management-sdk-js/build/main/lib/model/SearchIndexKey");
const lodash_1 = require("lodash");
const table_1 = require("table");
const paginator_1 = __importDefault(require("../../common/dc-management-sdk-js/paginator"));
const directory_utils_1 = require("../../common/import/directory-utils");
const log_helpers_1 = require("../../common/log-helpers");
const table_consts_1 = require("../../common/table/table.consts");
const dynamic_content_client_factory_1 = __importDefault(require("../../services/dynamic-content-client-factory"));
const export_service_1 = require("../../services/export.service");
const import_service_1 = require("../../services/import.service");
const import_1 = require("./import");
const path_1 = require("path");
exports.command = 'export <dir>';
exports.desc = 'Export Search Indexes';
const LOG_FILENAME = (platform = process.platform) => (0, log_helpers_1.getDefaultLogPath)('search-index', 'export', platform);
exports.LOG_FILENAME = LOG_FILENAME;
const builder = (yargs) => {
yargs
.positional('dir', {
describe: 'Output directory for the exported Search Index definitions',
type: 'string'
})
.option('id', {
type: 'string',
describe: 'The ID of a Search Index to be exported.\nIf no --id option is given, all search indexes for the hub are exported.\nA single --id option may be given to export a single Search Index.\nMultiple --id options may be given to export multiple search indexes at the same time.',
requiresArg: true
})
.alias('f', 'force')
.option('f', {
type: 'boolean',
boolean: true,
describe: 'Overwrite search indexes without asking.'
})
.option('logFile', {
type: 'string',
default: exports.LOG_FILENAME,
describe: 'Path to a log file to write to.',
coerce: log_helpers_1.createLog
});
};
exports.builder = builder;
const ensureJSON = (resource) => {
return resource.toJSON != null ? resource.toJSON() : resource;
};
const webhookEquals = (a, b) => {
if (a === undefined) {
return b === undefined;
}
else if (b === undefined) {
return false;
}
return (a.method === b.method &&
a.secret === b.secret &&
a.label === b.label &&
a.active === b.active &&
(0, lodash_1.isEqual)(a.customPayload, b.customPayload) &&
(0, lodash_1.isEqual)(a.events, b.events) &&
(0, lodash_1.isEqual)(a.filters, b.filters) &&
(0, lodash_1.isEqual)(a.handlers, b.handlers) &&
(0, lodash_1.isEqual)(a.headers, b.headers));
};
exports.webhookEquals = webhookEquals;
const replicaEquals = (a, b, keys) => a.label === b.label &&
(!keys || (0, lodash_1.isEqual)(ensureJSON(a.keys), ensureJSON(b.keys))) &&
(0, lodash_1.isEqual)(ensureJSON(a.settings), ensureJSON(b.settings));
exports.replicaEquals = replicaEquals;
const assignedContentTypeEquals = (a, b, aWebhooks, bWebhooks) => !(aWebhooks && bWebhooks) ||
((0, exports.webhookEquals)(aWebhooks.get(a.webhook), bWebhooks.get(b.webhook)) &&
(0, exports.webhookEquals)(aWebhooks.get(a.activeContentWebhook), bWebhooks.get(b.activeContentWebhook)) &&
(0, exports.webhookEquals)(aWebhooks.get(a.archivedContentWebhook), bWebhooks.get(b.archivedContentWebhook)));
exports.assignedContentTypeEquals = assignedContentTypeEquals;
const ensureSettings = (settings) => {
const result = ensureJSON(settings);
result.replicas = result.replicas || [];
return result;
};
exports.ensureSettings = ensureSettings;
const equals = (a, b, keys = true, aWebhooks, bWebhooks) => a.label === b.label &&
a.assignedContentTypes
.map((x, i) => (0, exports.assignedContentTypeEquals)(x, b.assignedContentTypes[i], aWebhooks, bWebhooks))
.reduce((a, b) => a && b, true) &&
a.replicas.length == b.replicas.length &&
a.replicas.map((x, i) => (0, exports.replicaEquals)(x, b.replicas[i], keys)).reduce((a, b) => a && b, true) &&
(!keys || (0, lodash_1.isEqual)(ensureJSON(a.keys), ensureJSON(b.keys))) &&
(0, lodash_1.isEqual)((0, exports.ensureSettings)(a.settings), (0, exports.ensureSettings)(b.settings));
exports.equals = equals;
const searchIndexList = (hub, parentId, projection) => {
return (options) => hub.related.searchIndexes.list(parentId, projection, options);
};
class EnrichedAssignedContentType extends AssignedContentType_1.AssignedContentType {
}
exports.EnrichedAssignedContentType = EnrichedAssignedContentType;
class EnrichedReplica extends dc_management_sdk_js_1.SearchIndex {
}
exports.EnrichedReplica = EnrichedReplica;
class EnrichedSearchIndex extends dc_management_sdk_js_1.SearchIndex {
constructor(data) {
super(data);
if (this.settings && !(this.settings instanceof dc_management_sdk_js_1.SearchIndexSettings)) {
this.settings = new dc_management_sdk_js_1.SearchIndexSettings(this.settings);
}
if (this.keys && !(this.keys instanceof SearchIndexKey_1.SearchIndexKey)) {
this.keys = new SearchIndexKey_1.SearchIndexKey(this.keys);
}
if (this.assignedContentTypes) {
this.assignedContentTypes = this.assignedContentTypes.map(x => x instanceof EnrichedAssignedContentType ? x : new EnrichedAssignedContentType(x));
}
if (this.replicas) {
this.replicas = this.replicas.map(x => (x instanceof EnrichedReplica ? x : new EnrichedReplica(x)));
}
}
toJSON() {
const result = super.toJSON();
if (result.settings) {
result.settings = result.settings.toJSON();
}
if (result.keys) {
result.keys = result.keys.toJSON();
}
if (result.assignedContentTypes) {
result.assignedContentTypes = result.assignedContentTypes.map((type) => type.toJSON());
}
if (result.replicas) {
result.replicas = result.replicas.map((replica) => replica.toJSON());
}
return result;
}
}
exports.EnrichedSearchIndex = EnrichedSearchIndex;
const filterIndexesById = (listToFilter, indexIdList) => {
if (indexIdList.length === 0) {
return listToFilter;
}
const unmatchedIndexUriList = indexIdList.filter(id => !listToFilter.some(index => index.id === id));
if (unmatchedIndexUriList.length > 0) {
throw new Error(`The following ID(s) could not be found: [${unmatchedIndexUriList
.map(u => `'${u}'`)
.join(', ')}].\nNothing was exported, exiting.`);
}
return listToFilter.filter(index => indexIdList.some(id => index.id === id));
};
exports.filterIndexesById = filterIndexesById;
const registerWebhook = (mapping, webhook) => {
mapping.set(webhook.id, webhook);
return webhook.id;
};
exports.registerWebhook = registerWebhook;
const enrichReplica = async (replica) => {
const enrichedReplica = new EnrichedReplica(replica);
enrichedReplica.settings = await replica.related.settings.get();
enrichedReplica.keys = await replica.related.keys.get();
return enrichedReplica;
};
exports.enrichReplica = enrichReplica;
const enrichIndex = async (webhooks, allReplicas, index) => {
const enrichedIndex = new EnrichedSearchIndex(index);
enrichedIndex.settings = await index.related.settings.get();
const types = await (0, paginator_1.default)(index.related.assignedContentTypes.list);
enrichedIndex.keys = await index.related.keys.get();
const replicas = allReplicas.get(index.id);
if (replicas) {
enrichedIndex.replicas = await Promise.all(replicas.map(exports.enrichReplica));
}
else {
enrichedIndex.replicas = [];
}
const enrichedTypes = [];
for (const type of types) {
const enriched = new EnrichedAssignedContentType(type);
enriched.webhook = (0, exports.registerWebhook)(webhooks, await type.related.webhook());
enriched.activeContentWebhook = (0, exports.registerWebhook)(webhooks, await type.related.activeContentWebhook());
enriched.archivedContentWebhook = (0, exports.registerWebhook)(webhooks, await type.related.archivedContentWebhook());
enrichedTypes.push(enriched);
}
enrichedIndex.assignedContentTypes = enrichedTypes;
return enrichedIndex;
};
exports.enrichIndex = enrichIndex;
const getExportRecordForIndex = (index, outputDir, previouslyExportedIndexes, previouslyExportedWebhooks, webhooksBeingExported) => {
const indexOfExportedIndex = Object.values(previouslyExportedIndexes).findIndex(c => c.name === index.name);
if (indexOfExportedIndex < 0) {
const filename = (0, export_service_1.uniqueFilenamePath)(outputDir, index.name, 'json', Object.keys(previouslyExportedIndexes));
previouslyExportedIndexes[filename] = index;
return {
filename: filename,
status: 'CREATED',
index
};
}
const filename = Object.keys(previouslyExportedIndexes)[indexOfExportedIndex];
const previouslyExportedIndex = Object.values(previouslyExportedIndexes)[indexOfExportedIndex];
if ((0, exports.equals)(previouslyExportedIndex, index, true, previouslyExportedWebhooks, webhooksBeingExported)) {
return { filename, status: 'UP-TO-DATE', index };
}
return {
filename,
status: 'UPDATED',
index
};
};
exports.getExportRecordForIndex = getExportRecordForIndex;
const getExportedWebhooks = (outputDir) => {
const exportedWebhooks = (0, import_service_1.loadJsonFromDirectory)((0, path_1.join)(outputDir, 'webhooks'), dc_management_sdk_js_1.Webhook);
const webhookList = Object.values(exportedWebhooks);
const webhooks = new Map();
for (const webhook of webhookList) {
if (webhook.id) {
webhooks.set(webhook.id, webhook);
}
}
return webhooks;
};
exports.getExportedWebhooks = getExportedWebhooks;
const getIndexExports = (outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported) => {
const allExports = [];
const updatedExportsMap = [];
const previouslyExportedWebhooks = (0, exports.getExportedWebhooks)(outputDir);
for (const index of indexesBeingExported) {
if (!index.name) {
continue;
}
const exportRecord = (0, exports.getExportRecordForIndex)(index, outputDir, previouslyExportedIndexes, previouslyExportedWebhooks, webhooksBeingExported);
allExports.push(exportRecord);
if (exportRecord.status === 'UPDATED') {
updatedExportsMap.push({ uri: index.name, filename: exportRecord.filename });
}
}
return [allExports, updatedExportsMap];
};
exports.getIndexExports = getIndexExports;
const processIndexes = async (outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported, log, force) => {
if (indexesBeingExported.length === 0) {
(0, export_service_1.nothingExportedExit)(log, 'No search indexes to export from this hub, exiting.');
return;
}
const [allExports, updatedExportsMap] = (0, exports.getIndexExports)(outputDir, previouslyExportedIndexes, indexesBeingExported, webhooksBeingExported);
if (allExports.length === 0 ||
(Object.keys(updatedExportsMap).length > 0 && !(force || (await (0, export_service_1.promptToOverwriteExports)(updatedExportsMap, log))))) {
(0, export_service_1.nothingExportedExit)(log);
return;
}
await (0, directory_utils_1.ensureDirectoryExists)(outputDir);
const data = [];
data.push([chalk_1.default.bold('File'), chalk_1.default.bold('Name'), chalk_1.default.bold('Result')]);
for (const { filename, status, index } of allExports) {
if (status !== 'UP-TO-DATE') {
delete index.id;
(0, export_service_1.writeJsonToFile)(filename, index);
}
else {
indexesBeingExported.splice(indexesBeingExported.indexOf(index), 1);
}
data.push([filename, index.name, status]);
}
log.appendLine((0, table_1.table)(data, table_consts_1.streamTableOptions));
};
exports.processIndexes = processIndexes;
const filterWebhooks = (webhooks, filteredIndexes) => {
const filtered = new Map();
for (const index of filteredIndexes) {
for (const type of index.assignedContentTypes) {
filtered.set(type.webhook, webhooks.get(type.webhook));
filtered.set(type.activeContentWebhook, webhooks.get(type.activeContentWebhook));
filtered.set(type.archivedContentWebhook, webhooks.get(type.archivedContentWebhook));
}
}
return filtered;
};
exports.filterWebhooks = filterWebhooks;
const processWebhooks = async (outputDir, webhooksBeingExported, log) => {
if (webhooksBeingExported.length === 0) {
return;
}
log.appendLine('Exporting Webhooks...');
const previouslyExportedWebhooks = {};
const base = (0, path_1.join)(outputDir, 'webhooks');
await (0, directory_utils_1.ensureDirectoryExists)(base);
const data = [];
data.push([chalk_1.default.bold('File'), chalk_1.default.bold('Label'), chalk_1.default.bold('Result')]);
for (const webhook of webhooksBeingExported) {
const filename = (0, export_service_1.uniqueFilenamePath)(base, webhook.label, 'json', Object.keys(previouslyExportedWebhooks));
previouslyExportedWebhooks[filename] = webhook;
(0, export_service_1.writeJsonToFile)(filename, webhook);
data.push([filename, webhook.label, 'UPDATED']);
}
log.appendLine((0, table_1.table)(data, table_consts_1.streamTableOptions));
};
exports.processWebhooks = processWebhooks;
const separateReplicas = (allIndexes) => {
const storedIndexes = [];
const allReplicas = new Map();
for (const index of allIndexes) {
if (index.parentId == null) {
storedIndexes.push(index);
}
else {
let list = allReplicas.get(index.parentId);
if (list == null) {
list = [];
allReplicas.set(index.parentId, list);
}
list.push(index);
}
}
return { storedIndexes, allReplicas };
};
exports.separateReplicas = separateReplicas;
const handler = async (argv) => {
const { dir, id, logFile, force } = argv;
const client = (0, dynamic_content_client_factory_1.default)(argv);
const hub = await client.hubs.get(argv.hubId);
const log = logFile.open();
if (!(hub._links && hub._links.hasOwnProperty('algolia-search-indexes'))) {
log.warn('Search Indexes link missing for the given hub - they are likely disabled for this account.');
await log.close();
return;
}
const previouslyExportedIndexes = (0, import_service_1.loadJsonFromDirectory)(dir, EnrichedSearchIndex);
(0, import_1.validateNoDuplicateIndexNames)(previouslyExportedIndexes);
const allStoredIndexes = await (0, paginator_1.default)(searchIndexList(hub));
const { storedIndexes, allReplicas } = (0, exports.separateReplicas)(allStoredIndexes);
const idArray = id ? (Array.isArray(id) ? id : [id]) : [];
const filteredIndexes = (0, exports.filterIndexesById)(storedIndexes, idArray);
const webhooks = new Map();
const enrichedIndexes = await Promise.all(filteredIndexes.map(index => (0, exports.enrichIndex)(webhooks, allReplicas, index)));
await (0, exports.processIndexes)(dir, previouslyExportedIndexes, enrichedIndexes, webhooks, log, force || false);
const filteredWebhooks = (0, exports.filterWebhooks)(webhooks, enrichedIndexes);
await (0, exports.processWebhooks)(dir, Array.from(filteredWebhooks.values()), log);
await log.close();
};
exports.handler = handler;