@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.
- package/README.md +3 -3
- package/lib/commands/cm/stacks/export.js +4 -1
- package/lib/config/index.js +7 -0
- package/lib/export/module-exporter.js +3 -2
- package/lib/export/modules/base-class.js +1 -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 +4 -2
- package/lib/export/modules/entries.js +7 -7
- package/lib/export/modules/global-fields.js +6 -2
- package/lib/export/modules/marketplace-apps.js +33 -21
- package/lib/export/modules/stack.js +18 -18
- package/lib/export/modules/taxonomies.d.ts +32 -8
- package/lib/export/modules/taxonomies.js +204 -129
- package/lib/export/modules/workflows.js +1 -1
- package/lib/types/default-config.d.ts +6 -0
- package/lib/types/index.d.ts +27 -1
- package/lib/utils/basic-login.js +1 -1
- package/lib/utils/export-config-handler.js +5 -5
- package/lib/utils/file-helper.js +1 -1
- package/lib/utils/marketplace-app-helper.js +1 -3
- package/messages/index.json +73 -67
- package/oclif.manifest.json +2 -2
- package/package.json +13 -6
|
@@ -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
|
-
*
|
|
12
|
-
* @param {number} skip
|
|
13
|
-
* @returns {Promise<any>}
|
|
14
|
+
* Process and export taxonomies for a specific locale
|
|
14
15
|
*/
|
|
15
|
-
|
|
16
|
-
sanitizeTaxonomiesAttribs(taxonomies: Record<string, any>[]): void;
|
|
16
|
+
processLocaleExport(localeCode: string): Promise<void>;
|
|
17
17
|
/**
|
|
18
|
-
*
|
|
19
|
-
* @returns {Promise<any>}
|
|
18
|
+
* Write taxonomies metadata file
|
|
20
19
|
*/
|
|
21
|
-
|
|
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 =
|
|
19
|
-
this.
|
|
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
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
*
|
|
80
|
-
* @param {number} skip
|
|
81
|
-
* @returns {Promise<any>}
|
|
60
|
+
* Process and export taxonomies for a specific locale
|
|
82
61
|
*/
|
|
83
|
-
async
|
|
84
|
-
|
|
85
|
-
if (
|
|
86
|
-
|
|
87
|
-
|
|
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(
|
|
69
|
+
cli_utilities_1.log.debug(`No taxonomies found for locale: ${localeCode}`, this.exportConfig.context);
|
|
91
70
|
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
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
|
-
|
|
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
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
122
|
-
|
|
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(`
|
|
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
|
|
131
|
-
* @returns {Promise<any>}
|
|
170
|
+
* Export taxonomies - supports both locale-based and legacy export
|
|
132
171
|
*/
|
|
133
|
-
async exportTaxonomies() {
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
if (
|
|
137
|
-
cli_utilities_1.log.
|
|
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
|
-
|
|
142
|
-
|
|
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
|
-
|
|
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
|
-
|
|
152
|
-
|
|
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
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
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
|
-
|
|
171
|
-
|
|
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
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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
|
-
|
|
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;
|
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,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;
|
package/lib/utils/basic-login.js
CHANGED
|
@@ -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
|
|
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;
|
package/lib/utils/file-helper.js
CHANGED
|
@@ -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('');
|