@contentstack/cli-cm-export 2.0.0-beta.1 → 2.0.0-beta.3

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.
@@ -2,21 +2,45 @@ import BaseClass from './base-class';
2
2
  import { ModuleClassParams } from '../../types';
3
3
  export default class ExportTaxonomies extends BaseClass {
4
4
  private taxonomies;
5
+ private taxonomiesByLocale;
5
6
  private taxonomiesConfig;
7
+ private isLocaleBasedExportSupported;
6
8
  private qs;
7
9
  taxonomiesFolderPath: string;
10
+ private localesFilePath;
8
11
  constructor({ exportConfig, stackAPIClient }: ModuleClassParams);
9
12
  start(): Promise<void>;
10
13
  /**
11
- * Fetch in the provided stack
12
- * @param {number} skip
13
- * @returns {Promise<any>}
14
+ * Process and export taxonomies for a specific locale
14
15
  */
15
- getAllTaxonomies(skip?: number): Promise<any>;
16
- sanitizeTaxonomiesAttribs(taxonomies: Record<string, any>[]): void;
16
+ processLocaleExport(localeCode: string): Promise<void>;
17
17
  /**
18
- * Export all taxonomies details using metadata(this.taxonomies) and write it into respective <taxonomy-uid>.json file
19
- * @returns {Promise<any>}
18
+ * Write taxonomies metadata file
20
19
  */
21
- exportTaxonomies(): Promise<any>;
20
+ writeTaxonomiesMetadata(): Promise<void>;
21
+ /**
22
+ * Fetch taxonomies
23
+ *
24
+ * @async
25
+ * @param {?string} [localeCode]
26
+ * @param {boolean} [checkLocaleSupport=false]
27
+ * @returns {Promise<void>}
28
+ */
29
+ fetchTaxonomies(localeCode?: string, checkLocaleSupport?: boolean): Promise<void>;
30
+ /**
31
+ * remove invalid keys and write data into taxonomies
32
+ * @function sanitizeTaxonomiesAttribs
33
+ * @param {Record<string, string>[]} taxonomies
34
+ * @param {?string} [localeCode]
35
+ */
36
+ sanitizeTaxonomiesAttribs(taxonomies: Record<string, string>[], localeCode?: string): void;
37
+ /**
38
+ * Export taxonomies - supports both locale-based and legacy export
39
+ */
40
+ exportTaxonomies(localeCode?: string): Promise<void>;
41
+ /**
42
+ * Get all locales to export
43
+ */
44
+ getLocalesToExport(): string[];
45
+ private isLocalePlanLimitationError;
22
46
  }
@@ -11,170 +11,245 @@ const utils_1 = require("../../utils");
11
11
  class ExportTaxonomies extends base_class_1.default {
12
12
  constructor({ exportConfig, stackAPIClient }) {
13
13
  super({ exportConfig, stackAPIClient });
14
+ this.isLocaleBasedExportSupported = true; // Flag to track if locale-based export is supported
14
15
  this.taxonomies = {};
16
+ this.taxonomiesByLocale = {};
15
17
  this.taxonomiesConfig = exportConfig.modules.taxonomies;
16
18
  this.qs = { include_count: true, limit: this.taxonomiesConfig.limit || 100, skip: 0 };
17
19
  this.applyQueryFilters(this.qs, 'taxonomies');
18
- this.exportConfig.context.module = utils_1.MODULE_CONTEXTS.TAXONOMIES;
19
- this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.TAXONOMIES];
20
+ this.exportConfig.context.module = 'taxonomies';
21
+ this.localesFilePath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.data), (0, cli_utilities_1.sanitizePath)(exportConfig.branchName || ''), (0, cli_utilities_1.sanitizePath)(exportConfig.modules.locales.dirName), (0, cli_utilities_1.sanitizePath)(exportConfig.modules.locales.fileName));
20
22
  }
