@contentstack/cli-cm-export 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.
- package/LICENSE +1 -1
- package/README.md +11 -65
- package/lib/commands/cm/stacks/export.d.ts +0 -1
- package/lib/commands/cm/stacks/export.js +12 -37
- package/lib/config/index.js +7 -0
- package/lib/constants/index.d.ts +57 -0
- package/lib/constants/index.js +59 -0
- package/lib/export/module-exporter.js +3 -2
- package/lib/export/modules/assets.js +5 -5
- package/lib/export/modules/base-class.d.ts +17 -0
- package/lib/export/modules/base-class.js +29 -1
- package/lib/export/modules/composable-studio.d.ts +15 -0
- package/lib/export/modules/composable-studio.js +87 -0
- package/lib/export/modules/content-types.js +6 -8
- package/lib/export/modules/custom-roles.js +2 -2
- package/lib/export/modules/entries.d.ts +1 -1
- package/lib/export/modules/entries.js +18 -19
- package/lib/export/modules/environments.js +2 -3
- package/lib/export/modules/extensions.js +2 -3
- package/lib/export/modules/global-fields.js +8 -5
- package/lib/export/modules/labels.js +2 -3
- package/lib/export/modules/locales.js +2 -3
- package/lib/export/modules/marketplace-apps.js +36 -25
- package/lib/export/modules/personalize.js +1 -2
- package/lib/export/modules/stack.js +29 -29
- package/lib/export/modules/taxonomies.d.ts +52 -8
- package/lib/export/modules/taxonomies.js +278 -104
- package/lib/export/modules/webhooks.js +2 -3
- package/lib/export/modules/workflows.js +3 -4
- package/lib/types/default-config.d.ts +6 -0
- package/lib/types/index.d.ts +27 -2
- package/lib/utils/basic-login.d.ts +1 -1
- package/lib/utils/basic-login.js +5 -5
- package/lib/utils/common-helper.d.ts +1 -1
- package/lib/utils/common-helper.js +4 -4
- package/lib/utils/export-config-handler.js +10 -13
- package/lib/utils/file-helper.js +1 -1
- package/lib/utils/logger.d.ts +1 -1
- package/lib/utils/logger.js +2 -2
- package/lib/utils/marketplace-app-helper.js +2 -4
- package/messages/index.json +73 -67
- package/oclif.manifest.json +4 -42
- package/package.json +18 -15
|
@@ -11,63 +11,45 @@ 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
20
|
this.exportConfig.context.module = utils_1.MODULE_CONTEXTS.TAXONOMIES;
|
|
19
21
|
this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.TAXONOMIES];
|
|
22
|
+
this.localesFilePath = (0, node_path_1.resolve)((0, cli_utilities_1.sanitizePath)(exportConfig.exportDir), (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
23
|
}
|
|
21
24
|
async start() {
|
|
22
25
|
var _a;
|
|
23
26
|
try {
|
|
24
|
-
cli_utilities_1.log.debug('Starting
|
|
25
|
-
|
|
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
|
-
});
|
|
27
|
+
cli_utilities_1.log.debug('Starting export process for taxonomies...', this.exportConfig.context);
|
|
28
|
+
const totalCount = await this.initializeExport();
|
|
36
29
|
if (totalCount === 0) {
|
|
37
30
|
cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('TAXONOMY_NOT_FOUND'), this.exportConfig.context);
|
|
38
31
|
return;
|
|
39
32
|
}
|
|
40
|
-
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
33
|
+
const progress = this.setupProgress(totalCount);
|
|
34
|
+
const localesToExport = this.getLocalesToExport();
|
|
35
|
+
if (localesToExport.length === 0) {
|
|
36
|
+
cli_utilities_1.log.warn('No locales found to export', this.exportConfig.context);
|
|
37
|
+
this.completeProgress(true);
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// Start fetch process
|
|
46
41
|
progress
|
|
47
42
|
.startProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES)
|
|
48
43
|
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.FETCH_TAXONOMIES].FETCHING, utils_1.PROCESS_NAMES.FETCH_TAXONOMIES);
|
|
49
|
-
|
|
44
|
+
// Determine export strategy and fetch taxonomies
|
|
45
|
+
await this.determineExportStrategy((_a = this.exportConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code);
|
|
46
|
+
await this.fetchAllTaxonomies(localesToExport);
|
|
50
47
|
progress.completeProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES, true);
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
//
|
|
54
|
-
|
|
55
|
-
|
|
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);
|
|
48
|
+
// Export taxonomies with detailed information
|
|
49
|
+
const actualCount = await this.exportAllTaxonomies(progress, localesToExport, totalCount);
|
|
50
|
+
// Write metadata and complete
|
|
51
|
+
await this.writeTaxonomiesMetadata();
|
|
52
|
+
cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('TAXONOMY_EXPORT_COMPLETE', actualCount), this.exportConfig.context);
|
|
71
53
|
this.completeProgress(true);
|
|
72
54
|
}
|
|
73
55
|
catch (error) {
|
|
@@ -76,72 +58,226 @@ class ExportTaxonomies extends base_class_1.default {
|
|
|
76
58
|
}
|
|
77
59
|
}
|
|
78
60
|
/**
|
|
79
|
-
*
|
|
80
|
-
* @param {number} skip
|
|
81
|
-
* @returns {Promise<any>}
|
|
61
|
+
* Initialize export setup (create directories, get initial count)
|
|
82
62
|
*/
|
|
83
|
-
async
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
63
|
+
async initializeExport() {
|
|
64
|
+
return this.withLoadingSpinner('TAXONOMIES: Analyzing taxonomy structure...', async () => {
|
|
65
|
+
this.taxonomiesFolderPath = (0, node_path_1.resolve)(this.exportConfig.exportDir, this.exportConfig.branchName || '', this.taxonomiesConfig.dirName);
|
|
66
|
+
cli_utilities_1.log.debug(`Taxonomies folder path: '${this.taxonomiesFolderPath}'`, this.exportConfig.context);
|
|
67
|
+
await utils_1.fsUtil.makeDirectory(this.taxonomiesFolderPath);
|
|
68
|
+
cli_utilities_1.log.debug('Created taxonomies directory.', this.exportConfig.context);
|
|
69
|
+
// Get count first for progress tracking
|
|
70
|
+
const countResponse = await this.stack
|
|
71
|
+
.taxonomy()
|
|
72
|
+
.query(Object.assign(Object.assign({}, this.qs), { include_count: true, limit: 1 }))
|
|
73
|
+
.find();
|
|
74
|
+
return countResponse.count || 0;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Setup progress manager with processes
|
|
79
|
+
*/
|
|
80
|
+
setupProgress(totalCount) {
|
|
81
|
+
const progress = this.createNestedProgress(this.currentModuleName);
|
|
82
|
+
// For fetch: count API calls, not individual taxonomies
|
|
83
|
+
const fetchApiCallsCount = Math.ceil(totalCount / (this.qs.limit || 100));
|
|
84
|
+
progress.addProcess(utils_1.PROCESS_NAMES.FETCH_TAXONOMIES, fetchApiCallsCount);
|
|
85
|
+
progress.addProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, totalCount);
|
|
86
|
+
return progress;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Determine if locale-based export is supported
|
|
90
|
+
*/
|
|
91
|
+
async determineExportStrategy(masterLocale) {
|
|
92
|
+
await this.fetchTaxonomies(masterLocale, true);
|
|
93
|
+
if (!this.isLocaleBasedExportSupported) {
|
|
94
|
+
cli_utilities_1.log.debug('Falling back to legacy export (non-localized)', this.exportConfig.context);
|
|
95
|
+
this.taxonomies = {};
|
|
96
|
+
this.taxonomiesByLocale = {};
|
|
88
97
|
}
|
|
89
98
|
else {
|
|
90
|
-
cli_utilities_1.log.debug('
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
99
|
+
cli_utilities_1.log.debug('Localization enabled, proceeding with locale-based export', this.exportConfig.context);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Fetch all taxonomies based on export strategy
|
|
104
|
+
*/
|
|
105
|
+
async fetchAllTaxonomies(localesToExport) {
|
|
106
|
+
if (!this.isLocaleBasedExportSupported) {
|
|
107
|
+
await this.fetchTaxonomies();
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
for (const localeCode of localesToExport) {
|
|
111
|
+
await this.fetchTaxonomies(localeCode);
|
|
102
112
|
}
|
|
103
|
-
|
|
104
|
-
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Export all taxonomies with detailed information
|
|
117
|
+
*/
|
|
118
|
+
async exportAllTaxonomies(progress, localesToExport, totalCount) {
|
|
119
|
+
var _a;
|
|
120
|
+
const actualCount = (_a = Object.keys(this.taxonomies || {})) === null || _a === void 0 ? void 0 : _a.length;
|
|
121
|
+
cli_utilities_1.log.debug(`Found ${actualCount} taxonomies to export (API reported ${totalCount})`, this.exportConfig.context);
|
|
122
|
+
if (actualCount === 0) {
|
|
123
|
+
cli_utilities_1.log.info('No taxonomies found to export detailed information', this.exportConfig.context);
|
|
124
|
+
return 0;
|
|
125
|
+
}
|
|
126
|
+
// Update progress total if needed
|
|
127
|
+
if (actualCount !== totalCount) {
|
|
128
|
+
progress.updateProcessTotal(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, actualCount);
|
|
129
|
+
}
|
|
130
|
+
// Start export process
|
|
131
|
+
progress
|
|
132
|
+
.startProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS)
|
|
133
|
+
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS].EXPORTING, utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS);
|
|
134
|
+
// Export based on strategy
|
|
135
|
+
if (!this.isLocaleBasedExportSupported) {
|
|
136
|
+
await this.exportTaxonomies();
|
|
105
137
|
}
|
|
106
138
|
else {
|
|
139
|
+
for (const localeCode of localesToExport) {
|
|
140
|
+
await this.processLocaleExport(localeCode);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
progress.completeProcess(utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS, true);
|
|
144
|
+
return actualCount;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Process and export taxonomies for a specific locale
|
|
148
|
+
*/
|
|
149
|
+
async processLocaleExport(localeCode) {
|
|
150
|
+
const localeTaxonomies = this.taxonomiesByLocale[localeCode];
|
|
151
|
+
if ((localeTaxonomies === null || localeTaxonomies === void 0 ? void 0 : localeTaxonomies.size) > 0) {
|
|
152
|
+
cli_utilities_1.log.info(`Found ${localeTaxonomies.size} taxonomies for locale: ${localeCode}`, this.exportConfig.context);
|
|
153
|
+
await this.exportTaxonomies(localeCode);
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
cli_utilities_1.log.debug(`No taxonomies found for locale: ${localeCode}`, this.exportConfig.context);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Write taxonomies metadata file
|
|
161
|
+
*/
|
|
162
|
+
async writeTaxonomiesMetadata() {
|
|
163
|
+
if (!this.taxonomies || (0, isEmpty_1.default)(this.taxonomies)) {
|
|
107
164
|
cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('TAXONOMY_NOT_FOUND'), this.exportConfig.context);
|
|
165
|
+
return;
|
|
108
166
|
}
|
|
167
|
+
const taxonomiesFilePath = (0, node_path_1.resolve)(this.taxonomiesFolderPath, this.taxonomiesConfig.fileName);
|
|
168
|
+
cli_utilities_1.log.debug(`Writing taxonomies metadata to: ${taxonomiesFilePath}`, this.exportConfig.context);
|
|
169
|
+
utils_1.fsUtil.writeFile(taxonomiesFilePath, this.taxonomies);
|
|
109
170
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
171
|
+
/**
|
|
172
|
+
* Fetch taxonomies
|
|
173
|
+
*
|
|
174
|
+
* @async
|
|
175
|
+
* @param {?string} [localeCode]
|
|
176
|
+
* @param {boolean} [checkLocaleSupport=false]
|
|
177
|
+
* @returns {Promise<void>}
|
|
178
|
+
*/
|
|
179
|
+
async fetchTaxonomies(localeCode, checkLocaleSupport = false) {
|
|
180
|
+
var _a, _b;
|
|
181
|
+
let skip = 0;
|
|
182
|
+
const localeInfo = localeCode ? `for locale: ${localeCode}` : '';
|
|
183
|
+
if (localeCode && !this.taxonomiesByLocale[localeCode]) {
|
|
184
|
+
this.taxonomiesByLocale[localeCode] = new Set();
|
|
185
|
+
}
|
|
186
|
+
do {
|
|
187
|
+
const queryParams = Object.assign(Object.assign({}, this.qs), { skip });
|
|
188
|
+
if (localeCode) {
|
|
189
|
+
queryParams.locale = localeCode;
|
|
120
190
|
}
|
|
121
|
-
|
|
122
|
-
|
|
191
|
+
cli_utilities_1.log.debug(`Fetching taxonomies ${localeInfo} with skip: ${skip}`, this.exportConfig.context);
|
|
192
|
+
try {
|
|
193
|
+
const data = await this.stack.taxonomy().query(queryParams).find();
|
|
194
|
+
const { items, count } = data;
|
|
195
|
+
const taxonomiesCount = (_a = count !== null && count !== void 0 ? count : items === null || items === void 0 ? void 0 : items.length) !== null && _a !== void 0 ? _a : 0;
|
|
196
|
+
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);
|
|
197
|
+
if (!(items === null || items === void 0 ? void 0 : items.length)) {
|
|
198
|
+
cli_utilities_1.log.debug(`No taxonomies found ${localeInfo}`, this.exportConfig.context);
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
// Check localization support
|
|
202
|
+
if (checkLocaleSupport && localeCode && skip === 0 && !items[0].locale) {
|
|
203
|
+
cli_utilities_1.log.debug('API does not support locale-based taxonomy export', this.exportConfig.context);
|
|
204
|
+
this.isLocaleBasedExportSupported = false;
|
|
205
|
+
}
|
|
206
|
+
this.sanitizeTaxonomiesAttribs(items, localeCode);
|
|
207
|
+
// Track progress per API call (only for actual fetch, not locale support check)
|
|
208
|
+
if (!checkLocaleSupport) {
|
|
209
|
+
(_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.tick(true, `fetched ${items.length} taxonomies${localeInfo}`, null, utils_1.PROCESS_NAMES.FETCH_TAXONOMIES);
|
|
210
|
+
}
|
|
211
|
+
skip += this.qs.limit || 100;
|
|
212
|
+
if (skip >= taxonomiesCount) {
|
|
213
|
+
cli_utilities_1.log.debug(`Completed fetching all taxonomies ${localeInfo}`, this.exportConfig.context);
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
cli_utilities_1.log.debug(`Error fetching taxonomies ${localeInfo}`, this.exportConfig.context);
|
|
219
|
+
if (checkLocaleSupport && this.isLocalePlanLimitationError(error)) {
|
|
220
|
+
cli_utilities_1.log.debug('Taxonomy localization is not included in your plan. Falling back to non-localized export.', this.exportConfig.context);
|
|
221
|
+
this.isLocaleBasedExportSupported = false;
|
|
222
|
+
}
|
|
223
|
+
else if (checkLocaleSupport) {
|
|
224
|
+
cli_utilities_1.log.debug('Locale-based taxonomy export not supported, will use legacy method', this.exportConfig.context);
|
|
225
|
+
this.isLocaleBasedExportSupported = false;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
// Log actual errors during normal fetch (not locale check)
|
|
229
|
+
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.exportConfig.context), (localeCode && { locale: localeCode })));
|
|
230
|
+
}
|
|
231
|
+
// Break to avoid infinite retry loop on errors
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
} while (true);
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* remove invalid keys and write data into taxonomies
|
|
238
|
+
* @function sanitizeTaxonomiesAttribs
|
|
239
|
+
* @param {Record<string, string>[]} taxonomies
|
|
240
|
+
* @param {?string} [localeCode]
|
|
241
|
+
*/
|
|
242
|
+
sanitizeTaxonomiesAttribs(taxonomies, localeCode) {
|
|
243
|
+
const localeInfo = localeCode ? ` for locale: ${localeCode}` : '';
|
|
244
|
+
cli_utilities_1.log.debug(`Processing ${taxonomies.length} taxonomies${localeInfo}`, this.exportConfig.context);
|
|
245
|
+
for (const taxonomy of taxonomies) {
|
|
246
|
+
const taxonomyUID = taxonomy.uid;
|
|
247
|
+
const taxonomyName = taxonomy.name;
|
|
248
|
+
cli_utilities_1.log.debug(`Processing taxonomy: ${taxonomyName} (${taxonomyUID})${localeInfo}`, this.exportConfig.context);
|
|
249
|
+
// Store taxonomy metadata (only once per taxonomy)
|
|
250
|
+
if (!this.taxonomies[taxonomyUID]) {
|
|
251
|
+
this.taxonomies[taxonomyUID] = (0, omit_1.default)(taxonomy, this.taxonomiesConfig.invalidKeys);
|
|
252
|
+
}
|
|
253
|
+
// Track taxonomy for this locale
|
|
254
|
+
if (localeCode) {
|
|
255
|
+
this.taxonomiesByLocale[localeCode].add(taxonomyUID);
|
|
123
256
|
}
|
|
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
257
|
}
|
|
127
|
-
cli_utilities_1.log.debug(`
|
|
258
|
+
cli_utilities_1.log.debug(`Processing complete${localeInfo}. Total taxonomies processed: ${(0, keys_1.default)(this.taxonomies).length}`, this.exportConfig.context);
|
|
128
259
|
}
|
|
129
260
|
/**
|
|
130
|
-
* Export
|
|
131
|
-
* @returns {Promise<any>}
|
|
261
|
+
* Export taxonomies - supports both locale-based and legacy export
|
|
132
262
|
*/
|
|
133
|
-
async exportTaxonomies() {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
cli_utilities_1.log.
|
|
263
|
+
async exportTaxonomies(localeCode) {
|
|
264
|
+
const taxonomiesUID = localeCode ? Array.from(this.taxonomiesByLocale[localeCode] || []) : (0, keys_1.default)(this.taxonomies);
|
|
265
|
+
const localeInfo = localeCode ? ` for locale: ${localeCode}` : '';
|
|
266
|
+
if (taxonomiesUID.length === 0) {
|
|
267
|
+
cli_utilities_1.log.debug(`No taxonomies to export${localeInfo}`, this.exportConfig.context);
|
|
138
268
|
return;
|
|
139
269
|
}
|
|
270
|
+
cli_utilities_1.log.debug(`Exporting detailed data for ${taxonomiesUID.length} taxonomies${localeInfo}`, this.exportConfig.context);
|
|
271
|
+
const exportFolderPath = localeCode ? (0, node_path_1.resolve)(this.taxonomiesFolderPath, localeCode) : this.taxonomiesFolderPath;
|
|
272
|
+
if (localeCode) {
|
|
273
|
+
await utils_1.fsUtil.makeDirectory(exportFolderPath);
|
|
274
|
+
cli_utilities_1.log.debug(`Created locale folder: ${exportFolderPath}`, this.exportConfig.context);
|
|
275
|
+
}
|
|
140
276
|
const onSuccess = ({ response, uid }) => {
|
|
141
277
|
var _a, _b;
|
|
142
278
|
const taxonomyName = (_a = this.taxonomies[uid]) === null || _a === void 0 ? void 0 : _a.name;
|
|
143
|
-
const filePath = (0, node_path_1.resolve)(
|
|
144
|
-
cli_utilities_1.log.debug(`Writing detailed taxonomy to: ${filePath}`, this.exportConfig.context);
|
|
279
|
+
const filePath = (0, node_path_1.resolve)(exportFolderPath, `${uid}.json`);
|
|
280
|
+
cli_utilities_1.log.debug(`Writing detailed taxonomy data to: ${filePath}`, this.exportConfig.context);
|
|
145
281
|
utils_1.fsUtil.writeFile(filePath, response);
|
|
146
282
|
// Track progress for each exported taxonomy
|
|
147
283
|
(_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.tick(true, `taxonomy: ${taxonomyName || uid}`, null, utils_1.PROCESS_NAMES.EXPORT_TAXONOMIES_TERMS);
|
|
@@ -150,31 +286,69 @@ class ExportTaxonomies extends base_class_1.default {
|
|
|
150
286
|
const onReject = ({ error, uid }) => {
|
|
151
287
|
var _a, _b;
|
|
152
288
|
const taxonomyName = (_a = this.taxonomies[uid]) === null || _a === void 0 ? void 0 : _a.name;
|
|
289
|
+
cli_utilities_1.log.debug(`Failed to export detailed data for taxonomy: ${uid}${localeInfo}`, this.exportConfig.context);
|
|
153
290
|
// Track failure
|
|
154
291
|
(_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 }),
|
|
292
|
+
(0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign(Object.assign({}, this.exportConfig.context), { uid }), (localeCode && { locale: localeCode })));
|
|
156
293
|
};
|
|
157
|
-
const
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
resolve: onSuccess,
|
|
167
|
-
reject: onReject,
|
|
168
|
-
});
|
|
294
|
+
for (const taxonomyUID of taxonomiesUID) {
|
|
295
|
+
cli_utilities_1.log.debug(`Processing detailed export for taxonomy: ${taxonomyUID}${localeInfo}`, this.exportConfig.context);
|
|
296
|
+
const exportParams = { format: 'json' };
|
|
297
|
+
if (localeCode) {
|
|
298
|
+
exportParams.locale = localeCode;
|
|
299
|
+
if (this.qs.include_fallback !== undefined)
|
|
300
|
+
exportParams.include_fallback = this.qs.include_fallback;
|
|
301
|
+
if (this.qs.fallback_locale)
|
|
302
|
+
exportParams.fallback_locale = this.qs.fallback_locale;
|
|
169
303
|
}
|
|
170
|
-
|
|
171
|
-
|
|
304
|
+
if (this.qs.branch)
|
|
305
|
+
exportParams.branch = this.qs.branch;
|
|
306
|
+
await this.makeAPICall({
|
|
307
|
+
reject: onReject,
|
|
308
|
+
resolve: onSuccess,
|
|
309
|
+
uid: taxonomyUID,
|
|
310
|
+
module: 'export-taxonomy',
|
|
311
|
+
queryParam: exportParams,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
cli_utilities_1.log.debug(`Completed detailed taxonomy export process${localeInfo}`, this.exportConfig.context);
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Get all locales to export
|
|
318
|
+
*/
|
|
319
|
+
getLocalesToExport() {
|
|
320
|
+
var _a;
|
|
321
|
+
cli_utilities_1.log.debug('Determining locales to export...', this.exportConfig.context);
|
|
322
|
+
const masterLocaleCode = ((_a = this.exportConfig.master_locale) === null || _a === void 0 ? void 0 : _a.code) || 'en-us';
|
|
323
|
+
const localeSet = new Set([masterLocaleCode]);
|
|
324
|
+
try {
|
|
325
|
+
const locales = utils_1.fsUtil.readFile(this.localesFilePath);
|
|
326
|
+
if (locales && (0, keys_1.default)(locales || {}).length > 0) {
|
|
327
|
+
cli_utilities_1.log.debug(`Loaded ${(0, keys_1.default)(locales || {}).length} locales from ${this.localesFilePath}`, this.exportConfig.context);
|
|
328
|
+
for (const localeUid of (0, keys_1.default)(locales)) {
|
|
329
|
+
const localeCode = locales[localeUid].code;
|
|
330
|
+
if (localeCode && !localeSet.has(localeCode)) {
|
|
331
|
+
localeSet.add(localeCode);
|
|
332
|
+
cli_utilities_1.log.debug(`Added locale: ${localeCode} (uid: ${localeUid})`, this.exportConfig.context);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
cli_utilities_1.log.debug(`No locales found in ${this.localesFilePath}`, this.exportConfig.context);
|
|
172
338
|
}
|
|
173
339
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
340
|
+
catch (error) {
|
|
341
|
+
cli_utilities_1.log.warn(`Failed to read locales file: ${this.localesFilePath}`, this.exportConfig.context);
|
|
342
|
+
}
|
|
343
|
+
const localesToExport = Array.from(localeSet);
|
|
344
|
+
cli_utilities_1.log.debug(`Total unique locales to export: ${localesToExport.length}`, this.exportConfig.context);
|
|
345
|
+
return localesToExport;
|
|
346
|
+
}
|
|
347
|
+
isLocalePlanLimitationError(error) {
|
|
348
|
+
var _a, _b;
|
|
349
|
+
return ((error === null || error === void 0 ? void 0 : error.status) === 403 &&
|
|
350
|
+
((_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') &&
|
|
351
|
+
msg.toLowerCase().includes('not included in your plan'))));
|
|
178
352
|
}
|
|
179
353
|
}
|
|
180
354
|
exports.default = ExportTaxonomies;
|
|
@@ -21,7 +21,7 @@ class ExportWebhooks extends base_class_1.default {
|
|
|
21
21
|
cli_utilities_1.log.debug('Starting webhooks export process...', this.exportConfig.context);
|
|
22
22
|
// Setup with loading spinner
|
|
23
23
|
const [totalCount] = await this.withLoadingSpinner('WEBHOOKS: Analyzing webhooks...', async () => {
|
|
24
|
-
this.webhooksFolderPath = (0, node_path_1.resolve)(this.exportConfig.
|
|
24
|
+
this.webhooksFolderPath = (0, node_path_1.resolve)(this.exportConfig.exportDir, this.exportConfig.branchName || '', this.webhookConfig.dirName);
|
|
25
25
|
await utils_1.fsUtil.makeDirectory(this.webhooksFolderPath);
|
|
26
26
|
// Get count for progress tracking
|
|
27
27
|
const countResponse = await this.stack.webhook().fetchAll(Object.assign(Object.assign({}, this.qs), { limit: 1 }));
|
|
@@ -43,9 +43,8 @@ class ExportWebhooks extends base_class_1.default {
|
|
|
43
43
|
const webhooksFilePath = (0, node_path_1.resolve)(this.webhooksFolderPath, this.webhookConfig.fileName);
|
|
44
44
|
cli_utilities_1.log.debug(`Writing webhooks to: ${webhooksFilePath}`, this.exportConfig.context);
|
|
45
45
|
utils_1.fsUtil.writeFile(webhooksFilePath, this.webhooks);
|
|
46
|
-
cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('WEBHOOK_EXPORT_COMPLETE', Object.keys(this.webhooks || {}).length), this.exportConfig.context);
|
|
47
46
|
}
|
|
48
|
-
this.
|
|
47
|
+
this.completeProgressWithMessage();
|
|
49
48
|
}
|
|
50
49
|
catch (error) {
|
|
51
50
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
|
|
@@ -22,7 +22,7 @@ class ExportWorkFlows extends base_class_1.default {
|
|
|
22
22
|
// Setup with loading spinner
|
|
23
23
|
const [totalCount] = await this.withLoadingSpinner('WORKFLOWS: Analyzing workflows...', async () => {
|
|
24
24
|
var _a;
|
|
25
|
-
this.webhooksFolderPath = (0, node_path_1.resolve)(this.exportConfig.
|
|
25
|
+
this.webhooksFolderPath = (0, node_path_1.resolve)(this.exportConfig.exportDir, this.exportConfig.branchName || '', this.workflowConfig.dirName);
|
|
26
26
|
await utils_1.fsUtil.makeDirectory(this.webhooksFolderPath);
|
|
27
27
|
// Get count for progress tracking
|
|
28
28
|
const countResponse = await this.stack.workflow().fetchAll(Object.assign(Object.assign({}, this.qs), { limit: 1 }));
|
|
@@ -46,9 +46,8 @@ class ExportWorkFlows extends base_class_1.default {
|
|
|
46
46
|
const workflowsFilePath = (0, node_path_1.resolve)(this.webhooksFolderPath, this.workflowConfig.fileName);
|
|
47
47
|
cli_utilities_1.log.debug(`Writing workflows to: ${workflowsFilePath}`, this.exportConfig.context);
|
|
48
48
|
utils_1.fsUtil.writeFile(workflowsFilePath, this.workflows);
|
|
49
|
-
cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('WORKFLOW_EXPORT_COMPLETE', Object.keys(this.workflows || {}).length), this.exportConfig.context);
|
|
50
49
|
}
|
|
51
|
-
this.
|
|
50
|
+
this.completeProgressWithMessage();
|
|
52
51
|
}
|
|
53
52
|
catch (error) {
|
|
54
53
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
|
|
@@ -140,7 +139,7 @@ class ExportWorkFlows extends base_class_1.default {
|
|
|
140
139
|
.catch((err) => {
|
|
141
140
|
cli_utilities_1.log.debug(`Failed to fetch role data for UID: ${roleUid}`, this.exportConfig.context);
|
|
142
141
|
(0, cli_utilities_1.handleAndLogError)(err, Object.assign({}, this.exportConfig.context));
|
|
143
|
-
|
|
142
|
+
return undefined; // Return undefined instead of throwing to handle gracefully
|
|
144
143
|
});
|
|
145
144
|
}
|
|
146
145
|
}
|
|
@@ -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;
|
package/lib/types/index.d.ts
CHANGED
|
@@ -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,11 +96,36 @@ 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;
|
|
102
128
|
userId: string | undefined;
|
|
103
|
-
email?: string | undefined;
|
|
104
129
|
sessionId: string | undefined;
|
|
105
130
|
clientId?: string | undefined;
|
|
106
131
|
apiKey: string;
|
package/lib/utils/basic-login.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
/* eslint-disable no-empty */
|
|
5
5
|
/*!
|
|
6
6
|
* Contentstack Import
|
|
7
|
-
* Copyright (c)
|
|
7
|
+
* Copyright (c) 2026 Contentstack LLC
|
|
8
8
|
* MIT Licensed
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
@@ -16,7 +16,7 @@ const login = async (config) => {
|
|
|
16
16
|
const response = await client.login({ email: config.email, password: config.password }).catch(Promise.reject);
|
|
17
17
|
if ((_a = response === null || response === void 0 ? void 0 : response.user) === null || _a === void 0 ? void 0 : _a.authtoken) {
|
|
18
18
|
config.headers = {
|
|
19
|
-
api_key: config.
|
|
19
|
+
api_key: config.apiKey,
|
|
20
20
|
access_token: config.access_token,
|
|
21
21
|
authtoken: response.user.authtoken,
|
|
22
22
|
'X-User-Agent': 'contentstack-export/v',
|
|
@@ -26,15 +26,15 @@ const login = async (config) => {
|
|
|
26
26
|
return config;
|
|
27
27
|
}
|
|
28
28
|
else {
|
|
29
|
-
cli_utilities_1.log.error(`Failed to
|
|
29
|
+
cli_utilities_1.log.error(`Failed to log in!`, config.context);
|
|
30
30
|
process.exit(1);
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
|
-
else if (!config.email && !config.password && config.
|
|
33
|
+
else if (!config.email && !config.password && config.apiKey && config.access_token) {
|
|
34
34
|
cli_utilities_1.log.info(`Content types, entries, assets, labels, global fields, extensions modules will be exported`, config.context);
|
|
35
35
|
cli_utilities_1.log.info(`Email, password, or management token is not set in the config, cannot export Webhook and label modules`, config.context);
|
|
36
36
|
config.headers = {
|
|
37
|
-
api_key: config.
|
|
37
|
+
api_key: config.apiKey,
|
|
38
38
|
access_token: config.access_token,
|
|
39
39
|
'X-User-Agent': 'contentstack-export/v',
|
|
40
40
|
};
|