@contentstack/cli-cm-import 2.0.0-beta.1 → 2.0.0-beta.10

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.
Files changed (54) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +50 -96
  3. package/lib/commands/cm/stacks/import.d.ts +0 -1
  4. package/lib/commands/cm/stacks/import.js +13 -46
  5. package/lib/config/index.js +7 -0
  6. package/lib/constants/index.d.ts +57 -0
  7. package/lib/constants/index.js +59 -0
  8. package/lib/import/module-importer.js +4 -4
  9. package/lib/import/modules/assets.js +18 -9
  10. package/lib/import/modules/base-class.d.ts +21 -4
  11. package/lib/import/modules/base-class.js +31 -1
  12. package/lib/import/modules/composable-studio.d.ts +44 -0
  13. package/lib/import/modules/composable-studio.js +235 -0
  14. package/lib/import/modules/content-types.d.ts +2 -0
  15. package/lib/import/modules/content-types.js +52 -13
  16. package/lib/import/modules/custom-roles.js +10 -10
  17. package/lib/import/modules/entries.d.ts +2 -0
  18. package/lib/import/modules/entries.js +41 -36
  19. package/lib/import/modules/environments.js +6 -6
  20. package/lib/import/modules/extensions.js +7 -7
  21. package/lib/import/modules/global-fields.d.ts +1 -1
  22. package/lib/import/modules/global-fields.js +10 -10
  23. package/lib/import/modules/labels.js +6 -6
  24. package/lib/import/modules/locales.d.ts +1 -1
  25. package/lib/import/modules/locales.js +8 -8
  26. package/lib/import/modules/marketplace-apps.js +6 -6
  27. package/lib/import/modules/personalize.js +2 -3
  28. package/lib/import/modules/stack.js +5 -5
  29. package/lib/import/modules/taxonomies.d.ts +26 -3
  30. package/lib/import/modules/taxonomies.js +180 -63
  31. package/lib/import/modules/variant-entries.js +5 -5
  32. package/lib/import/modules/webhooks.js +6 -6
  33. package/lib/import/modules/workflows.d.ts +1 -1
  34. package/lib/import/modules/workflows.js +7 -7
  35. package/lib/types/default-config.d.ts +6 -0
  36. package/lib/types/index.d.ts +37 -11
  37. package/lib/utils/asset-helper.js +1 -1
  38. package/lib/utils/common-helper.d.ts +1 -1
  39. package/lib/utils/common-helper.js +8 -7
  40. package/lib/utils/content-type-helper.d.ts +1 -1
  41. package/lib/utils/content-type-helper.js +3 -3
  42. package/lib/utils/extension-helper.js +5 -4
  43. package/lib/utils/file-helper.js +1 -1
  44. package/lib/utils/import-config-handler.js +7 -13
  45. package/lib/utils/import-path-resolver.js +2 -8
  46. package/lib/utils/logger.d.ts +1 -1
  47. package/lib/utils/logger.js +2 -2
  48. package/lib/utils/login-handler.d.ts +1 -1
  49. package/lib/utils/login-handler.js +4 -4
  50. package/lib/utils/marketplace-app-helper.js +9 -6
  51. package/lib/utils/taxonomies-helper.js +1 -1
  52. package/messages/index.json +10 -1
  53. package/oclif.manifest.json +4 -48
  54. package/package.json +15 -17
@@ -5,11 +5,13 @@ const node_path_1 = require("node:path");
5
5
  const values_1 = tslib_1.__importDefault(require("lodash/values"));
6
6
  const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
7
7
  const cli_utilities_1 = require("@contentstack/cli-utilities");
8
+ const constants_1 = require("../../constants");
8
9
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
9
10
  const utils_1 = require("../../utils");
10
11
  class ImportTaxonomies extends base_class_1.default {
11
12
  constructor({ importConfig, stackAPIClient }) {
12
13
  super({ importConfig, stackAPIClient });
14
+ this.isLocaleBasedStructure = false;
13
15
  this.createdTaxonomies = {};
14
16
  this.failedTaxonomies = {};
15
17
  this.createdTerms = {};
@@ -17,13 +19,14 @@ class ImportTaxonomies extends base_class_1.default {
17
19
  this.importConfig.context.module = utils_1.MODULE_CONTEXTS.TAXONOMIES;
18
20
  this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.TAXONOMIES];
19
21
  this.taxonomiesConfig = importConfig.modules.taxonomies;
20
- this.taxonomiesMapperDirPath = (0, node_path_1.join)(importConfig.backupDir, 'mapper', 'taxonomies');
21
- this.termsMapperDirPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'terms');
22
- this.taxonomiesFolderPath = (0, node_path_1.join)(importConfig.backupDir, this.taxonomiesConfig.dirName);
23
- this.taxSuccessPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'success.json');
24
- this.taxFailsPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, 'fails.json');
25
- this.termsSuccessPath = (0, node_path_1.join)(this.termsMapperDirPath, 'success.json');
26
- this.termsFailsPath = (0, node_path_1.join)(this.termsMapperDirPath, 'fails.json');
22
+ this.taxonomiesMapperDirPath = (0, node_path_1.join)(importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.TAXONOMIES);
23
+ this.termsMapperDirPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, constants_1.PATH_CONSTANTS.MAPPER_MODULES.TAXONOMY_TERMS);
24
+ this.taxonomiesFolderPath = (0, node_path_1.join)(importConfig.contentDir, this.taxonomiesConfig.dirName);
25
+ this.taxSuccessPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
26
+ this.taxFailsPath = (0, node_path_1.join)(this.taxonomiesMapperDirPath, constants_1.PATH_CONSTANTS.FILES.FAILS);
27
+ this.termsSuccessPath = (0, node_path_1.join)(this.termsMapperDirPath, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
28
+ this.termsFailsPath = (0, node_path_1.join)(this.termsMapperDirPath, constants_1.PATH_CONSTANTS.FILES.FAILS);
29
+ this.localesFilePath = (0, node_path_1.join)(importConfig.backupDir, importConfig.modules.locales.dirName, importConfig.modules.locales.fileName);
27
30
  }