21
23
  async start() {
22
24
  var _a;
23
- try {
24
- cli_utilities_1.log.debug('Starting taxonomies export process...', this.exportConfig.context);
25
- // Setup with loading spinner
26
- const [totalCount] = await this.withLoadingSpinner('TAXONOMIES: Analyzing taxonomy structure...', async () => {
27
- this.taxonomiesFolderPath = (0, node_path_1.resolve)(this.exportConfig.data, this.exportConfig.branchName || '', this.taxonomiesConfig.dirName);
28
- await utils_1.fsUtil.makeDirectory(this.taxonomiesFolderPath);
29
- // Get count first for progress tracking
30
- const countResponse = await this.stack
31
- .taxonomy()
32
- .query(Object.assign(Object.assign({}, this.qs), { include_count: true, limit: 1 }))
33
- .find();
34
- return [countResponse.count || 0];
35
- });
36
- if (totalCount === 0) {
37
- cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('TAXONOMY_NOT_FOUND'), this.exportConfig.context);
38
- return;
39
- }
40
- // Create nested progress manager
41
- const progress = this.createNestedProgress(this.currentModuleName);
42
- // Add sub-processes
43
- progress.addProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES, totalCount);
44
- progress.addProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, totalCount);
45
- // Fetch taxonomies
46
- progress
47
- .startProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES)
48
- .updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.FETCH_TAXONOMIES].FETCHING, utils_1.PROCESS_NAMES.FETCH_TAXONOMIES);
49
- await this.getAllTaxonomies();
50
- progress.completeProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES, true);
51
- const actualTaxonomyCount = (_a = Object.keys(this.taxonomies || {})) === null || _a === void 0 ? void 0 : _a.length;
52
- cli_utilities_1.log.debug(`Found ${actualTaxonomyCount} taxonomies to export (API reported ${totalCount})`, this.exportConfig.context);
53
- // Update progress for export step if counts differ
54
- if (actualTaxonomyCount !== totalCount && actualTaxonomyCount > 0) {
55
- // Remove the old process and add with correct count
56
- progress.addProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, actualTaxonomyCount);
57
- }
58
- // Export detailed taxonomies
59
- if (actualTaxonomyCount > 0) {
60
- progress
61
- .startProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS)
62
- .updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS].EXPORTING, utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS);
63
- await this.exportTaxonomies();
64
- progress.completeProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, true);
65
- }
66
- else {
67
- cli_utilities_1.log.info('No taxonomies found to export detailed information', this.exportConfig.context);
68
- }
69
- const taxonomyCount = Object.keys(this.taxonomies || {}).length;
70
- cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_COMPLETE', taxonomyCount), this.exportConfig.context);
71
- this.completeProgress(true);
25
+ cli_utilities_1.log.debug('Starting export process for taxonomies...', this.exportConfig.context);
26
+ //create taxonomies folder
27
+ this.taxonomiesFolderPath = (0, node_path_1.resolve)(this.exportConfig.data, this.exportConfig.branchName || '', this.taxonomiesConfig.dirName);
28
+ cli_utilities_1.log.debug(`Taxonomies folder path: '${this.taxonomiesFolderPath}'`, this.exportConfig.context);
29
+ await utils_1.fsUtil.makeDirectory(this.taxonomiesFolderPath);
30
+ cli_utilities_1.log.debug('Created taxonomies directory.', this.exportConfig.context);
31
+ const localesToExport = this.getLocalesToExport();
32
+ cli_utilities_1.log.debug(`Will attempt to export taxonomies for ${localesToExport.length} locale(s): ${localesToExport.join(', ')}`, this.exportConfig.context);
33
+ if (localesToExport.length === 0) {
34
+ cli_utilities_1.log.warn('No locales found to export', this.exportConfig.context);
35
+ return;
72
36
  }
