@contentstack/cli-cm-import 1.7.1 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,536 @@
1
+ "use strict";
2
+ /* eslint-disable no-prototype-builtins */
3
+ /*!
4
+ * Contentstack Import
5
+ * Copyright (c) 2019 Contentstack LLC
6
+ * MIT Licensed
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const tslib_1 = require("tslib");
10
+ const path = tslib_1.__importStar(require("path"));
11
+ const lodash_1 = require("lodash");
12
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
13
+ const utils_1 = require("../../utils");
14
+ const base_class_1 = tslib_1.__importDefault(require("./base-class"));
15
+ class EntriesImport extends base_class_1.default {
16
+ constructor({ importConfig, stackAPIClient }) {
17
+ super({ importConfig, stackAPIClient });
18
+ this.assetUidMapperPath = path.resolve(importConfig.data, 'mapper', 'assets', 'uid-mapping.json');
19
+ this.assetUrlMapperPath = path.resolve(importConfig.data, 'mapper', 'assets', 'url-mapping.json');
20
+ this.entriesMapperPath = path.resolve(importConfig.data, 'mapper', 'entries');
21
+ this.envPath = path.resolve(importConfig.data, 'environments', 'environments.json');
22
+ this.entriesUIDMapperPath = path.join(this.entriesMapperPath, 'uid-mapping.json');
23
+ this.uniqueUidMapperPath = path.join(this.entriesMapperPath, 'unique-mapping.json');
24
+ this.modifiedCTsPath = path.join(this.entriesMapperPath, 'modified-schemas.json');
25
+ this.marketplaceAppMapperPath = path.join(this.importConfig.data, 'mapper', 'marketplace_apps', 'uid-mapping.json');
26
+ this.entriesConfig = importConfig.modules.entries;
27
+ this.entriesPath = path.resolve(importConfig.data, this.entriesConfig.dirName);
28
+ this.cTsPath = path.resolve(importConfig.data, importConfig.modules['content-types'].dirName);
29
+ this.localesPath = path.resolve(importConfig.data, importConfig.modules.locales.dirName, importConfig.modules.locales.fileName);
30
+ this.importConcurrency = this.entriesConfig.importConcurrency || importConfig.importConcurrency;
31
+ this.entriesUidMapper = {};
32
+ this.modifiedCTs = [];
33
+ this.refCTs = [];
34
+ this.jsonRteCTs = [];
35
+ this.jsonRteCTsWithRef = [];
36
+ this.envs = {};
37
+ this.autoCreatedEntries = [];
38
+ }
39
+ async start() {
40
+ try {
41
+ this.cTs = utils_1.fsUtil.readFile(path.join(this.cTsPath, 'schema.json'));
42
+ if (!this.cTs || (0, lodash_1.isEmpty)(this.cTs)) {
43
+ (0, utils_1.log)(this.importConfig, 'No content type found', 'info');
44
+ return;
45
+ }
46
+ this.installedExtensions = ((await utils_1.fsUtil.readFile(this.marketplaceAppMapperPath)) || { extension_uid: {} }).extension_uid;
47
+ this.assetUidMapper = utils_1.fsUtil.readFile(this.assetUidMapperPath) || {};
48
+ this.assetUrlMapper = utils_1.fsUtil.readFile(this.assetUrlMapperPath) || {};
49
+ utils_1.fsUtil.makeDirectory(this.entriesMapperPath);
50
+ await this.disableMandatoryCTReferences();
51
+ this.locales = (0, lodash_1.values)(utils_1.fsUtil.readFile(this.localesPath));
52
+ this.locales.unshift(this.importConfig.master_locale); // adds master locale to the list
53
+ //Create Entries
54
+ const entryRequestOptions = this.populateEntryCreatePayload();
55
+ for (let entryRequestOption of entryRequestOptions) {
56
+ await this.createEntries(entryRequestOption);
57
+ }
58
+ await utils_1.fileHelper.writeLargeFile(path.join(this.entriesMapperPath, 'uid-mapping.json'), this.entriesUidMapper); // TBD: manages mapper in one file, should find an alternative
59
+ utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
60
+ // Update entries with references
61
+ const entryUpdateRequestOptions = this.populateEntryUpdatePayload();
62
+ for (let entryUpdateRequestOption of entryUpdateRequestOptions) {
63
+ await this.updateEntriesWithReferences(entryUpdateRequestOption).catch((error) => {
64
+ (0, utils_1.log)(this.importConfig, `Error while updating entries references of ${entryUpdateRequestOption.cTUid} in locale ${entryUpdateRequestOption.locale}`, 'error');
65
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
66
+ });
67
+ }
68
+ utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
69
+ (0, utils_1.log)(this.importConfig, 'Restoring content type changes', 'info');
70
+ await this.enableMandatoryCTReferences().catch((error) => {
71
+ (0, utils_1.log)(this.importConfig, `Error while updating content type references ${(0, utils_1.formatError)(error)}`, 'error');
72
+ });
73
+ if (this.autoCreatedEntries.length > 0) {
74
+ (0, utils_1.log)(this.importConfig, 'Removing entries from master language which got created by default', 'info');
75
+ await this.removeAutoCreatedEntries().catch((error) => {
76
+ (0, utils_1.log)(this.importConfig, `Error while removing auto created entries in master locale ${(0, utils_1.formatError)(error)}`, 'error');
77
+ });
78
+ }
79
+ // Update field rule of content types which are got removed earlier
80
+ (0, utils_1.log)(this.importConfig, 'Updating the field rules of content type', 'info');
81
+ await this.updateFieldRules().catch((error) => {
82
+ (0, utils_1.log)(this.importConfig, `Error while updating field rules of content type ${(0, utils_1.formatError)(error)}`, 'error');
83
+ });
84
+ (0, utils_1.log)(this.importConfig, 'Entries imported successfully', 'success');
85
+ // Publishing entries
86
+ if (this.importConfig.entriesPublish) {
87
+ (0, utils_1.log)(this.importConfig, 'Publishing entries', 'info');
88
+ this.envs = utils_1.fileHelper.readFileSync(this.envPath);
89
+ for (let entryRequestOption of entryRequestOptions) {
90
+ await this.publishEntries(entryRequestOption).catch((error) => {
91
+ (0, utils_1.log)(this.importConfig, `Error in publishing entries of ${entryRequestOption.cTUid} in locale ${entryRequestOption.locale} ${(0, utils_1.formatError)(error)}`, 'error');
92
+ });
93
+ }
94
+ (0, utils_1.log)(this.importConfig, 'All the entries have been published successfully', 'success');
95
+ }
96
+ }
97
+ catch (error) {
98
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
99
+ throw new Error('Error while importing entries');
100
+ }
101
+ }
102
+ async disableMandatoryCTReferences() {
103
+ const onSuccess = ({ response: contentType, apiData: { uid } }) => {
104
+ (0, utils_1.log)(this.importConfig, `${uid} content type references removed temporarily`, 'success');
105
+ };
106
+ const onReject = ({ error, apiData: { uid } }) => {
107
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
108
+ throw new Error(`${uid} content type references removal failed`);
109
+ };
110
+ return await this.makeConcurrentCall({
111
+ processName: 'Update content types (removing mandatory references temporarily)',
112
+ apiContent: this.cTs,
113
+ apiParams: {
114
+ serializeData: this.serializeUpdateCTs.bind(this),
115
+ reject: onReject.bind(this),
116
+ resolve: onSuccess.bind(this),
117
+ entity: 'update-cts',
118
+ includeParamOnCompletion: true,
119
+ },
120
+ concurrencyLimit: this.importConcurrency,
121
+ }).then(() => {
122
+ utils_1.fsUtil.writeFile(this.modifiedCTsPath, this.modifiedCTs);
123
+ });
124
+ }
125
+ /**
126
+ * @method serializeUpdateCTs
127
+ * @param {ApiOptions} apiOptions ApiOptions
128
+ * @returns {ApiOptions} ApiOptions
129
+ */
130
+ serializeUpdateCTs(apiOptions) {
131
+ const { apiData: contentType } = apiOptions;
132
+ if (contentType.field_rules) {
133
+ delete contentType.field_rules;
134
+ }
135
+ const flag = {
136
+ suppressed: false,
137
+ references: false,
138
+ jsonRte: false,
139
+ jsonRteEmbeddedEntries: false,
140
+ };
141
+ (0, utils_1.suppressSchemaReference)(contentType.schema, flag);
142
+ // Check if suppress modified flag
143
+ if (flag.suppressed) {
144
+ this.modifiedCTs.push((0, lodash_1.find)(this.cTs, { uid: contentType.uid }));
145
+ }
146
+ else {
147
+ // Note: Skips the content type from update if no reference found
148
+ apiOptions.additionalInfo = { skip: true };
149
+ return apiOptions;
150
+ }
151
+ if (flag.references) {
152
+ this.refCTs.push(contentType.uid);
153
+ }
154
+ if (flag.jsonRte) {
155
+ this.jsonRteCTs.push(contentType.uid);
156
+ if (flag.jsonRteEmbeddedEntries) {
157
+ this.jsonRteCTsWithRef.push(contentType.uid);
158
+ if (this.refCTs.indexOf(contentType.uid) === -1) {
159
+ this.refCTs.push(contentType.uid);
160
+ }
161
+ }
162
+ }
163
+ (0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
164
+ const contentTypePayload = this.stack.contentType(contentType.uid);
165
+ Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
166
+ apiOptions.apiData = contentTypePayload;
167
+ return apiOptions;
168
+ }
169
+ populateEntryCreatePayload() {
170
+ const requestOptions = [];
171
+ for (let locale of this.locales) {
172
+ for (let contentType of this.cTs) {
173
+ requestOptions.push({
174
+ cTUid: contentType.uid,
175
+ locale: locale.code,
176
+ });
177
+ }
178
+ }
179
+ return requestOptions;
180
+ }
181
+ async createEntries({ cTUid, locale }) {
182
+ var _a, _b;
183
+ const processName = 'Create Entries';
184
+ const indexFileName = 'index.json';
185
+ const basePath = path.join(this.entriesPath, cTUid, locale);
186
+ const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
187
+ const indexer = fs.indexFileContent;
188
+ const indexerCount = (0, lodash_1.values)(indexer).length;
189
+ if (indexerCount === 0) {
190
+ return Promise.resolve();
191
+ }
192
+ (0, utils_1.log)(this.importConfig, `Starting to create entries for ${cTUid} in locale ${locale}`, 'info');
193
+ const isMasterLocale = locale === ((_b = (_a = this.importConfig) === null || _a === void 0 ? void 0 : _a.master_locale) === null || _b === void 0 ? void 0 : _b.code);
194
+ // Write created entries
195
+ const entriesCreateFileHelper = new cli_utilities_1.FsUtility({
196
+ moduleName: 'created-entries',
197
+ indexFileName: 'index.json',
198
+ basePath: path.join(this.entriesMapperPath, cTUid, locale),
199
+ chunkFileSize: this.entriesConfig.chunkFileSize,
200
+ keepMetadata: false,
201
+ omitKeys: this.entriesConfig.invalidKeys,
202
+ });
203
+ const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
204
+ const onSuccess = ({ response, apiData: entry, additionalInfo: { entryFileName } }) => {
205
+ (0, utils_1.log)(this.importConfig, `Created entry: '${entry.title}' of content type ${cTUid} in locale ${locale}`, 'info');
206
+ this.entriesUidMapper[entry.uid] = response.uid;
207
+ entry.sourceEntryFilePath = path.join(basePath, entryFileName); // stores source file path temporarily
208
+ entry.entryOldUid = entry.uid; // stores old uid temporarily
209
+ if (!isMasterLocale) {
210
+ this.autoCreatedEntries.push({ cTUid, locale, entryUid: response.uid });
211
+ }
212
+ entriesCreateFileHelper.writeIntoFile({ [response.uid]: entry }, { mapKeyVal: true });
213
+ };
214
+ const onReject = ({ error, apiData: { uid, title } }) => {
215
+ (0, utils_1.log)(this.importConfig, `${title} entry of content type ${cTUid} in locale ${locale} failed to create`, 'error');
216
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
217
+ this.failedEntries.push({ content_type: cTUid, locale, entry: { uid, title } });
218
+ };
219
+ for (const index in indexer) {
220
+ const chunk = await fs.readChunkFiles.next().catch((error) => {
221
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
222
+ });
223
+ if (chunk) {
224
+ let apiContent = (0, lodash_1.values)(chunk);
225
+ await this.makeConcurrentCall({
226
+ apiContent,
227
+ processName,
228
+ indexerCount,
229
+ currentIndexer: +index,
230
+ apiParams: {
231
+ reject: onReject,
232
+ resolve: onSuccess,
233
+ entity: 'create-entries',
234
+ includeParamOnCompletion: true,
235
+ serializeData: this.serializeEntries.bind(this),
236
+ additionalInfo: { contentType, locale, cTUid, entryFileName: indexer[index] },
237
+ },
238
+ concurrencyLimit: this.importConcurrency,
239
+ }).then(() => {
240
+ entriesCreateFileHelper === null || entriesCreateFileHelper === void 0 ? void 0 : entriesCreateFileHelper.completeFile(true);
241
+ (0, utils_1.log)(this.importConfig, `Created entries for content type ${cTUid} in locale ${locale}`, 'success');
242
+ });
243
+ }
244
+ }
245
+ }
246
+ /**
247
+ * @method serializeEntries
248
+ * @param {ApiOptions} apiOptions ApiOptions
249
+ * @returns {ApiOptions} ApiOptions
250
+ */
251
+ serializeEntries(apiOptions) {
252
+ let { apiData: entry, additionalInfo: { cTUid, locale, contentType }, } = apiOptions;
253
+ if (this.jsonRteCTs.indexOf(cTUid) > -1) {
254
+ entry = (0, utils_1.removeUidsFromJsonRteFields)(entry, contentType.schema);
255
+ }
256
+ // remove entry references from json-rte fields
257
+ if (this.jsonRteCTsWithRef.indexOf(cTUid) > -1) {
258
+ entry = (0, utils_1.removeEntryRefsFromJSONRTE)(entry, contentType.schema);
259
+ }
260
+ // will replace all old asset uid/urls with new ones
261
+ entry = (0, utils_1.lookupAssets)({
262
+ content_type: contentType,
263
+ entry: entry,
264
+ }, this.assetUidMapper, this.assetUrlMapper, path.join(this.entriesPath, cTUid), this.installedExtensions);
265
+ delete entry.publish_details;
266
+ apiOptions.apiData = entry;
267
+ return apiOptions;
268
+ }
269
+ populateEntryUpdatePayload() {
270
+ const requestOptions = [];
271
+ for (let locale of this.locales) {
272
+ for (let cTUid of this.refCTs) {
273
+ requestOptions.push({
274
+ cTUid,
275
+ locale: locale.code,
276
+ });
277
+ }
278
+ }
279
+ return requestOptions;
280
+ }
281
+ async updateEntriesWithReferences({ cTUid, locale }) {
282
+ const processName = 'Update Entries';
283
+ const indexFileName = 'index.json';
284
+ const basePath = path.join(this.entriesMapperPath, cTUid, locale);
285
+ const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
286
+ const indexer = fs.indexFileContent;
287
+ const indexerCount = (0, lodash_1.values)(indexer).length;
288
+ if (indexerCount === 0) {
289
+ return Promise.resolve();
290
+ }
291
+ (0, utils_1.log)(this.importConfig, `Starting to update entries with references for ${cTUid} in locale ${locale}`, 'info');
292
+ const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
293
+ const onSuccess = ({ response, apiData: { uid, url, title } }) => {
294
+ (0, utils_1.log)(this.importConfig, `Updated entry: '${title}' of content type ${cTUid} in locale ${locale}`, 'info');
295
+ };
296
+ const onReject = ({ error, apiData: { uid, title } }) => {
297
+ (0, utils_1.log)(this.importConfig, `${title} entry of content type ${cTUid} in locale ${locale} failed to update`, 'error');
298
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
299
+ this.failedEntries.push({ content_type: cTUid, locale, entry: { uid: this.entriesUidMapper[uid], title } });
300
+ };
301
+ for (const index in indexer) {
302
+ const chunk = await fs.readChunkFiles.next().catch((error) => {
303
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
304
+ });
305
+ if (chunk) {
306
+ let apiContent = (0, lodash_1.values)(chunk);
307
+ await this.makeConcurrentCall({
308
+ apiContent,
309
+ processName,
310
+ indexerCount,
311
+ currentIndexer: +index,
312
+ apiParams: {
313
+ reject: onReject,
314
+ resolve: onSuccess,
315
+ entity: 'update-entries',
316
+ includeParamOnCompletion: true,
317
+ serializeData: this.serializeUpdateEntries.bind(this),
318
+ additionalInfo: { contentType, locale, cTUid },
319
+ },
320
+ concurrencyLimit: this.importConcurrency,
321
+ }).then(() => {
322
+ (0, utils_1.log)(this.importConfig, `Updated entries for content type ${cTUid} in locale ${locale}`, 'success');
323
+ });
324
+ }
325
+ }
326
+ }
327
+ /**
328
+ * @method serializeUpdateEntries
329
+ * @param {ApiOptions} apiOptions ApiOptions
330
+ * @returns {ApiOptions} ApiOptions
331
+ */
332
+ serializeUpdateEntries(apiOptions) {
333
+ let { apiData: entry, additionalInfo: { cTUid, locale, contentType }, } = apiOptions;
334
+ const sourceEntryFilePath = entry.sourceEntryFilePath;
335
+ const sourceEntry = (utils_1.fsUtil.readFile(sourceEntryFilePath) || {})[entry.entryOldUid];
336
+ // Removing temp values
337
+ delete entry.sourceEntryFilePath;
338
+ delete entry.entryOldUid;
339
+ if (this.jsonRteCTs.indexOf(cTUid) > -1) {
340
+ // the entries stored in eSuccessFilePath, have the same uids as the entries from source data
341
+ entry = (0, utils_1.restoreJsonRteEntryRefs)(entry, sourceEntry, contentType.schema, {
342
+ mappedAssetUids: this.assetUidMapper,
343
+ mappedAssetUrls: this.assetUrlMapper,
344
+ });
345
+ }
346
+ entry = (0, utils_1.lookupEntries)({
347
+ content_type: contentType,
348
+ entry,
349
+ }, this.entriesUidMapper, path.join(this.entriesMapperPath, cTUid, locale));
350
+ const entryResponse = this.stack.contentType(contentType.uid).entry(this.entriesUidMapper[entry.uid]);
351
+ Object.assign(entryResponse, (0, lodash_1.cloneDeep)(entry));
352
+ delete entryResponse.publish_details;
353
+ apiOptions.apiData = entryResponse;
354
+ return apiOptions;
355
+ }
356
+ async enableMandatoryCTReferences() {
357
+ const onSuccess = ({ response: contentType, apiData: { uid } }) => {
358
+ (0, utils_1.log)(this.importConfig, `${uid} content type references updated`, 'success');
359
+ };
360
+ const onReject = ({ error, apiData: { uid } }) => {
361
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
362
+ throw new Error(`Failed to update references of content type ${uid}`);
363
+ };
364
+ return await this.makeConcurrentCall({
365
+ processName: 'Update content type references',
366
+ apiContent: this.modifiedCTs,
367
+ apiParams: {
368
+ serializeData: this.serializeUpdateCTsWithRef.bind(this),
369
+ reject: onReject.bind(this),
370
+ resolve: onSuccess.bind(this),
371
+ entity: 'update-cts',
372
+ includeParamOnCompletion: true,
373
+ },
374
+ concurrencyLimit: this.importConcurrency,
375
+ });
376
+ }
377
+ /**
378
+ * @method serializeUpdateCTsWithRef
379
+ * @param {ApiOptions} apiOptions ApiOptions
380
+ * @returns {ApiOptions} ApiOptions
381
+ */
382
+ serializeUpdateCTsWithRef(apiOptions) {
383
+ const { apiData: contentType } = apiOptions;
384
+ if (contentType.field_rules) {
385
+ delete contentType.field_rules;
386
+ }
387
+ (0, utils_1.lookupExtension)(this.importConfig, contentType.schema, this.importConfig.preserveStackVersion, this.installedExtensions);
388
+ const contentTypePayload = this.stack.contentType(contentType.uid);
389
+ Object.assign(contentTypePayload, (0, lodash_1.cloneDeep)(contentType));
390
+ apiOptions.apiData = contentTypePayload;
391
+ return apiOptions;
392
+ }
393
+ async removeAutoCreatedEntries() {
394
+ const onSuccess = ({ response, apiData: { entryUid } }) => {
395
+ (0, utils_1.log)(this.importConfig, `Auto created entry in master locale removed - entry uid ${entryUid} `, 'success');
396
+ };
397
+ const onReject = ({ error, apiData: { entryUid } }) => {
398
+ (0, utils_1.log)(this.importConfig, `Failed to remove auto created entry in master locale - entry uid ${entryUid} \n ${(0, utils_1.formatError)(error)}`, 'error');
399
+ };
400
+ return await this.makeConcurrentCall({
401
+ processName: 'Remove auto created entry in master locale',
402
+ apiContent: this.autoCreatedEntries,
403
+ apiParams: {
404
+ reject: onReject.bind(this),
405
+ resolve: onSuccess.bind(this),
406
+ entity: 'delete-entries',
407
+ includeParamOnCompletion: true,
408
+ },
409
+ concurrencyLimit: this.importConcurrency,
410
+ });
411
+ }
412
+ async updateFieldRules() {
413
+ let cTsWithFieldRules = utils_1.fsUtil.readFile(path.join(this.cTsPath + '/field_rules_uid.json'));
414
+ if (!cTsWithFieldRules || (cTsWithFieldRules === null || cTsWithFieldRules === void 0 ? void 0 : cTsWithFieldRules.length) === 0) {
415
+ return;
416
+ }
417
+ for (let cTUid of cTsWithFieldRules) {
418
+ const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
419
+ if (contentType.field_rules) {
420
+ let fieldRuleLength = contentType.field_rules.length;
421
+ for (let k = 0; k < fieldRuleLength; k++) {
422
+ let fieldRuleConditionLength = contentType.field_rules[k].conditions.length;
423
+ for (let i = 0; i < fieldRuleConditionLength; i++) {
424
+ if (contentType.field_rules[k].conditions[i].operand_field === 'reference') {
425
+ let fieldRulesValue = contentType.field_rules[k].conditions[i].value;
426
+ let fieldRulesArray = fieldRulesValue.split('.');
427
+ let updatedValue = [];
428
+ for (const element of fieldRulesArray) {
429
+ let splittedFieldRulesValue = element;
430
+ if (this.entriesUidMapper.hasOwnProperty(splittedFieldRulesValue)) {
431
+ updatedValue.push(this.entriesUidMapper[splittedFieldRulesValue]);
432
+ }
433
+ else {
434
+ updatedValue.push(element);
435
+ }
436
+ }
437
+ contentType.field_rules[k].conditions[i].value = updatedValue.join('.');
438
+ }
439
+ }
440
+ }
441
+ const contentTypeResponse = await this.stack
442
+ .contentType(contentType.uid)
443
+ .fetch()
444
+ .catch((error) => {
445
+ (0, utils_1.log)(this.importConfig, `failed to update the field rules of ${cTUid} ${(0, utils_1.formatError)(error)}`, 'error');
446
+ });
447
+ if (!contentTypeResponse) {
448
+ continue;
449
+ }
450
+ contentTypeResponse.field_rules = contentType.field_rules;
451
+ await contentTypeResponse.update().catch((error) => {
452
+ (0, utils_1.log)(this.importConfig, `failed to update the field rules of ${cTUid} ${(0, utils_1.formatError)(error)}`, 'error');
453
+ });
454
+ (0, utils_1.log)(this.importConfig, `Updated the field rules of ${cTUid}`, 'info');
455
+ }
456
+ else {
457
+ (0, utils_1.log)(this.importConfig, `No field rules found in content type ${cTUid} to update`, 'error');
458
+ }
459
+ }
460
+ }
461
+ async publishEntries({ cTUid, locale }) {
462
+ const processName = 'Publish Entries';
463
+ const indexFileName = 'index.json';
464
+ const basePath = path.join(this.entriesPath, cTUid, locale);
465
+ const fs = new cli_utilities_1.FsUtility({ basePath, indexFileName });
466
+ const indexer = fs.indexFileContent;
467
+ const indexerCount = (0, lodash_1.values)(indexer).length;
468
+ const contentType = (0, lodash_1.find)(this.cTs, { uid: cTUid });
469
+ if (indexerCount === 0) {
470
+ return Promise.resolve();
471
+ }
472
+ (0, utils_1.log)(this.importConfig, `Starting publish entries for ${cTUid} in locale ${locale}`, 'info');
473
+ const onSuccess = ({ response, apiData: { environments }, additionalInfo: { entryUid } }) => {
474
+ (0, utils_1.log)(this.importConfig, `Published entry: '${entryUid}' of content type ${cTUid} and locale ${locale} in ${environments === null || environments === void 0 ? void 0 : environments.join(',')} environments`, 'info');
475
+ };
476
+ const onReject = ({ error, apiData, additionalInfo: { entryUid } }) => {
477
+ (0, utils_1.log)(this.importConfig, `${entryUid} entry of content type ${cTUid} in locale ${locale} failed to publish`, 'error');
478
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
479
+ };
480
+ for (const index in indexer) {
481
+ const chunk = await fs.readChunkFiles.next().catch((error) => {
482
+ (0, utils_1.log)(this.importConfig, (0, utils_1.formatError)(error), 'error');
483
+ });
484
+ if (chunk) {
485
+ let apiContent = (0, lodash_1.values)(chunk);
486
+ await this.makeConcurrentCall({
487
+ apiContent,
488
+ processName,
489
+ indexerCount,
490
+ currentIndexer: +index,
491
+ apiParams: {
492
+ reject: onReject,
493
+ resolve: onSuccess,
494
+ entity: 'publish-entries',
495
+ includeParamOnCompletion: true,
496
+ serializeData: this.serializePublishEntries.bind(this),
497
+ additionalInfo: { contentType, locale, cTUid },
498
+ },
499
+ concurrencyLimit: this.importConcurrency,
500
+ }).then(() => {
501
+ (0, utils_1.log)(this.importConfig, `Published entries for content type ${cTUid} in locale ${locale}`, 'success');
502
+ });
503
+ }
504
+ }
505
+ }
506
+ /**
507
+ * @method serializeEntries
508
+ * @param {ApiOptions} apiOptions ApiOptions
509
+ * @returns {ApiOptions} ApiOptions
510
+ */
511
+ serializePublishEntries(apiOptions) {
512
+ let { apiData: entry, additionalInfo } = apiOptions;
513
+ additionalInfo.entryUid = this.entriesUidMapper[entry.uid];
514
+ const requestObject = {
515
+ environments: [],
516
+ locales: [],
517
+ };
518
+ if (entry.publish_details && entry.publish_details.length > 0) {
519
+ (0, lodash_1.forEach)(entry.publish_details, (pubObject) => {
520
+ if (this.envs.hasOwnProperty(pubObject.environment) &&
521
+ (0, lodash_1.indexOf)(requestObject.environments, this.envs[pubObject.environment].name) === -1) {
522
+ requestObject.environments.push(this.envs[pubObject.environment].name);
523
+ }
524
+ if (pubObject.locale && (0, lodash_1.indexOf)(requestObject.locales, pubObject.locale) === -1) {
525
+ requestObject.locales.push(pubObject.locale);
526
+ }
527
+ });
528
+ }
529
+ else {
530
+ additionalInfo.skip = true;
531
+ }
532
+ apiOptions.apiData = requestObject;
533
+ return apiOptions;
534
+ }
535
+ }
536
+ exports.default = EntriesImport;
@@ -12,7 +12,7 @@ export default class ImportMarketplaceApps extends BaseClass {
12
12
  private appUidMapping;
13
13
  private installationUidMapping;
14
14
  private installedApps;
15
- private appOrginalName;
15
+ private appOriginalName;
16
16
  developerHubBaseUrl: string;
17
17
  sdkClient: ContentstackClient;
18
18
  nodeCrypto: NodeCrypto;
@@ -40,7 +40,10 @@ export default class ImportMarketplaceApps extends BaseClass {
40
40
  appCreationCallback(app: any, response: any, appSuffix: number): Promise<any>;
41
41
  /**
42
42
  * @method installApps
43
- * @returns {Void}
43
+ *
44
+ * @param {Record<string, any>} app
45
+ * @param {Record<string, any>[]} installedApps
46
+ * @returns {Promise<void>}
44
47
  */
45
48
  installApps(app: any): Promise<void>;
46
49
  /**
@@ -1,22 +1,22 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
5
- const find_1 = tslib_1.__importDefault(require("lodash/find"));
4
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
5
  const map_1 = tslib_1.__importDefault(require("lodash/map"));
6
+ const find_1 = tslib_1.__importDefault(require("lodash/find"));
7
7
  const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
8
+ const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
8
9
  const first_1 = tslib_1.__importDefault(require("lodash/first"));
9
10
  const split_1 = tslib_1.__importDefault(require("lodash/split"));
10
- const toLower_1 = tslib_1.__importDefault(require("lodash/toLower"));
11
- const filter_1 = tslib_1.__importDefault(require("lodash/filter"));
12
- const pick_1 = tslib_1.__importDefault(require("lodash/pick"));
13
11
  const node_path_1 = require("node:path");
12
+ const filter_1 = tslib_1.__importDefault(require("lodash/filter"));
13
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
14
+ const toLower_1 = tslib_1.__importDefault(require("lodash/toLower"));
14
15
  const cli_utilities_1 = require("@contentstack/cli-utilities");
15
- const chalk_1 = tslib_1.__importDefault(require("chalk"));
16
16
  const config_1 = tslib_1.__importDefault(require("../../config"));
17
- const utils_1 = require("../../utils");
18
17
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
19
18
  const interactive_1 = require("../../utils/interactive");
19
+ const utils_1 = require("../../utils");
20
20
  class ImportMarketplaceApps extends base_class_1.default {
21
21
  constructor({ importConfig, stackAPIClient }) {
22
22
  super({ importConfig, stackAPIClient });
@@ -27,7 +27,7 @@ class ImportMarketplaceApps extends base_class_1.default {
27
27
  this.httpClient = new cli_utilities_1.HttpClient();
28
28
  this.appNameMapping = {};
29
29
  this.appUidMapping = {};
30
- this.appOrginalName = undefined;
30
+ this.appOriginalName = undefined;
31
31
  this.installedApps = [];
32
32
  this.installationUidMapping = {};
33
33
  }
@@ -105,7 +105,8 @@ class ImportMarketplaceApps extends base_class_1.default {
105
105
  const listOfNewMeta = [];
106
106
  const listOfOldMeta = [];
107
107
  const extensionUidMap = {};
108
- this.installedApps = await (0, utils_1.getAllStackSpecificApps)(this.developerHubBaseUrl, this.httpClient, this.importConfig);
108
+ this.installedApps =
109
+ (await (0, utils_1.getAllStackSpecificApps)(this.developerHubBaseUrl, this.httpClient, this.importConfig)) || [];
109
110
  for (const app of this.marketplaceApps) {
110
111
  listOfOldMeta.push(...(0, map_1.default)((_a = app === null || app === void 0 ? void 0 : app.ui_location) === null || _a === void 0 ? void 0 : _a.locations, 'meta').flat());
111
112
  }
@@ -160,7 +161,7 @@ class ImportMarketplaceApps extends base_class_1.default {
160
161
  for (let app of privateApps) {
161
162
  // NOTE keys can be passed to install new app in the developer hub
162
163
  app.manifest = (0, pick_1.default)(app.manifest, ['uid', 'name', 'description', 'icon', 'target_type', 'webhook', 'oauth']);
163
- this.appOrginalName = app.manifest.name;
164
+ this.appOriginalName = app.manifest.name;
164
165
  const obj = {
165
166
  oauth: app.oauth,
166
167
  webhook: app.webhook,
@@ -168,10 +169,11 @@ class ImportMarketplaceApps extends base_class_1.default {
168
169
  };
169
170
  await this.createPrivateApps(Object.assign(Object.assign({}, obj), app.manifest));
170
171
  }
171
- this.appOrginalName = undefined;
172
+ this.appOriginalName = undefined;
172
173
  }
173
174
  async createPrivateApps(app, uidCleaned = false, appSuffix = 1) {
174
- let locations = app.ui_location && app.ui_location.locations;
175
+ var _a;
176
+ let locations = (_a = app === null || app === void 0 ? void 0 : app.ui_location) === null || _a === void 0 ? void 0 : _a.locations;
175
177
  if (!uidCleaned && !(0, isEmpty_1.default)(locations)) {
176
178
  app.ui_location.locations = await this.updateManifestUILocations(locations, 'uid');
177
179
  }
@@ -199,8 +201,8 @@ class ImportMarketplaceApps extends base_class_1.default {
199
201
  location.meta = (0, map_1.default)(location.meta, (meta) => {
200
202
  if (meta.name) {
201
203
  const name = `${(0, first_1.default)((0, split_1.default)(meta.name, '◈'))}◈${appSuffix}`;
202
- if (!this.appNameMapping[this.appOrginalName]) {
203
- this.appNameMapping[this.appOrginalName] = name;
204
+ if (!this.appNameMapping[this.appOriginalName]) {
205
+ this.appNameMapping[this.appOriginalName] = name;
204
206
  }
205
207
  meta.name = name;
206
208
  }
@@ -234,12 +236,15 @@ class ImportMarketplaceApps extends base_class_1.default {
234
236
  // NOTE new app installation
235
237
  (0, utils_1.log)(this.importConfig, `${response.name} app created successfully.!`, 'success');
236
238
  this.appUidMapping[app.uid] = response.uid;
237
- this.appNameMapping[this.appOrginalName] = response.name;
239
+ this.appNameMapping[this.appOriginalName] = response.name;
238
240
  }
239
241
  }
240
242
  /**
241
243
  * @method installApps
242
- * @returns {Void}
244
+ *
245
+ * @param {Record<string, any>} app
246
+ * @param {Record<string, any>[]} installedApps
247
+ * @returns {Promise<void>}
243
248
  */
244
249
  async installApps(app) {
245
250
  var _a, _b, _c, _d;