28
31
  /**
29
32
  * @method start
@@ -37,14 +40,22 @@ class ImportTaxonomies extends base_class_1.default {
37
40
  cli_utilities_1.log.info('No taxonomies found to import', this.importConfig.context);
38
41
  return;
39
42
  }
40
- const progress = this.createSimpleProgress(this.currentModuleName, taxonomiesCount);
41
43
  await this.prepareMapperDirectories();
44
+ // Check if locale-based structure exists before import
45
+ this.isLocaleBasedStructure = this.detectAndScanLocaleStructure();
46
+ const progress = this.createSimpleProgress(this.currentModuleName, taxonomiesCount);
42
47
  progress.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT].IMPORTING);
43
48
  cli_utilities_1.log.debug('Starting taxonomies import', this.importConfig.context);
44
- await this.importTaxonomies();
49
+ if (this.isLocaleBasedStructure) {
50
+ cli_utilities_1.log.debug('Detected locale-based folder structure for taxonomies', this.importConfig.context);
51
+ await this.importTaxonomiesByLocale();
52
+ }
53
+ else {
54
+ cli_utilities_1.log.debug('Using legacy folder structure for taxonomies', this.importConfig.context);
55
+ await this.importTaxonomiesLegacy();
56
+ }
45
57
  this.createSuccessAndFailedFile();
46
- this.completeProgress(true);
47
- cli_utilities_1.log.success('Taxonomies imported successfully!', this.importConfig.context);
58
+ this.completeProgressWithMessage();
48
59
  }
49
60
  catch (error) {
50
61
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Taxonomies import failed');
@@ -57,83 +68,189 @@ class ImportTaxonomies extends base_class_1.default {
57
68
  * @async
58
69
  * @returns {Promise<any>} Promise<any>
59
70
  */