73
- catch (error) {
74
- (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
75
- this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Taxonomies export failed');
37
+ // Test locale-based export support with master locale
38
+ const masterLocale = (_a = this.exportConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code;
39
+ await this.fetchTaxonomies(masterLocale, true);
40
+ if (!this.isLocaleBasedExportSupported) {
41
+ this.taxonomies = {};
42
+ this.taxonomiesByLocale = {};
43
+ // Fetch taxonomies without locale parameter
44
+ await this.fetchTaxonomies();
45
+ await this.exportTaxonomies();
46
+ await this.writeTaxonomiesMetadata();
47
+ }
48
+ else {
49
+ // Process all locales with locale-based export
50
+ cli_utilities_1.log.debug('Localization enabled, proceeding with locale-based export', this.exportConfig.context);
51
+ for (const localeCode of localesToExport) {
52
+ await this.fetchTaxonomies(localeCode);
53
+ await this.processLocaleExport(localeCode);
54
+ }
55
+ await this.writeTaxonomiesMetadata();
76
56
  }
57
+ cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_COMPLETE', (0, keys_1.default)(this.taxonomies || {}).length), this.exportConfig.context);
77
58
  }
78
59
  /**
79
- * Fetch in the provided stack
80
- * @param {number} skip
81
- * @returns {Promise<any>}
60
+ * Process and export taxonomies for a specific locale
82
61
  */
83
- async getAllTaxonomies(skip = 0) {
84
- var _a, _b;
85
- if (skip) {
86
- this.qs.skip = skip;
87
- cli_utilities_1.log.debug(`Fetching taxonomies with skip: ${skip}`, this.exportConfig.context);
62
+ async processLocaleExport(localeCode) {
63
+ const localeTaxonomies = this.taxonomiesByLocale[localeCode];
64
+ if ((localeTaxonomies === null || localeTaxonomies === void 0 ? void 0 : localeTaxonomies.size) > 0) {
65
+ cli_utilities_1.log.info(`Found ${localeTaxonomies.size} taxonomies for locale: ${localeCode}`, this.exportConfig.context);
66
+ await this.exportTaxonomies(localeCode);
88
67
  }
89
68
  else {
90
- cli_utilities_1.log.debug('Fetching taxonomies with initial query', this.exportConfig.context);
69
+ cli_utilities_1.log.debug(`No taxonomies found for locale: ${localeCode}`, this.exportConfig.context);
91
70
  }
92
- cli_utilities_1.log.debug(`Query parameters: ${JSON.stringify(this.qs)}`, this.exportConfig.context);
93
- let taxonomyResult = await this.stack.taxonomy().query(this.qs).find();
94
- cli_utilities_1.log.debug(`Fetched ${((_a = taxonomyResult.items) === null || _a === void 0 ? void 0 : _a.length) || 0} taxonomies out of total ${taxonomyResult.count}`, this.exportConfig.context);
95
- if ((taxonomyResult === null || taxonomyResult === void 0 ? void 0 : taxonomyResult.items) && ((_b = taxonomyResult === null || taxonomyResult === void 0 ? void 0 : taxonomyResult.items) === null || _b === void 0 ? void 0 : _b.length) > 0) {
96
- cli_utilities_1.log.debug(`Processing ${taxonomyResult.items.length} taxonomies`, this.exportConfig.context);
97
- this.sanitizeTaxonomiesAttribs(taxonomyResult.items);
98
- skip += this.taxonomiesConfig.limit;
99
- if (skip >= taxonomyResult.count) {
100
- cli_utilities_1.log.debug('Completed fetching all taxonomies', this.exportConfig.context);
101
- return;
102
- }
103
- cli_utilities_1.log.debug(`Continuing to fetch taxonomies with skip: ${skip}`, this.exportConfig.context);
104
- return await this.getAllTaxonomies(skip);
105
- }
106
- else {
71
+ }
72
+ /**
73
+ * Write taxonomies metadata file
74
+ */
75
+ async writeTaxonomiesMetadata() {
76
+ if (!this.taxonomies || (0, isEmpty_1.default)(this.taxonomies)) {
107
77
  cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('TAXONOMY_NOT_FOUND'), this.exportConfig.context);
78
+ return;
108
79
  }
80
+ const taxonomiesFilePath = (0, node_path_1.resolve)(this.taxonomiesFolderPath, 'taxonomies.json');
81
+ cli_utilities_1.log.debug(`Writing taxonomies metadata to: ${taxonomiesFilePath}`, this.exportConfig.context);
82
+ utils_1.fsUtil.writeFile(taxonomiesFilePath, this.taxonomies);
109
83
  }
110
- sanitizeTaxonomiesAttribs(taxonomies) {
84
+ /**
85
+ * Fetch taxonomies
86
+ *
87
+ * @async
88
+ * @param {?string} [localeCode]
89
+ * @param {boolean} [checkLocaleSupport=false]
90
+ * @returns {Promise<void>}
91
+ */
92
+ async fetchTaxonomies(localeCode, checkLocaleSupport = false) {
111
93
  var _a;
112
- cli_utilities_1.log.debug(`Sanitizing ${taxonomies.length} taxonomies`, this.exportConfig.context);
113
- for (let index = 0; index < (taxonomies === null || taxonomies === void 0 ? void 0 : taxonomies.length); index++) {
114
- const taxonomy = taxonomies[index];
115
- const taxonomyUid = taxonomy.uid;
116
- const taxonomyName = taxonomy === null || taxonomy === void 0 ? void 0 : taxonomy.name;
117
- cli_utilities_1.log.debug(`Processing taxonomy: ${taxonomyName} (${taxonomyUid})`, this.exportConfig.context);
118
- if (this.taxonomiesConfig.invalidKeys && this.taxonomiesConfig.invalidKeys.length > 0) {
119
- this.taxonomies[taxonomyUid] = (0, omit_1.default)(taxonomy, this.taxonomiesConfig.invalidKeys);
94
+ let skip = 0;
95
+ const localeInfo = localeCode ? `for locale: ${localeCode}` : '';
96
+ if (localeCode && !this.taxonomiesByLocale[localeCode]) {
97
+ this.taxonomiesByLocale[localeCode] = new Set();
98
+ }
99
+ do {
100
+ const queryParams = Object.assign(Object.assign({}, this.qs), { skip });
101
+ if (localeCode) {
102
+ queryParams.locale = localeCode;
120
103
  }
121
- else {
122
- this.taxonomies[taxonomyUid] = taxonomy;
104
+ cli_utilities_1.log.debug(`Fetching taxonomies ${localeInfo} with skip: ${skip}`, this.exportConfig.context);
105
+ try {
106
+ const data = await this.stack.taxonomy().query(queryParams).find();
107
+ const { items, count } = data;
108
+ const taxonomiesCount = (_a = count !== null && count !== void 0 ? count : items === null || items === void 0 ? void 0 : items.length) !== null && _a !== void 0 ? _a : 0;
109
+ cli_utilities_1.log.debug(`Fetched ${(items === null || items === void 0 ? void 0 : items.length) || 0} taxonomies out of total ${taxonomiesCount} ${localeInfo}`, this.exportConfig.context);
110
+ if (!(items === null || items === void 0 ? void 0 : items.length)) {
111
+ cli_utilities_1.log.debug(`No taxonomies found ${localeInfo}`, this.exportConfig.context);
112
+ break;
113
+ }
114
+ // Check localization support
115
+ if (checkLocaleSupport && localeCode && skip === 0 && !items[0].locale) {
116
+ cli_utilities_1.log.debug('API does not support locale-based taxonomy export', this.exportConfig.context);
117
+ this.isLocaleBasedExportSupported = false;
118
+ }
119
+ this.sanitizeTaxonomiesAttribs(items, localeCode);
120
+ skip += this.qs.limit || 100;
121
+ if (skip >= taxonomiesCount) {
122
+ cli_utilities_1.log.debug(`Completed fetching all taxonomies ${localeInfo}`, this.exportConfig.context);
123
+ break;
124
+ }
125
+ }
126
+ catch (error) {
127
+ cli_utilities_1.log.debug(`Error fetching taxonomies ${localeInfo}`, this.exportConfig.context);
128
+ if (checkLocaleSupport && this.isLocalePlanLimitationError(error)) {
129
+ cli_utilities_1.log.debug('Taxonomy localization is not included in your plan. Falling back to non-localized export.', this.exportConfig.context);
130
+ this.isLocaleBasedExportSupported = false;
131
+ }
132
+ else if (checkLocaleSupport) {
133
+ cli_utilities_1.log.debug('Locale-based taxonomy export not supported, will use legacy method', this.exportConfig.context);
134
+ this.isLocaleBasedExportSupported = false;
135
+ }
136
+ else {
137
+ // Log actual errors during normal fetch (not locale check)
138
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.exportConfig.context), (localeCode && { locale: localeCode })));
139
+ }
140
+ // Break to avoid infinite retry loop on errors
141
+ break;
142
+ }
143
+ } while (true);
144
+ }
145
+ /**
146
+ * remove invalid keys and write data into taxonomies
147
+ * @function sanitizeTaxonomiesAttribs
148
+ * @param {Record<string, string>[]} taxonomies
149
+ * @param {?string} [localeCode]
150
+ */
151
+ sanitizeTaxonomiesAttribs(taxonomies, localeCode) {
152
+ const localeInfo = localeCode ? ` for locale: ${localeCode}` : '';
153
+ cli_utilities_1.log.debug(`Processing ${taxonomies.length} taxonomies${localeInfo}`, this.exportConfig.context);
154
+ for (const taxonomy of taxonomies) {
155
+ const taxonomyUID = taxonomy.uid;
156
+ const taxonomyName = taxonomy.name;
157
+ cli_utilities_1.log.debug(`Processing taxonomy: ${taxonomyName} (${taxonomyUID})${localeInfo}`, this.exportConfig.context);
158
+ // Store taxonomy metadata (only once per taxonomy)
159
+ if (!this.taxonomies[taxonomyUID]) {
160
+ this.taxonomies[taxonomyUID] = (0, omit_1.default)(taxonomy, this.taxonomiesConfig.invalidKeys);
161
+ }
162
+ // Track taxonomy for this locale
163
+ if (localeCode) {
164
+ this.taxonomiesByLocale[localeCode].add(taxonomyUID);
123
165
  }
124
- // Track progress for each taxonomy
125
- (_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `taxonomy: ${taxonomyName || taxonomyUid}`, null, utils_1.PROCESS_NAMES.FETCH_TAXONOMIES);
126
166
  }
127
- cli_utilities_1.log.debug(`Sanitization complete. Total taxonomies processed: ${Object.keys(this.taxonomies || {}).length}`, this.exportConfig.context);
167
+ cli_utilities_1.log.debug(`Processing complete${localeInfo}. Total taxonomies processed: ${(0, keys_1.default)(this.taxonomies).length}`, this.exportConfig.context);
128
168
  }
129
169
  /**
130
- * Export all taxonomies details using metadata(this.taxonomies) and write it into respective <taxonomy-uid>.json file
131
- * @returns {Promise<any>}
170
+ * Export taxonomies - supports both locale-based and legacy export
132
171
  */
133
- async exportTaxonomies() {
134
- var _a;
135
- cli_utilities_1.log.debug(`Exporting ${(_a = Object.keys(this.taxonomies || {})) === null || _a === void 0 ? void 0 : _a.length} taxonomies with detailed information`, this.exportConfig.context);
136
- if ((0, isEmpty_1.default)(this.taxonomies)) {
137
- cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('TAXONOMY_NOT_FOUND'), this.exportConfig.context);
172
+ async exportTaxonomies(localeCode) {
173
+ const taxonomiesUID = localeCode ? Array.from(this.taxonomiesByLocale[localeCode] || []) : (0, keys_1.default)(this.taxonomies);
174
+ const localeInfo = localeCode ? ` for locale: ${localeCode}` : '';
175
+ if (taxonomiesUID.length === 0) {
176
+ cli_utilities_1.log.debug(`No taxonomies to export${localeInfo}`, this.exportConfig.context);
138
177
  return;
139
178
  }
179
+ cli_utilities_1.log.debug(`Exporting detailed data for ${taxonomiesUID.length} taxonomies${localeInfo}`, this.exportConfig.context);
180
+ const exportFolderPath = localeCode ? (0, node_path_1.resolve)(this.taxonomiesFolderPath, localeCode) : this.taxonomiesFolderPath;
181
+ if (localeCode) {
182
+ await utils_1.fsUtil.makeDirectory(exportFolderPath);
183
+ cli_utilities_1.log.debug(`Created locale folder: ${exportFolderPath}`, this.exportConfig.context);
184
+ }
140
185
  const onSuccess = ({ response, uid }) => {
141
- var _a, _b;
142
- const taxonomyName = (_a = this.taxonomies[uid]) === null || _a === void 0 ? void 0 : _a.name;
143
- const filePath = (0, node_path_1.resolve)(this.taxonomiesFolderPath, `${uid}.json`);
144
- cli_utilities_1.log.debug(`Writing detailed taxonomy to: ${filePath}`, this.exportConfig.context);
186
+ const filePath = (0, node_path_1.resolve)(exportFolderPath, `${uid}.json`);
187
+ cli_utilities_1.log.debug(`Writing detailed taxonomy data to: ${filePath}`, this.exportConfig.context);
145
188
  utils_1.fsUtil.writeFile(filePath, response);
146
- // Track progress for each exported taxonomy
147
- (_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.tick(true, `taxonomy: ${taxonomyName || uid}`, null, utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS);
148
- cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_SUCCESS', taxonomyName || uid), this.exportConfig.context);
189
+ cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_SUCCESS', uid), this.exportConfig.context);
149
190
  };
150
191
  const onReject = ({ error, uid }) => {
151
- var _a, _b;
152
- const taxonomyName = (_a = this.taxonomies[uid]) === null || _a === void 0 ? void 0 : _a.name;
153
- // Track failure
154
- (_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.tick(false, `taxonomy: ${taxonomyName || uid}`, (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS].FAILED, utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS);
155
- (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.exportConfig.context), { uid }), cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_FAILED', taxonomyName || uid));
192
+ cli_utilities_1.log.debug(`Failed to export detailed data for taxonomy: ${uid}${localeInfo}`, this.exportConfig.context);
193
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign(Object.assign({}, this.exportConfig.context), { uid }), (localeCode && { locale: localeCode })));
156
194
  };
157
- const taxonomyUids = (0, keys_1.default)(this.taxonomies);
158
- cli_utilities_1.log.debug(`Starting detailed export for ${taxonomyUids.length} taxonomies`, this.exportConfig.context);
159
- // Export each taxonomy individually
160
- for (const uid of taxonomyUids) {
161
- try {
162
- cli_utilities_1.log.debug(`Exporting detailed taxonomy: ${uid}`, this.exportConfig.context);
163
- await this.makeAPICall({
164
- module: 'export-taxonomy',
165
- uid,
166
- resolve: onSuccess,
167
- reject: onReject,
168
- });
195
+ for (const taxonomyUID of taxonomiesUID) {
196
+ cli_utilities_1.log.debug(`Processing detailed export for taxonomy: ${taxonomyUID}${localeInfo}`, this.exportConfig.context);
197
+ const exportParams = { format: 'json' };
198
+ if (localeCode) {
199
+ exportParams.locale = localeCode;
200
+ if (this.qs.include_fallback !== undefined)
201
+ exportParams.include_fallback = this.qs.include_fallback;
202
+ if (this.qs.fallback_locale)
203
+ exportParams.fallback_locale = this.qs.fallback_locale;
169
204
  }
170
- catch (error) {
171
- onReject({ error, uid });
205
+ if (this.qs.branch)
206
+ exportParams.branch = this.qs.branch;
207
+ await this.makeAPICall({
208
+ reject: onReject,
209
+ resolve: onSuccess,
210
+ uid: taxonomyUID,
211
+ module: 'export-taxonomy',
212
+ queryParam: exportParams,
213
+ });
214
+ }
215
+ cli_utilities_1.log.debug(`Completed detailed taxonomy export process${localeInfo}`, this.exportConfig.context);
216
+ }
217
+ /**
218
+ * Get all locales to export
219
+ */
220
+ getLocalesToExport() {
221
+ var _a;
222
+ cli_utilities_1.log.debug('Determining locales to export...', this.exportConfig.context);
223
+ const masterLocaleCode = ((_a = this.exportConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code) || 'en-us';
224
+ const localeSet = new Set([masterLocaleCode]);
225
+ try {
226
+ const locales = utils_1.fsUtil.readFile(this.localesFilePath);
227
+ if (locales && (0, keys_1.default)(locales || {}).length > 0) {
228
+ cli_utilities_1.log.debug(`Loaded ${(0, keys_1.default)(locales || {}).length} locales from ${this.localesFilePath}`, this.exportConfig.context);
229
+ for (const localeUid of (0, keys_1.default)(locales)) {
230
+ const localeCode = locales[localeUid].code;
231
+ if (localeCode && !localeSet.has(localeCode)) {
232
+ localeSet.add(localeCode);
233
+ cli_utilities_1.log.debug(`Added locale: ${localeCode} (uid: ${localeUid})`, this.exportConfig.context);
234
+ }
235
+ }
236
+ }
237
+ else {
238
+ cli_utilities_1.log.debug(`No locales found in ${this.localesFilePath}`, this.exportConfig.context);
172
239
  }
173
240
  }
174
- // Write the taxonomies index file
175
- const taxonomiesFilePath = (0, node_path_1.resolve)(this.taxonomiesFolderPath, this.taxonomiesConfig.fileName);
176
- cli_utilities_1.log.debug(`Writing taxonomies index to: ${taxonomiesFilePath}`, this.exportConfig.context);
177
- utils_1.fsUtil.writeFile(taxonomiesFilePath, this.taxonomies);
241
+ catch (error) {
242
+ cli_utilities_1.log.warn(`Failed to read locales file: ${this.localesFilePath}`, this.exportConfig.context);
243
+ }
244
+ const localesToExport = Array.from(localeSet);
245
+ cli_utilities_1.log.debug(`Total unique locales to export: ${localesToExport.length}`, this.exportConfig.context);
246
+ return localesToExport;
247
+ }
248
+ isLocalePlanLimitationError(error) {
249
+ var _a, _b;
250
+ return ((error === null || error === void 0 ? void 0 : error.status) === 403 &&
251
+ ((_b = (_a = error === null || error === void 0 ? void 0 : error.errors) === null || _a === void 0 ? void 0 : _a.taxonomies) === null || _b === void 0 ? void 0 : _b.some((msg) => msg.toLowerCase().includes('taxonomy localization') &&
252
+ msg.toLowerCase().includes('not included in your plan'))));
178
253
  }
179
254
  }
180
255
  exports.default = ExportTaxonomies;
@@ -140,7 +140,7 @@ class ExportWorkFlows extends base_class_1.default {
140
140
  .catch((err) => {
141
141
  cli_utilities_1.log.debug(`Failed to fetch role data for UID: ${roleUid}`, this.exportConfig.context);
142
142
  (0, cli_utilities_1.handleAndLogError)(err, Object.assign({}, this.exportConfig.context));
143
- throw err;
143
+ return undefined; // Return undefined instead of throwing to handle gracefully
144
144
  });
145
145
  }
146
146
  }
@@ -147,6 +147,12 @@ export default interface DefaultConfig {
147
147
  fileName: string;
148
148
  dependencies?: Modules[];
149
149
  };
150
+ 'composable-studio': {
151
+ dirName: string;
152
+ fileName: string;
153
+ apiBaseUrl: string;
154
+ apiVersion: string;
155
+ };
150
156
  masterLocale: {
151
157
  dirName: string;
152
158
  fileName: string;
@@ -26,7 +26,7 @@ export interface Region {
26
26
  cda: string;
27
27
  uiHost: 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';
29
+ export type Modules = 'stack' | 'assets' | 'locales' | 'environments' | 'extensions' | 'webhooks' | 'global-fields' | 'entries' | 'content-types' | 'custom-roles' | 'workflows' | 'labels' | 'marketplace-apps' | 'taxonomies' | 'personalize' | 'composable-studio';
30
30
  export type ModuleClassParams = {
31
31
  stackAPIClient: ReturnType<ContentstackClient['stack']>;
32
32
  exportConfig: ExportConfig;
@@ -96,6 +96,32 @@ export interface StackConfig {
96
96
  dependencies?: Modules[];
97
97
  limit?: number;
98
98
  }
99
+ export interface ComposableStudioConfig {
100
+ dirName: string;
101
+ fileName: string;
102
+ apiBaseUrl: string;
103
+ apiVersion: string;
104
+ }
105
+ export interface ComposableStudioProject {
106
+ name: string;
107
+ description: string;
108
+ canvasUrl: string;
109
+ connectedStackApiKey: string;
110
+ contentTypeUid: string;
111
+ organizationUid: string;
112
+ settings: {
113
+ configuration: {
114
+ environment: string;
115
+ locale: string;
116
+ };
117
+ };
118
+ createdBy: string;
119
+ updatedBy: string;
120
+ deletedAt: boolean;
121
+ createdAt: string;
122
+ updatedAt: string;
123
+ uid: string;
124
+ }
99
125
  export interface Context {
100
126
  command: string;
101
127
  module: string;
@@ -26,7 +26,7 @@ const login = async (config) => {
26
26
  return config;
27
27
  }
28
28
  else {
29
- cli_utilities_1.log.error(`Failed to login, Invalid credentials`, config.context);
29
+ cli_utilities_1.log.error(`Failed to log in!`, config.context);
30
30
  process.exit(1);
31
31
  }
32
32
  }
@@ -16,14 +16,14 @@ const setupConfig = async (exportCmdFlags) => {
16
16
  cli_utilities_1.log.debug('Setting up export configuration');
17
17
  // setup the config
18
18
  if (exportCmdFlags['config']) {
19
- cli_utilities_1.log.debug('Loading external configuration file', { configFile: exportCmdFlags['config'] });
19
+ cli_utilities_1.log.debug('Loading external configuration file...', { configFile: exportCmdFlags['config'] });
20
20
  const externalConfig = await (0, file_helper_1.readFile)(exportCmdFlags['config']);
21
21
  config = merge_1.default.recursive(config, externalConfig);
22
22
  }
23
23
  config.exportDir = (0, cli_utilities_1.sanitizePath)(exportCmdFlags['data'] || exportCmdFlags['data-dir'] || config.data || (await (0, interactive_1.askExportDir)()));
24
24
  const pattern = /[*$%#<>{}!&?]/g;
25
25
  if (pattern.test(config.exportDir)) {
26
- cli_utilities_1.cliux.print(`\nPlease add a directory path without any of the special characters: (*,&,{,},[,],$,%,<,>,?,!)`, {
26
+ cli_utilities_1.cliux.print(`\nPlease enter a directory path without any special characters: (*,&,{,},[,],$,%,<,>,?,!)`, {
27
27
  color: 'yellow',
28
28
  });
29
29
  config.exportDir = (0, cli_utilities_1.sanitizePath)(await (0, interactive_1.askExportDir)());
@@ -40,7 +40,7 @@ const setupConfig = async (exportCmdFlags) => {
40
40
  config.apiKey = apiKey;
41
41
  authenticationMethod = 'Management Token';
42
42
  if (!config.management_token) {
43
- cli_utilities_1.log.debug('Management token not found for alias', { alias: managementTokenAlias });
43
+ cli_utilities_1.log.debug('Management token not found for alias!', { alias: managementTokenAlias });
44
44
  throw new Error(`No management token found on given alias ${managementTokenAlias}`);
45
45
  }
46
46
  cli_utilities_1.log.debug('Management token configuration successful');
@@ -73,7 +73,7 @@ const setupConfig = async (exportCmdFlags) => {
73
73
  config.apiKey =
74
74
  exportCmdFlags['stack-uid'] || exportCmdFlags['stack-api-key'] || config.source_stack || (await (0, interactive_1.askAPIKey)());
75
75
  if (typeof config.apiKey !== 'string') {
76
- cli_utilities_1.log.debug('Invalid API key received', { apiKey: config.apiKey });
76
+ cli_utilities_1.log.debug('Invalid API key received!', { apiKey: config.apiKey });
77
77
  throw new Error('Invalid API key received');
78
78
  }
79
79
  }
@@ -123,7 +123,7 @@ const setupConfig = async (exportCmdFlags) => {
123
123
  cli_utilities_1.configHandler.set('log.progressSupportedModule', 'export');
124
124
  // Add authentication details to config for context tracking
125
125
  config.authenticationMethod = authenticationMethod;
126
- cli_utilities_1.log.debug('Export configuration setup completed', Object.assign({}, config));
126
+ cli_utilities_1.log.debug('Export configuration setup completed.', Object.assign({}, config));
127
127
  return config;
128
128
  };
129
129
  exports.default = setupConfig;
@@ -51,7 +51,7 @@ const readLargeFile = function (filePath, options = {}) {
51
51
  resolve(data);
52
52
  });
53
53
  parseStream.on('error', (error) => {
54
- console.log('error', error);
54
+ console.log('Error', error);
55
55
  reject(error);
56
56
  });
57
57
  readStream.pipe(parseStream);
@@ -22,10 +22,8 @@ async function createNodeCryptoInstance(config) {
22
22
  if (config.forceStopMarketplaceAppsPrompt) {
23
23
  cryptoArgs['encryptionKey'] = config.marketplaceAppEncryptionKey;
24
24
  }
25
- else if (config.marketplaceAppEncryptionKey) {
26
- cryptoArgs['encryptionKey'] = config.marketplaceAppEncryptionKey;
27
- }
28
25
  else {
26
+ // Always prompt when forceStopMarketplaceAppsPrompt is false, using existing key as default
29
27
  cli_utilities_1.cliux.print('');
30
28
  cryptoArgs['encryptionKey'] = await askEncryptionKey(config);
31
29
  cli_utilities_1.cliux.print('');