60
- async importTaxonomies() {
61
- cli_utilities_1.log.debug('Validating taxonomies data', this.importConfig.context);
62
- if (this.taxonomies === undefined || (0, isEmpty_1.default)(this.taxonomies)) {
63
- cli_utilities_1.log.info('No Taxonomies Found!', this.importConfig.context);
71
+ async importTaxonomies({ apiContent, localeCode }) {
72
+ if (!apiContent || (apiContent === null || apiContent === void 0 ? void 0 : apiContent.length) === 0) {
73
+ cli_utilities_1.log.debug('No taxonomies to import', this.importConfig.context);
64
74
  return;
65
75
  }
66
- const apiContent = (0, values_1.default)(this.taxonomies);
67
- cli_utilities_1.log.debug(`Starting to import ${apiContent.length} taxonomies`, this.importConfig.context);
68
- const onSuccess = ({ apiData }) => {
69
- var _a, _b, _c;
70
- const taxonomyUID = (_a = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _a === void 0 ? void 0 : _a.uid;
71
- const taxonomyName = (_b = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _b === void 0 ? void 0 : _b.name;
72
- const termsCount = Object.keys((apiData === null || apiData === void 0 ? void 0 : apiData.terms) || {}).length;
73
- this.createdTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
74
- this.createdTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
75
- (_c = this.progressManager) === null || _c === void 0 ? void 0 : _c.tick(true, null, `taxonomy: ${taxonomyName || taxonomyUID} (${termsCount} terms)`, utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
76
- cli_utilities_1.log.success(`Taxonomy '${taxonomyUID}' imported successfully!`, this.importConfig.context);
77
- cli_utilities_1.log.debug(`Taxonomy '${taxonomyName}' imported with ${termsCount} terms successfully!`, this.importConfig.context);
78
- };
79
- const onReject = ({ error, apiData }) => {
80
- var _a, _b, _c, _d;
81
- const taxonomyUID = (_a = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _a === void 0 ? void 0 : _a.uid;
82
- const taxonomyName = (_b = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _b === void 0 ? void 0 : _b.name;
83
- if ((error === null || error === void 0 ? void 0 : error.status) === 409 && (error === null || error === void 0 ? void 0 : error.statusText) === 'Conflict') {
84
- cli_utilities_1.log.info(`Taxonomy '${taxonomyUID}' already exists!`, this.importConfig.context);
85
- cli_utilities_1.log.debug(`Adding existing taxonomy '${taxonomyUID}' to created list`, this.importConfig.context);
86
- this.createdTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
87
- this.createdTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
88
- (_c = this.progressManager) === null || _c === void 0 ? void 0 : _c.tick(true, null, `taxonomy: ${taxonomyName || taxonomyUID} already exists`, utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
89
- }
90
- else {
91
- this.failedTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
92
- this.failedTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
93
- (_d = this.progressManager) === null || _d === void 0 ? void 0 : _d.tick(false, `taxonomy: ${taxonomyName || taxonomyUID}`, (error === null || error === void 0 ? void 0 : error.message) || 'Failed to import taxonomy', utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
94
- (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { taxonomyUID }), `Taxonomy '${taxonomyUID}' failed to be imported`);
95
- }
96
- };
97
- cli_utilities_1.log.debug(`Using concurrency limit: ${this.importConfig.fetchConcurrency || 2}`, this.importConfig.context);
76
+ const onSuccess = ({ apiData }) => this.handleSuccess(apiData, localeCode);
77
+ const onReject = ({ error, apiData }) => this.handleFailure(error, apiData, localeCode);
98
78
  await this.makeConcurrentCall({
99
79
  apiContent,
100
80
  processName: 'import taxonomies',
101
81
  apiParams: {
102
- serializeData: this.serializeTaxonomiesData.bind(this),
82
+ serializeData: this.serializeTaxonomy.bind(this),
103
83
  reject: onReject,
104
84
  resolve: onSuccess,
105
85
  entity: 'import-taxonomy',
106
86
  includeParamOnCompletion: true,
87
+ queryParam: {
88
+ locale: localeCode,
89
+ },
107
90
  },
108
91
  concurrencyLimit: this.importConfig.concurrency || this.importConfig.fetchConcurrency || 1,
109
92
  }, undefined, false);
110
- cli_utilities_1.log.debug('Taxonomies import process completed', this.importConfig.context);
111
93
  }
112
94
  /**
113
- * @method serializeTaxonomiesData
95
+ * Import taxonomies using legacy structure (taxonomies/{uid}.json)
96
+ */
97
+ async importTaxonomiesLegacy() {
98
+ const apiContent = (0, values_1.default)(this.taxonomies);
99
+ await this.importTaxonomies({ apiContent });
100
+ }
101
+ /**
102
+ * Import taxonomies using locale-based structure (taxonomies/{locale}/{uid}.json)
103
+ */
104
+ async importTaxonomiesByLocale() {
105
+ const locales = this.loadAvailableLocales();
106
+ const apiContent = (0, values_1.default)(this.taxonomies);
107
+ for (const localeCode of Object.keys(locales)) {
108
+ await this.importTaxonomies({ apiContent, localeCode });
109
+ }
110
+ }
111
+ handleSuccess(apiData, locale) {
112
+ var _a;
113
+ const { taxonomy, terms } = apiData || {};
114
+ const taxonomyUID = taxonomy === null || taxonomy === void 0 ? void 0 : taxonomy.uid;
115
+ const taxonomyName = taxonomy === null || taxonomy === void 0 ? void 0 : taxonomy.name;
116
+ const termsCount = Object.keys(terms || {}).length;
117
+ this.createdTaxonomies[taxonomyUID] = taxonomy;
118
+ this.createdTerms[taxonomyUID] = terms;
119
+ (_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `taxonomy: ${taxonomyName || taxonomyUID}`, null, utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
120
+ cli_utilities_1.log.success(`Taxonomy '${taxonomyUID}' imported successfully${locale ? ` for locale: ${locale}` : ''}!`, this.importConfig.context);
121
+ cli_utilities_1.log.debug(`Created taxonomy '${taxonomyName}' with ${termsCount} terms${locale ? ` for locale: ${locale}` : ''}`, this.importConfig.context);
122
+ }
123
+ handleFailure(error, apiData, locale) {
124
+ var _a, _b, _c, _d, _e, _f;
125
+ const taxonomyUID = (_a = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _a === void 0 ? void 0 : _a.uid;
126
+ const taxonomyName = (_b = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy) === null || _b === void 0 ? void 0 : _b.name;
127
+ if ((error === null || error === void 0 ? void 0 : error.status) === 409 && (error === null || error === void 0 ? void 0 : error.statusText) === 'Conflict') {
128
+ (_c = this.progressManager) === null || _c === void 0 ? void 0 : _c.tick(true, null, `taxonomy: ${taxonomyName || taxonomyUID} (already exists)`, utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
129
+ cli_utilities_1.log.info(`Taxonomy '${taxonomyUID}' already exists ${locale ? ` for locale: ${locale}` : ''}!`, this.importConfig.context);
130
+ this.createdTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
131
+ this.createdTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
132
+ return;
133
+ }
134
+ const errMsg = (error === null || error === void 0 ? void 0 : error.errorMessage) || ((_d = error === null || error === void 0 ? void 0 : error.errors) === null || _d === void 0 ? void 0 : _d.taxonomy) || ((_e = error === null || error === void 0 ? void 0 : error.errors) === null || _e === void 0 ? void 0 : _e.term) || (error === null || error === void 0 ? void 0 : error.message);
135
+ (_f = this.progressManager) === null || _f === void 0 ? void 0 : _f.tick(false, `taxonomy: ${taxonomyName || taxonomyUID}`, errMsg || 'Failed to import taxonomy', utils_1.PROCESS_NAMES.TAXONOMIES_IMPORT);
136
+ if (errMsg) {
137
+ cli_utilities_1.log.error(`Taxonomy '${taxonomyUID}' failed to import${locale ? ` for locale: ${locale}` : ''}! ${errMsg}`, this.importConfig.context);
138
+ }
139
+ else {
140
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { taxonomyUID, locale }), `Taxonomy '${taxonomyUID}' failed`);
141
+ }
142
+ this.failedTaxonomies[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.taxonomy;
143
+ this.failedTerms[taxonomyUID] = apiData === null || apiData === void 0 ? void 0 : apiData.terms;
144
+ }
145
+ /**
146
+ * @method serializeTaxonomy
114
147
  * @param {ApiOptions} apiOptions ApiOptions
115
148
  * @returns {ApiOptions} ApiOptions
116
149
  */
117
- serializeTaxonomiesData(apiOptions) {
118
- var _a, _b;
119
- const { apiData: taxonomyData } = apiOptions;
120
- cli_utilities_1.log.debug(`Serializing taxonomy: ${(_a = taxonomyData.taxonomy) === null || _a === void 0 ? void 0 : _a.name} (${(_b = taxonomyData.taxonomy) === null || _b === void 0 ? void 0 : _b.uid})`, this.importConfig.context);
121
- const taxonomyUID = taxonomyData === null || taxonomyData === void 0 ? void 0 : taxonomyData.uid;
122
- const filePath = (0, node_path_1.join)(this.taxonomiesFolderPath, `${taxonomyUID}.json`);
123
- cli_utilities_1.log.debug(`Looking for taxonomy file: ${filePath}`, this.importConfig.context);
124
- if (utils_1.fileHelper.fileExistsSync(filePath)) {
125
- const taxonomyDetails = utils_1.fsUtil.readFile(filePath, true);
126
- cli_utilities_1.log.debug(`Successfully loaded taxonomy details from ${filePath}`, this.importConfig.context);
150
+ serializeTaxonomy(apiOptions) {
151
+ const { apiData, queryParam: { locale }, } = apiOptions;
152
+ const taxonomyUID = apiData === null || apiData === void 0 ? void 0 : apiData.uid;
153
+ if (!taxonomyUID) {
154
+ cli_utilities_1.log.debug('No taxonomy UID provided for serialization', this.importConfig.context);
155
+ apiOptions.apiData = undefined;
156
+ return apiOptions;
157
+ }
158
+ const context = locale ? ` for locale: ${locale}` : '';
159
+ cli_utilities_1.log.debug(`Serializing taxonomy: ${taxonomyUID}${context}`, this.importConfig.context);
160
+ // Determine file path - if locale is provided, use it directly, otherwise search
161
+ const filePath = locale
162
+ ? (0, node_path_1.join)(this.taxonomiesFolderPath, locale, `${taxonomyUID}.json`)
163
+ : this.findTaxonomyFilePath(taxonomyUID);
164
+ if (!filePath || !utils_1.fileHelper.fileExistsSync(filePath)) {
165
+ cli_utilities_1.log.debug(`Taxonomy file not found for: ${taxonomyUID}${context}`, this.importConfig.context);
166
+ apiOptions.apiData = undefined;
167
+ return apiOptions;
168
+ }
169
+ const taxonomyDetails = this.loadTaxonomyFile(filePath);
170
+ if (taxonomyDetails) {
127
171
  const termCount = Object.keys((taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.terms) || {}).length;
128
- cli_utilities_1.log.debug(`Taxonomy has ${termCount} term entries`, this.importConfig.context);
129
- apiOptions.apiData = { filePath, taxonomy: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.taxonomy, terms: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.terms };
172
+ cli_utilities_1.log.debug(`Taxonomy has ${termCount} term entries${context}`, this.importConfig.context);
173
+ apiOptions.apiData = {
174
+ filePath,
175
+ taxonomy: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.taxonomy,
176
+ terms: taxonomyDetails === null || taxonomyDetails === void 0 ? void 0 : taxonomyDetails.terms,
177
+ };
130
178
  }
131
179
  else {
132
- cli_utilities_1.log.debug(`File does not exist for taxonomy: ${taxonomyUID}`, this.importConfig.context);
133
180
  apiOptions.apiData = undefined;
134
181
  }
135
182
  return apiOptions;
136
183
  }
184
+ loadTaxonomyFile(filePath) {
185
+ if (!utils_1.fileHelper.fileExistsSync(filePath)) {
186
+ cli_utilities_1.log.debug(`File does not exist: ${filePath}`, this.importConfig.context);
187
+ return undefined;
188
+ }
189
+ try {
190
+ const taxonomyDetails = utils_1.fsUtil.readFile(filePath, true);
191
+ cli_utilities_1.log.debug(`Successfully loaded taxonomy from: ${filePath}`, this.importConfig.context);
192
+ return taxonomyDetails;
193
+ }
194
+ catch (error) {
195
+ cli_utilities_1.log.debug(`Error loading taxonomy file: ${filePath}`, this.importConfig.context);
196
+ return undefined;
197
+ }
198
+ }
199
+ findTaxonomyFilePath(taxonomyUID) {
200
+ if (this.isLocaleBasedStructure) {
201
+ return this.findTaxonomyInLocaleFolders(taxonomyUID);
202
+ }
203
+ const legacyPath = (0, node_path_1.join)(this.taxonomiesFolderPath, `${taxonomyUID}.json`);
204
+ return utils_1.fileHelper.fileExistsSync(legacyPath) ? legacyPath : undefined;
205
+ }
206
+ findTaxonomyInLocaleFolders(taxonomyUID) {
207
+ const locales = this.loadAvailableLocales();
208
+ for (const localeCode of Object.keys(locales)) {
209
+ const filePath = (0, node_path_1.join)(this.taxonomiesFolderPath, localeCode, `${taxonomyUID}.json`);
210
+ if (utils_1.fileHelper.fileExistsSync(filePath)) {
211
+ return filePath;
212
+ }
213
+ }
214
+ return undefined;
215
+ }
216
+ loadAvailableLocales() {
217
+ var _a;
218
+ if (!utils_1.fileHelper.fileExistsSync(this.localesFilePath)) {
219
+ cli_utilities_1.log.debug('No locales file found', this.importConfig.context);
220
+ return {};
221
+ }
222
+ try {
223
+ const localesData = utils_1.fsUtil.readFile(this.localesFilePath, true);
224
+ const locales = {};
225
+ const masterCode = ((_a = this.importConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code) || 'en-us';
226
+ locales[masterCode] = masterCode;
227
+ for (const [, locale] of Object.entries(localesData || {})) {
228
+ if (locale === null || locale === void 0 ? void 0 : locale.code) {
229
+ locales[locale.code] = locale.code;
230
+ }
231
+ }
232
+ cli_utilities_1.log.debug(`Loaded ${Object.keys(locales).length} locales from file`, this.importConfig.context);
233
+ return locales;
234
+ }
235
+ catch (error) {
236
+ cli_utilities_1.log.debug('Error loading locales file', this.importConfig.context);
237
+ return {};
238
+ }
239
+ }
240
+ /**
241
+ * Detect if locale-based folder structure exists (taxonomies/{locale}/{uid}.json)
242
+ */
243
+ detectAndScanLocaleStructure() {
244
+ var _a;
245
+ const masterLocaleCode = ((_a = this.importConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code) || 'en-us';
246
+ const masterLocaleFolder = (0, node_path_1.join)(this.taxonomiesFolderPath, masterLocaleCode);
247
+ if (!utils_1.fileHelper.fileExistsSync(masterLocaleFolder)) {
248
+ cli_utilities_1.log.debug('No locale-based folder structure detected', this.importConfig.context);
249
+ return false;
250
+ }
251
+ cli_utilities_1.log.debug('Locale-based folder structure detected', this.importConfig.context);
252
+ return true;
253
+ }
137
254
  /**
138
255
  * create taxonomies success and fail in (mapper/taxonomies)
139
256
  * create terms success and fail in (mapper/taxonomies/terms)
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const path_1 = tslib_1.__importDefault(require("path"));
5
5
  const cli_utilities_1 = require("@contentstack/cli-utilities");
6
+ const constants_1 = require("../../constants");
6
7
  const cli_variants_1 = require("@contentstack/cli-variants");
7
8
  const utils_1 = require("../../utils");
8
9
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
@@ -13,7 +14,7 @@ class ImportVariantEntries extends base_class_1.default {
13
14
  this.config.context.module = utils_1.MODULE_CONTEXTS.VARIANT_ENTRIES;
14
15
  this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.VARIANT_ENTRIES];
15
16
  this.personalize = importConfig.modules.personalize;
16
- this.projectMapperFilePath = path_1.default.resolve((0, cli_utilities_1.sanitizePath)(this.config.data), 'mapper', (0, cli_utilities_1.sanitizePath)(this.personalize.dirName), 'projects', 'projects.json');
17
+ this.projectMapperFilePath = path_1.default.resolve((0, cli_utilities_1.sanitizePath)(this.config.backupDir), constants_1.PATH_CONSTANTS.MAPPER, (0, cli_utilities_1.sanitizePath)(this.personalize.dirName), 'projects', 'projects.json');
17
18
  }
18
19
  /**
19
20
  * @method start
@@ -34,8 +35,7 @@ class ImportVariantEntries extends base_class_1.default {
34
35
  progress.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.VARIANT_ENTRIES_IMPORT].IMPORTING, utils_1.PROCESS_NAMES.VARIANT_ENTRIES_IMPORT);
35
36
  cli_utilities_1.log.info('Starting variant entries import process', this.config.context);
36
37
  await this.importVariantEntries();
37
- this.completeProgress(true);
38
- cli_utilities_1.log.success('Variant entries imported successfully', this.config.context);
38
+ this.completeProgressWithMessage();
39
39
  }
40
40
  catch (error) {
41
41
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Variant entries import failed');
@@ -89,8 +89,8 @@ class ImportVariantEntries extends base_class_1.default {
89
89
  return [false, 0];
90
90
  }
91
91
  // Basic validation - check if data file exists
92
- const dataFilePath = path_1.default.resolve((0, cli_utilities_1.sanitizePath)(this.config.data), 'mapper', 'entries', 'data-for-variant-entry.json');
93
- const hasVariantData = utils_1.fileHelper.fileExistsSync(dataFilePath);
92
+ const varientEntriesMapperFilePath = path_1.default.resolve((0, cli_utilities_1.sanitizePath)(this.config.backupDir), 'mapper', 'entries', 'data-for-variant-entry.json');
93
+ const hasVariantData = utils_1.fileHelper.fileExistsSync(varientEntriesMapperFilePath);
94
94
  cli_utilities_1.log.debug(`Found valid personalize project: ${project.uid} with variant data: ${hasVariantData}`, this.config.context);
95
95
  // Return 0 count - let the variant module update it dynamically
96
96
  return [hasValidProject && hasVariantData, 0];
@@ -5,6 +5,7 @@ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
5
5
  const values_1 = tslib_1.__importDefault(require("lodash/values"));
6
6
  const node_path_1 = require("node:path");
7
7
  const cli_utilities_1 = require("@contentstack/cli-utilities");
8
+ const constants_1 = require("../../constants");
8
9
  const utils_1 = require("../../utils");
9
10
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
10
11
  class ImportWebhooks extends base_class_1.default {
@@ -13,11 +14,11 @@ class ImportWebhooks extends base_class_1.default {
13
14
  this.importConfig.context.module = utils_1.MODULE_CONTEXTS.WEBHOOKS;
14
15
  this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.WEBHOOKS];
15
16
  this.webhooksConfig = importConfig.modules.webhooks;
16
- this.mapperDirPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'webhooks');
17
+ this.mapperDirPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.WEBHOOKS);
17
18
  this.webhooksFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, this.webhooksConfig.dirName);
18
- this.webhookUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, 'uid-mapping.json');
19
- this.createdWebhooksPath = (0, node_path_1.join)(this.mapperDirPath, 'success.json');
20
- this.failedWebhooksPath = (0, node_path_1.join)(this.mapperDirPath, 'fails.json');
19
+ this.webhookUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
20
+ this.createdWebhooksPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
21
+ this.failedWebhooksPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.FAILS);
21
22
  this.webhooks = {};
22
23
  this.failedWebhooks = [];
23
24
  this.createdWebhooks = [];
@@ -40,8 +41,7 @@ class ImportWebhooks extends base_class_1.default {
40
41
  progress.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.WEBHOOKS_IMPORT].IMPORTING);
41
42
  await this.importWebhooks();
42
43
  this.processWebhookResults();
43
- this.completeProgress(true);
44
- cli_utilities_1.log.success('Webhooks have been imported successfully!', this.importConfig.context);
44
+ this.completeProgressWithMessage();
45
45
  }
46
46
  catch (error) {
47
47
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Webhooks import failed');
@@ -20,7 +20,7 @@ export default class ImportWorkflows extends BaseClass {
20
20
  start(): Promise<void>;
21
21
  getRoles(): Promise<void>;
22
22
  importWorkflows(): Promise<void>;
23
- updateNextAvailableStagesUid(workflow: Record<string, any>, newWorkflowStages: Record<string, any>[], oldWorkflowStages: Record<string, any>[]): Promise<import("@contentstack/management/types/stack/workflow").Workflow>;
23
+ updateNextAvailableStagesUid(workflow: Record<string, any>, newWorkflowStages: Record<string, any>[], oldWorkflowStages: Record<string, any>[]): Promise<any>;
24
24
  /**
25
25
  * @method serializeWorkflows
26
26
  * @param {ApiOptions} apiOptions ApiOptions
@@ -11,6 +11,7 @@ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
11
11
  const cloneDeep_1 = tslib_1.__importDefault(require("lodash/cloneDeep"));
12
12
  const findIndex_1 = tslib_1.__importDefault(require("lodash/findIndex"));
13
13
  const cli_utilities_1 = require("@contentstack/cli-utilities");
14
+ const constants_1 = require("../../constants");
14
15
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
15
16
  const utils_1 = require("../../utils");
16
17
  class ImportWorkflows extends base_class_1.default {
@@ -19,11 +20,11 @@ class ImportWorkflows extends base_class_1.default {
19
20
  this.importConfig.context.module = utils_1.MODULE_CONTEXTS.WORKFLOWS;
20
21
  this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.WORKFLOWS];
21
22
  this.workflowsConfig = importConfig.modules.workflows;
22
- this.mapperDirPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'workflows');
23
+ this.mapperDirPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.WORKFLOWS);
23
24
  this.workflowsFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, this.workflowsConfig.dirName);
24
- this.workflowUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, 'uid-mapping.json');
25
- this.createdWorkflowsPath = (0, node_path_1.join)(this.mapperDirPath, 'success.json');
26
- this.failedWorkflowsPath = (0, node_path_1.join)(this.mapperDirPath, 'fails.json');
25
+ this.workflowUidMapperPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
26
+ this.createdWorkflowsPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
27
+ this.failedWorkflowsPath = (0, node_path_1.join)(this.mapperDirPath, constants_1.PATH_CONSTANTS.FILES.FAILS);
27
28
  this.workflows = {};
28
29
  this.failedWebhooks = [];
29
30
  this.createdWorkflows = [];
@@ -61,8 +62,7 @@ class ImportWorkflows extends base_class_1.default {
61
62
  await this.importWorkflows();
62
63
  progress.completeProcess(utils_1.PROCESS_NAMES.WORKFLOWS_CREATE, true);
63
64
  this.processWorkflowResults();
64
- this.completeProgress(true);
65
- cli_utilities_1.log.success('Workflows have been imported successfully!', this.importConfig.context);
65
+ this.completeProgressWithMessage();
66
66
  }
67
67
  catch (error) {
68
68
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Workflows import failed');
@@ -142,7 +142,7 @@ class ImportWorkflows extends base_class_1.default {
142
142
  else {
143
143
  this.failedWebhooks.push(apiData);
144
144
  (_d = this.progressManager) === null || _d === void 0 ? void 0 : _d.tick(false, `workflow: ${name || uid}`, (error === null || error === void 0 ? void 0 : error.message) || 'Failed to import workflow', utils_1.PROCESS_NAMES.WORKFLOWS_CREATE);
145
- if (error.errors['workflow_stages.0.users']) {
145
+ if ((error === null || error === void 0 ? void 0 : error.errors) && error.errors['workflow_stages.0.users']) {
146
146
  cli_utilities_1.log.error("Failed to import Workflows as you've specified certain roles in the Stage transition and access rules section. We currently don't import roles to the stack.", this.importConfig.context);
147
147
  }
148
148
  else {
@@ -156,6 +156,12 @@ export default interface DefaultConfig {
156
156
  locale: string;
157
157
  } & AnyProperty;
158
158
  } & AnyProperty;
159
+ 'composable-studio': {
160
+ dirName: string;
161
+ fileName: string;
162
+ apiBaseUrl: string;
163
+ apiVersion: string;
164
+ };
159
165
  };
160
166
  languagesCode: string[];
161
167
  apis: {
@@ -26,7 +26,7 @@ export interface User {
26
26
  email: string;
27
27
  authtoken: string;
28
28
  }
29
- export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies' | 'personalize' | 'variant-entries';
29
+ export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies' | 'personalize' | 'variant-entries' | 'composable-studio';
30
30
  export type ModuleClassParams = {
31
31
  stackAPIClient: ReturnType<ContentstackClient['stack']>;
32
32
  importConfig: ImportConfig;
@@ -71,23 +71,49 @@ export interface TaxonomiesConfig {
71
71
  fileName: string;
72
72
  dependencies?: Modules[];
73
73
  }
74
- export { default as DefaultConfig } from './default-config';
75
- export { default as ImportConfig } from './import-config';
76
- export * from './entries';
77
- export * from './marketplace-app';
78
- export type ExtensionType = {
79
- uid: string;
80
- scope: Record<string, unknown>;
81
- title: string;
82
- };
74
+ export interface ComposableStudioConfig {
75
+ dirName: string;
76
+ fileName: string;
77
+ apiBaseUrl: string;
78
+ apiVersion: string;
79
+ }
80
+ export interface ComposableStudioProject {
81
+ name: string;
82
+ description: string;
83
+ canvasUrl: string;
84
+ connectedStackApiKey: string;
85
+ contentTypeUid: string;
86
+ organizationUid: string;
87
+ settings: {
88
+ configuration: {
89
+ environment: string;
90
+ locale: string;
91
+ };
92
+ };
93
+ uid?: string;
94
+ createdBy?: string;
95
+ updatedBy?: string;
96
+ deletedAt?: boolean;
97
+ createdAt?: string;
98
+ updatedAt?: string;
99
+ }
83
100
  export interface Context {
84
101
  command: string;
85
102
  module: string;
86
103
  userId: string | undefined;
87
- email?: string | undefined;
104
+ email: string | undefined;
88
105
  sessionId: string | undefined;
89
106
  clientId?: string | undefined;
90
107
  apiKey: string;
91
108
  orgId: string;
92
109
  authenticationMethod?: string;
93
110
  }
111
+ export { default as DefaultConfig } from './default-config';
112
+ export { default as ImportConfig } from './import-config';
113
+ export * from './entries';
114
+ export * from './marketplace-app';
115
+ export type ExtensionType = {
116
+ uid: string;
117
+ scope: Record<string, unknown>;
118
+ title: string;
119
+ };
@@ -34,7 +34,7 @@ const uploadAssetHelper = function (config, req, fsPath, RETRY) {
34
34
  cli_utilities_1.log.debug(`Uploading asset (attempt ${RETRY}/${MAX_RETRY_LIMIT}): ${fsPath}`);
35
35
  req.upload = fsPath;
36
36
  const stackAPIClient = APIClient.stack({
37
- api_key: config.target_stack,
37
+ api_key: config.apiKey,
38
38
  management_token: config.management_token,
39
39
  });
40
40
  stackAPIClient
@@ -1,6 +1,6 @@
1
1
  /*!
2
2
  * Contentstack Import
3
- * Copyright (c) 2024 Contentstack LLC
3
+ * Copyright (c) 2026 Contentstack LLC
4
4
  * MIT Licensed
5
5
  */
6
6
  import { ImportConfig } from '../types';
@@ -2,7 +2,7 @@
2
2
  /* eslint-disable no-console */
3
3
  /*!
4
4
  * Contentstack Import
5
- * Copyright (c) 2024 Contentstack LLC
5
+ * Copyright (c) 2026 Contentstack LLC
6
6
  * MIT Licensed
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
@@ -11,6 +11,7 @@ const tslib_1 = require("tslib");
11
11
  const _ = tslib_1.__importStar(require("lodash"));
12
12
  const path = tslib_1.__importStar(require("path"));
13
13
  const cli_utilities_1 = require("@contentstack/cli-utilities");
14
+ const constants_1 = require("../constants");
14
15
  const file_helper_1 = require("./file-helper");
15
16
  const config_1 = tslib_1.__importDefault(require("../config"));
16
17
  const promise_limit_1 = tslib_1.__importDefault(require("promise-limit"));
@@ -25,14 +26,14 @@ const initialization = (configData) => {
25
26
  exports.initialization = initialization;
26
27
  const validateConfig = (importConfig) => {
27
28
  cli_utilities_1.log.debug('Validating import configuration');
28
- if (importConfig.email && importConfig.password && !importConfig.target_stack) {
29
+ if (importConfig.email && importConfig.password && !importConfig.apiKey) {
29
30
  cli_utilities_1.log.debug('Target stack API token is required when using email/password authentication');
30
31
  return 'error';
31
32
  }
32
33
  else if (!importConfig.email &&
33
34
  !importConfig.password &&
34
35
  !importConfig.management_token &&
35
- importConfig.target_stack &&
36
+ importConfig.apiKey &&
36
37
  !(0, cli_utilities_1.isAuthenticated)()) {
37
38
  cli_utilities_1.log.debug('Authentication credentials missing - either management token or email/password required');
38
39
  return 'error';
@@ -70,7 +71,7 @@ const sanitizeStack = (importConfig) => {
70
71
  const newStackVersion = stackDetails.data.stack.settings.version;
71
72
  const newStackDate = new Date(newStackVersion).toString();
72
73
  cli_utilities_1.log.debug(`New stack version: ${newStackVersion} (${newStackDate})`);
73
- const stackFilePath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.data), (0, cli_utilities_1.sanitizePath)(importConfig.modules.stack.dirName), (0, cli_utilities_1.sanitizePath)(importConfig.modules.stack.fileName));
74
+ const stackFilePath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.contentDir), (0, cli_utilities_1.sanitizePath)(importConfig.modules.stack.dirName), (0, cli_utilities_1.sanitizePath)(importConfig.modules.stack.fileName));
74
75
  cli_utilities_1.log.debug(`Reading stack file from: ${stackFilePath}`);
75
76
  const oldStackDetails = (0, file_helper_1.readFileSync)(stackFilePath);
76
77
  if (!oldStackDetails || !oldStackDetails.settings || !oldStackDetails.settings.hasOwnProperty('version')) {
@@ -137,8 +138,8 @@ const field_rules_update = (importConfig, ctPath) => {
137
138
  for (let i = 0; i < fieldRuleConditionLength; i++) {
138
139
  if (schema.field_rules[k].conditions[i].operand_field === 'reference') {
139
140
  cli_utilities_1.log.debug(`Processing reference field rule condition`);
140
- let entryMapperPath = path.resolve(importConfig.data, 'mapper', 'entries');
141
- let entryUidMapperPath = path.join(entryMapperPath, 'uid-mapping.json');
141
+ let entryMapperPath = path.resolve(importConfig.contentDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.ENTRIES);
142
+ let entryUidMapperPath = path.join(entryMapperPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
142
143
  let fieldRulesValue = schema.field_rules[k].conditions[i].value;
143
144
  let fieldRulesArray = fieldRulesValue.split('.');
144
145
  let updatedValue = [];
@@ -158,7 +159,7 @@ const field_rules_update = (importConfig, ctPath) => {
158
159
  }
159
160
  }
160
161
  const stackAPIClient = client.stack({
161
- api_key: importConfig.target_stack,
162
+ api_key: importConfig.apiKey,
162
163
  management_token: importConfig.management_token,
163
164
  });
164
165
  let ctObj = stackAPIClient.contentType(schema.uid);
@@ -42,7 +42,7 @@ export declare const schemaTemplate: {
42
42
  };
43
43
  /*!
44
44
  * Contentstack Import
45
- * Copyright (c) 2024 Contentstack LLC
45
+ * Copyright (c) 2026 Contentstack LLC
46
46
  * MIT Licensed
47
47
  */
48
48
  export declare const suppressSchemaReference: (schema: any, flag: any) => void;
@@ -48,7 +48,7 @@ exports.schemaTemplate = {
48
48
  };
49
49
  /*!
50
50
  * Contentstack Import
51
- * Copyright (c) 2024 Contentstack LLC
51
+ * Copyright (c) 2026 Contentstack LLC
52
52
  * MIT Licensed
53
53
  */
54
54
  const suppressSchemaReference = function (schema, flag) {
@@ -128,7 +128,7 @@ const removeReferenceFields = async function (schema, flag = { supressed: false
128
128
  catch (error) {
129
129
  // Else warn and modify the schema object.
130
130
  isContentTypeError = true;
131
- cli_utilities_1.log.warn(`Content-type ${schema[i].reference_to[j]} does not exist. Removing the field from schema`);
131
+ cli_utilities_1.log.warn(`Content type ${schema[i].reference_to[j]} does not exist. Removing the field from schema...`);
132
132
  }
133
133
  }
134
134
  if (isContentTypeError) {
@@ -200,7 +200,7 @@ const updateFieldRules = function (contentType) {
200
200
  const field = contentType.schema[i];
201
201
  fieldDataTypeMap[field.uid] = field.data_type;
202
202
  }
203
- cli_utilities_1.log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields`);
203
+ cli_utilities_1.log.debug(`Created field data type mapping for ${Object.keys(fieldDataTypeMap).length} fields.`);
204
204
  const fieldRules = [...contentType.field_rules];
205
205
  let len = fieldRules.length;
206
206
  let removedRules = 0;