@contentstack/cli-cm-export 2.0.0-beta.12 → 2.0.0-beta.14
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 +1 -1
- package/lib/config/index.js +1 -0
- package/lib/export/modules/assets.js +42 -42
- package/lib/export/modules/stack.d.ts +11 -1
- package/lib/export/modules/stack.js +73 -29
- package/lib/types/default-config.d.ts +1 -0
- package/lib/types/index.d.ts +1 -0
- package/oclif.manifest.json +1 -1
- package/package.json +7 -7
package/README.md
CHANGED
|
@@ -48,7 +48,7 @@ $ npm install -g @contentstack/cli-cm-export
|
|
|
48
48
|
$ csdx COMMAND
|
|
49
49
|
running command...
|
|
50
50
|
$ csdx (--version)
|
|
51
|
-
@contentstack/cli-cm-export/2.0.0-beta.
|
|
51
|
+
@contentstack/cli-cm-export/2.0.0-beta.14 linux-x64 node-v22.22.1
|
|
52
52
|
$ csdx --help [COMMAND]
|
|
53
53
|
USAGE
|
|
54
54
|
$ csdx COMMAND
|
package/lib/config/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const map_1 = tslib_1.__importDefault(require("lodash/map"));
|
|
5
|
-
const
|
|
5
|
+
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
6
6
|
const chunk_1 = tslib_1.__importDefault(require("lodash/chunk"));
|
|
7
7
|
const first_1 = tslib_1.__importDefault(require("lodash/first"));
|
|
8
8
|
const merge_1 = tslib_1.__importDefault(require("lodash/merge"));
|
|
@@ -15,7 +15,7 @@ const includes_1 = tslib_1.__importDefault(require("lodash/includes"));
|
|
|
15
15
|
const progress_stream_1 = tslib_1.__importDefault(require("progress-stream"));
|
|
16
16
|
const node_fs_1 = require("node:fs");
|
|
17
17
|
const node_path_1 = require("node:path");
|
|
18
|
-
const
|
|
18
|
+
const cli_utilities_2 = require("@contentstack/cli-utilities");
|
|
19
19
|
const constants_1 = require("../../constants");
|
|
20
20
|
const config_1 = tslib_1.__importDefault(require("../../config"));
|
|
21
21
|
const base_class_1 = tslib_1.__importDefault(require("./base-class"));
|
|
@@ -38,10 +38,10 @@ class ExportAssets extends base_class_1.default {
|
|
|
38
38
|
}
|
|
39
39
|
async start() {
|
|
40
40
|
this.assetsRootPath = (0, node_path_1.resolve)(this.exportConfig.exportDir, this.exportConfig.branchName || '', this.assetConfig.dirName);
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
cli_utilities_2.log.debug(`Assets root path resolved to: ${this.assetsRootPath}`, this.exportConfig.context);
|
|
42
|
+
cli_utilities_2.log.debug('Fetching assets and folders count...', this.exportConfig.context);
|
|
43
43
|
// NOTE step 1: Get assets and it's folder count in parallel
|
|
44
|
-
const [assetsCount, assetsFolderCount] = await this.withLoadingSpinner(`${
|
|
44
|
+
const [assetsCount, assetsFolderCount] = await this.withLoadingSpinner(`${(0, cli_utilities_1.getChalk)().bold('ASSETS')}: Analyzing stack content...`, () => Promise.all([this.getAssetsCount(), this.getAssetsCount(true)]));
|
|
45
45
|
// Create nested progress manager
|
|
46
46
|
const progress = this.createNestedProgress(this.currentModuleName);
|
|
47
47
|
// Add sub-processes
|
|
@@ -71,7 +71,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
71
71
|
}
|
|
72
72
|
// Get versioned assets
|
|
73
73
|
if (!(0, isEmpty_1.default)(this.versionedAssets) && this.assetConfig.includeVersionedAssets) {
|
|
74
|
-
|
|
74
|
+
cli_utilities_2.log.debug('Fetching versioned assets metadata...', this.exportConfig.context);
|
|
75
75
|
progress.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_METADATA].FETCHING_VERSION, utils_1.PROCESS_NAMES.ASSET_METADATA);
|
|
76
76
|
await this.getVersionedAssets();
|
|
77
77
|
}
|
|
@@ -80,7 +80,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
80
80
|
progress
|
|
81
81
|
.startProcess(utils_1.PROCESS_NAMES.ASSET_DOWNLOADS)
|
|
82
82
|
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_DOWNLOADS].DOWNLOADING, utils_1.PROCESS_NAMES.ASSET_DOWNLOADS);
|
|
83
|
-
|
|
83
|
+
cli_utilities_2.log.debug('Starting download of all assets...', this.exportConfig.context);
|
|
84
84
|
await this.downloadAssets();
|
|
85
85
|
progress.completeProcess(utils_1.PROCESS_NAMES.ASSET_DOWNLOADS, true);
|
|
86
86
|
}
|
|
@@ -99,9 +99,9 @@ class ExportAssets extends base_class_1.default {
|
|
|
99
99
|
if (!totalCount)
|
|
100
100
|
return Promise.resolve();
|
|
101
101
|
const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { query: { is_dir: true } });
|
|
102
|
-
|
|
102
|
+
cli_utilities_2.log.debug(`Fetching asset folders with query: ${JSON.stringify(queryParam)}`, this.exportConfig.context);
|
|
103
103
|
const onSuccess = ({ response: { items } }) => {
|
|
104
|
-
|
|
104
|
+
cli_utilities_2.log.debug(`Fetched ${(items === null || items === void 0 ? void 0 : items.length) || 0} asset folders`, this.exportConfig.context);
|
|
105
105
|
if (!(0, isEmpty_1.default)(items)) {
|
|
106
106
|
this.assetsFolder.push(...items);
|
|
107
107
|
items.forEach((folder) => {
|
|
@@ -113,7 +113,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
113
113
|
const onReject = ({ error }) => {
|
|
114
114
|
var _a;
|
|
115
115
|
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, 'asset folder', (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_FOLDERS].FAILED, utils_1.PROCESS_NAMES.ASSET_FOLDERS);
|
|
116
|
-
(0,
|
|
116
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
|
|
117
117
|
};
|
|
118
118
|
return this.makeConcurrentCall({
|
|
119
119
|
totalCount,
|
|
@@ -128,10 +128,10 @@ class ExportAssets extends base_class_1.default {
|
|
|
128
128
|
}).then(() => {
|
|
129
129
|
if (!(0, isEmpty_1.default)(this.assetsFolder)) {
|
|
130
130
|
const path = (0, node_path_1.resolve)(this.assetsRootPath, 'folders.json');
|
|
131
|
-
|
|
132
|
-
new
|
|
131
|
+
cli_utilities_2.log.debug(`Writing asset folders to ${path}`, this.exportConfig.context);
|
|
132
|
+
new cli_utilities_2.FsUtility({ basePath: this.assetsRootPath }).writeFile(path, this.assetsFolder);
|
|
133
133
|
}
|
|
134
|
-
|
|
134
|
+
cli_utilities_2.log.info(cli_utilities_2.messageHandler.parse('ASSET_FOLDERS_EXPORT_COMPLETE', this.assetsFolder.length), this.exportConfig.context);
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
/**
|
|
@@ -142,7 +142,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
142
142
|
getAssets(totalCount) {
|
|
143
143
|
if (!totalCount)
|
|
144
144
|
return Promise.resolve();
|
|
145
|
-
|
|
145
|
+
cli_utilities_2.log.debug(`Fetching ${totalCount} assets...`, this.exportConfig.context);
|
|
146
146
|
let fs;
|
|
147
147
|
let metaHandler;
|
|
148
148
|
const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { include_publish_details: true, except: { BASE: this.assetConfig.invalidKeys } });
|
|
@@ -150,7 +150,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
150
150
|
if (this.assetConfig.includeVersionedAssets) {
|
|
151
151
|
const customHandler = (array) => {
|
|
152
152
|
const versionAssets = (0, filter_1.default)(array, ({ _version }) => _version > 1);
|
|
153
|
-
|
|
153
|
+
cli_utilities_2.log.debug(`Found ${versionAssets.length} versioned assets`, this.exportConfig.context);
|
|
154
154
|
if (!(0, isEmpty_1.default)(versionAssets)) {
|
|
155
155
|
this.versionedAssets.push(...(0, map_1.default)(versionAssets, ({ uid, _version }) => ({
|
|
156
156
|
[uid]: _version,
|
|
@@ -162,13 +162,13 @@ class ExportAssets extends base_class_1.default {
|
|
|
162
162
|
const onReject = ({ error }) => {
|
|
163
163
|
var _a;
|
|
164
164
|
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, 'asset', (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.ASSET_METADATA].FAILED, utils_1.PROCESS_NAMES.ASSET_METADATA);
|
|
165
|
-
(0,
|
|
165
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign({}, this.exportConfig.context), cli_utilities_2.messageHandler.parse('ASSET_QUERY_FAILED'));
|
|
166
166
|
};
|
|
167
167
|
const onSuccess = ({ response: { items } }) => {
|
|
168
|
-
|
|
168
|
+
cli_utilities_2.log.debug(`Fetched ${(items === null || items === void 0 ? void 0 : items.length) || 0} assets`, this.exportConfig.context);
|
|
169
169
|
if (!fs && !(0, isEmpty_1.default)(items)) {
|
|
170
|
-
|
|
171
|
-
fs = new
|
|
170
|
+
cli_utilities_2.log.debug('Initializing FsUtility for writing assets metadata', this.exportConfig.context);
|
|
171
|
+
fs = new cli_utilities_2.FsUtility({
|
|
172
172
|
metaHandler,
|
|
173
173
|
moduleName: 'assets',
|
|
174
174
|
indexFileName: this.assetConfig.fileName,
|
|
@@ -178,7 +178,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
180
|
if (!(0, isEmpty_1.default)(items)) {
|
|
181
|
-
|
|
181
|
+
cli_utilities_2.log.debug(`Writing ${items.length} assets into file`, this.exportConfig.context);
|
|
182
182
|
fs === null || fs === void 0 ? void 0 : fs.writeIntoFile(items, { mapKeyVal: true });
|
|
183
183
|
// Track progress for each asset with process name
|
|
184
184
|
items.forEach((asset) => {
|
|
@@ -199,7 +199,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
199
199
|
concurrencyLimit: this.assetConfig.fetchConcurrency,
|
|
200
200
|
}).then(() => {
|
|
201
201
|
fs === null || fs === void 0 ? void 0 : fs.completeFile(true);
|
|
202
|
-
|
|
202
|
+
cli_utilities_2.log.info(cli_utilities_2.messageHandler.parse('ASSET_METADATA_EXPORT_COMPLETE'), this.exportConfig.context);
|
|
203
203
|
});
|
|
204
204
|
}
|
|
205
205
|
/**
|
|
@@ -207,7 +207,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
207
207
|
* @returns Promise<any|void>
|
|
208
208
|
*/
|
|
209
209
|
getVersionedAssets() {
|
|
210
|
-
|
|
210
|
+
cli_utilities_2.log.debug('Preparing to fetch versioned assets...', this.exportConfig.context);
|
|
211
211
|
let fs;
|
|
212
212
|
const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { include_publish_details: true, except: { BASE: this.assetConfig.invalidKeys } });
|
|
213
213
|
const versionedAssets = (0, map_1.default)(this.versionedAssets, (element) => {
|
|
@@ -218,13 +218,13 @@ class ExportAssets extends base_class_1.default {
|
|
|
218
218
|
}
|
|
219
219
|
return batch;
|
|
220
220
|
}).flat();
|
|
221
|
-
|
|
221
|
+
cli_utilities_2.log.debug(`Prepared ${versionedAssets.length} versioned asset queries`, this.exportConfig.context);
|
|
222
222
|
const apiBatches = (0, chunk_1.default)(versionedAssets, this.assetConfig.fetchConcurrency);
|
|
223
223
|
const promisifyHandler = (input) => {
|
|
224
224
|
const { index, batchIndex, apiParams, isLastRequest } = input;
|
|
225
225
|
const batch = apiBatches[batchIndex][index];
|
|
226
226
|
const [uid, version] = (0, first_1.default)((0, entries_1.default)(batch));
|
|
227
|
-
|
|
227
|
+
cli_utilities_2.log.debug(`Fetching versioned asset [UID: ${uid}, Version: ${version}]`, this.exportConfig.context);
|
|
228
228
|
if (apiParams === null || apiParams === void 0 ? void 0 : apiParams.queryParam) {
|
|
229
229
|
apiParams.uid = uid;
|
|
230
230
|
apiParams.queryParam.version = version;
|
|
@@ -234,7 +234,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
234
234
|
};
|
|
235
235
|
const onSuccess = ({ response }) => {
|
|
236
236
|
if (!fs && !(0, isEmpty_1.default)(response)) {
|
|
237
|
-
fs = new
|
|
237
|
+
fs = new cli_utilities_2.FsUtility({
|
|
238
238
|
moduleName: 'assets',
|
|
239
239
|
indexFileName: constants_1.PATH_CONSTANTS.FILES.VERSIONED_ASSETS,
|
|
240
240
|
chunkFileSize: this.assetConfig.chunkFileSize,
|
|
@@ -243,12 +243,12 @@ class ExportAssets extends base_class_1.default {
|
|
|
243
243
|
});
|
|
244
244
|
}
|
|
245
245
|
if (!(0, isEmpty_1.default)(response)) {
|
|
246
|
-
|
|
246
|
+
cli_utilities_2.log.debug(`Writing versioned asset: UID=${response.uid}, Version=${response._version}`, this.exportConfig.context);
|
|
247
247
|
fs === null || fs === void 0 ? void 0 : fs.writeIntoFile([response], { mapKeyVal: true, keyName: ['uid', '_version'] });
|
|
248
248
|
}
|
|
249
249
|
};
|
|
250
250
|
const onReject = ({ error }) => {
|
|
251
|
-
(0,
|
|
251
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign({}, this.exportConfig.context), cli_utilities_2.messageHandler.parse('ASSET_VERSIONED_QUERY_FAILED'));
|
|
252
252
|
};
|
|
253
253
|
return this.makeConcurrentCall({
|
|
254
254
|
apiBatches,
|
|
@@ -263,24 +263,24 @@ class ExportAssets extends base_class_1.default {
|
|
|
263
263
|
concurrencyLimit: this.assetConfig.fetchConcurrency,
|
|
264
264
|
}, promisifyHandler).then(() => {
|
|
265
265
|
fs === null || fs === void 0 ? void 0 : fs.completeFile(true);
|
|
266
|
-
|
|
266
|
+
cli_utilities_2.log.info(cli_utilities_2.messageHandler.parse('ASSET_VERSIONED_METADATA_EXPORT_COMPLETE'), this.exportConfig.context);
|
|
267
267
|
});
|
|
268
268
|
}
|
|
269
269
|
getAssetsCount(isDir = false) {
|
|
270
270
|
const queryParam = Object.assign(Object.assign({ limit: 1 }, this.commonQueryParam), { skip: 10 ** 100 });
|
|
271
271
|
if (isDir)
|
|
272
272
|
queryParam.query = { is_dir: true };
|
|
273
|
-
|
|
273
|
+
cli_utilities_2.log.debug(`Querying count of assets${isDir ? ' (folders only)' : ''} with params: ${JSON.stringify(queryParam)}`, this.exportConfig.context);
|
|
274
274
|
return this.stack
|
|
275
275
|
.asset()
|
|
276
276
|
.query(queryParam)
|
|
277
277
|
.count()
|
|
278
278
|
.then(({ assets }) => {
|
|
279
|
-
|
|
279
|
+
cli_utilities_2.log.debug(`Received asset count: ${assets}`, this.exportConfig.context);
|
|
280
280
|
return assets;
|
|
281
281
|
})
|
|
282
282
|
.catch((error) => {
|
|
283
|
-
(0,
|
|
283
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign({}, this.exportConfig.context), cli_utilities_2.messageHandler.parse('ASSET_COUNT_QUERY_FAILED'));
|
|
284
284
|
});
|
|
285
285
|
}
|
|
286
286
|
/**
|
|
@@ -288,12 +288,12 @@ class ExportAssets extends base_class_1.default {
|
|
|
288
288
|
* @returns Promise<any|void>
|
|
289
289
|
*/
|
|
290
290
|
async downloadAssets() {
|
|
291
|
-
const fs = new
|
|
291
|
+
const fs = new cli_utilities_2.FsUtility({
|
|
292
292
|
fileExt: 'json',
|
|
293
293
|
createDirIfNotExist: false,
|
|
294
294
|
basePath: this.assetsRootPath,
|
|
295
295
|
});
|
|
296
|
-
|
|
296
|
+
cli_utilities_2.log.debug('Reading asset metadata for download...', this.exportConfig.context);
|
|
297
297
|
const assetsMetaData = fs.getPlainMeta();
|
|
298
298
|
let listOfAssets = (0, values_1.default)(assetsMetaData).flat();
|
|
299
299
|
if (this.assetConfig.includeVersionedAssets) {
|
|
@@ -301,21 +301,21 @@ class ExportAssets extends base_class_1.default {
|
|
|
301
301
|
listOfAssets.push(...(0, values_1.default)(versionedAssetsMetaData).flat());
|
|
302
302
|
}
|
|
303
303
|
listOfAssets = (0, uniqBy_1.default)(listOfAssets, 'url');
|
|
304
|
-
|
|
304
|
+
cli_utilities_2.log.debug(`Total unique assets to download: ${listOfAssets.length}`, this.exportConfig.context);
|
|
305
305
|
const apiBatches = (0, chunk_1.default)(listOfAssets, this.assetConfig.downloadLimit);
|
|
306
|
-
const downloadedAssetsDirs = await (0,
|
|
306
|
+
const downloadedAssetsDirs = await (0, cli_utilities_2.getDirectories)((0, node_path_1.resolve)(this.assetsRootPath, 'files'));
|
|
307
307
|
const onSuccess = ({ response: { data }, additionalInfo }) => {
|
|
308
308
|
var _a;
|
|
309
309
|
const { asset } = additionalInfo;
|
|
310
310
|
const assetFolderPath = (0, node_path_1.resolve)(this.assetsRootPath, 'files', asset.uid);
|
|
311
311
|
const assetFilePath = (0, node_path_1.resolve)(assetFolderPath, asset.filename);
|
|
312
|
-
|
|
312
|
+
cli_utilities_2.log.debug(`Saving asset to: ${assetFilePath}`, this.exportConfig.context);
|
|
313
313
|
if (!(0, includes_1.default)(downloadedAssetsDirs, asset.uid)) {
|
|
314
314
|
fs.createFolderIfNotExist(assetFolderPath);
|
|
315
315
|
}
|
|
316
316
|
const assetWriterStream = (0, node_fs_1.createWriteStream)(assetFilePath);
|
|
317
317
|
assetWriterStream.on('error', (error) => {
|
|
318
|
-
(0,
|
|
318
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign(Object.assign({}, this.exportConfig.context), { uid: asset.uid, filename: asset.fileName }), cli_utilities_2.messageHandler.parse('ASSET_DOWNLOAD_FAILED', asset.filename, asset.uid));
|
|
319
319
|
});
|
|
320
320
|
/**
|
|
321
321
|
* NOTE if pipe not working as expected add the following code below to fix the issue
|
|
@@ -339,21 +339,21 @@ class ExportAssets extends base_class_1.default {
|
|
|
339
339
|
data.pipe(assetWriterStream);
|
|
340
340
|
}
|
|
341
341
|
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `Downloaded asset: ${asset.filename || asset.uid}`, null, utils_1.PROCESS_NAMES.ASSET_DOWNLOADS);
|
|
342
|
-
|
|
342
|
+
cli_utilities_2.log.success(cli_utilities_2.messageHandler.parse('ASSET_DOWNLOAD_SUCCESS', asset.filename, asset.uid), this.exportConfig.context);
|
|
343
343
|
};
|
|
344
344
|
const onReject = ({ error, additionalInfo }) => {
|
|
345
345
|
var _a;
|
|
346
346
|
const { asset } = additionalInfo;
|
|
347
347
|
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, `Failed to download asset: ${asset.filename || asset.uid}`, null, utils_1.PROCESS_NAMES.ASSET_DOWNLOADS);
|
|
348
|
-
(0,
|
|
348
|
+
(0, cli_utilities_2.handleAndLogError)(error, Object.assign(Object.assign({}, this.exportConfig.context), { uid: asset.uid, filename: asset.filename }), cli_utilities_2.messageHandler.parse('ASSET_DOWNLOAD_FAILED', asset.filename, asset.uid));
|
|
349
349
|
};
|
|
350
350
|
const promisifyHandler = (input) => {
|
|
351
351
|
const { index, batchIndex } = input;
|
|
352
352
|
const asset = apiBatches[batchIndex][index];
|
|
353
353
|
const url = this.assetConfig.securedAssets
|
|
354
|
-
? `${asset.url}?authtoken=${
|
|
354
|
+
? `${asset.url}?authtoken=${cli_utilities_2.configHandler.get('authtoken')}`
|
|
355
355
|
: asset.url;
|
|
356
|
-
|
|
356
|
+
cli_utilities_2.log.debug(`Preparing to download asset: ${asset.filename} (UID: ${asset.uid}) from URL: ${url}`, this.exportConfig.context);
|
|
357
357
|
return this.makeAPICall({
|
|
358
358
|
reject: onReject,
|
|
359
359
|
resolve: onSuccess,
|
|
@@ -368,7 +368,7 @@ class ExportAssets extends base_class_1.default {
|
|
|
368
368
|
totalCount: listOfAssets.length,
|
|
369
369
|
concurrencyLimit: this.assetConfig.downloadLimit,
|
|
370
370
|
}, promisifyHandler).then(() => {
|
|
371
|
-
|
|
371
|
+
cli_utilities_2.log.success(cli_utilities_2.messageHandler.parse('ASSET_DOWNLOAD_COMPLETE'), this.exportConfig.context);
|
|
372
372
|
});
|
|
373
373
|
}
|
|
374
374
|
}
|
|
@@ -8,6 +8,16 @@ export default class ExportStack extends BaseClass {
|
|
|
8
8
|
start(): Promise<void>;
|
|
9
9
|
getStack(): Promise<any>;
|
|
10
10
|
getLocales(skip?: number): Promise<any>;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* Reuse stack snapshot from `getStack()` when present so we do not call `stack.fetch()` twice
|
|
13
|
+
* (same GET /stacks payload as writing stack.json). Falls back to `this.stack.fetch()` otherwise.
|
|
14
|
+
*/
|
|
15
|
+
exportStack(preloadedStack?: Record<string, any> | null): Promise<any>;
|
|
16
|
+
private isStackFetchPayload;
|
|
17
|
+
/**
|
|
18
|
+
* Management-token exports cannot use Stack CMA endpoints for full metadata; write api_key from config only.
|
|
19
|
+
*/
|
|
20
|
+
private writeStackJsonFromConfigApiKeyOnly;
|
|
21
|
+
private persistStackJsonPayload;
|
|
12
22
|
exportStackSettings(): Promise<any>;
|
|
13
23
|
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
const find_1 = tslib_1.__importDefault(require("lodash/find"));
|
|
5
|
+
const omit_1 = tslib_1.__importDefault(require("lodash/omit"));
|
|
5
6
|
const node_path_1 = require("node:path");
|
|
6
7
|
const cli_utilities_1 = require("@contentstack/cli-utilities");
|
|
7
8
|
const constants_1 = require("../../constants");
|
|
@@ -17,35 +18,31 @@ class ExportStack extends base_class_1.default {
|
|
|
17
18
|
this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.STACK];
|
|
18
19
|
}
|
|
19
20
|
async start() {
|
|
21
|
+
var _a;
|
|
20
22
|
try {
|
|
21
23
|
cli_utilities_1.log.debug('Starting stack export process...', this.exportConfig.context);
|
|
22
|
-
// Initial analysis with loading spinner
|
|
24
|
+
// Initial analysis with loading spinner (skip getStack when using management token — no SDK snapshot)
|
|
23
25
|
const [stackData] = await this.withLoadingSpinner('STACK: Analyzing stack configuration...', async () => {
|
|
24
|
-
const stackData = (0, cli_utilities_1.isAuthenticated)() ? await this.getStack()
|
|
26
|
+
const stackData = this.exportConfig.management_token || !(0, cli_utilities_1.isAuthenticated)() ? null : await this.getStack();
|
|
25
27
|
return [stackData];
|
|
26
28
|
});
|
|
27
29
|
// Create nested progress manager
|
|
28
30
|
const progress = this.createNestedProgress(this.currentModuleName);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
this.exportConfig.org_uid = stackData.org_uid;
|
|
31
|
+
const orgUid = (_a = stackData === null || stackData === void 0 ? void 0 : stackData.org_uid) !== null && _a !== void 0 ? _a : stackData === null || stackData === void 0 ? void 0 : stackData.organization_uid;
|
|
32
|
+
if (orgUid) {
|
|
33
|
+
cli_utilities_1.log.debug(`Found organization UID: '${orgUid}'.`, this.exportConfig.context);
|
|
34
|
+
this.exportConfig.org_uid = orgUid;
|
|
34
35
|
this.exportConfig.sourceStackName = stackData.name;
|
|
35
36
|
cli_utilities_1.log.debug(`Set source stack name: ${stackData.name}`, this.exportConfig.context);
|
|
36
37
|
}
|
|
37
38
|
if (!this.exportConfig.management_token) {
|
|
38
39
|
progress.addProcess(utils_1.PROCESS_NAMES.STACK_SETTINGS, 1);
|
|
39
|
-
processCount++;
|
|
40
40
|
}
|
|
41
|
+
progress.addProcess(utils_1.PROCESS_NAMES.STACK_DETAILS, 1);
|
|
41
42
|
if (!this.exportConfig.preserveStackVersion && !this.exportConfig.hasOwnProperty('master_locale')) {
|
|
42
43
|
progress.addProcess(utils_1.PROCESS_NAMES.STACK_LOCALE, 1);
|
|
43
|
-
processCount++;
|
|
44
|
-
}
|
|
45
|
-
else if (this.exportConfig.preserveStackVersion) {
|
|
46
|
-
progress.addProcess(utils_1.PROCESS_NAMES.STACK_DETAILS, 1);
|
|
47
|
-
processCount++;
|
|
48
44
|
}
|
|
45
|
+
let stackDetailsExportResult;
|
|
49
46
|
// Execute processes
|
|
50
47
|
if (!this.exportConfig.management_token) {
|
|
51
48
|
progress
|
|
@@ -53,9 +50,19 @@ class ExportStack extends base_class_1.default {
|
|
|
53
50
|
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.STACK_SETTINGS].EXPORTING, utils_1.PROCESS_NAMES.STACK_SETTINGS);
|
|
54
51
|
await this.exportStackSettings();
|
|
55
52
|
progress.completeProcess(utils_1.PROCESS_NAMES.STACK_SETTINGS, true);
|
|
53
|
+
progress
|
|
54
|
+
.startProcess(utils_1.PROCESS_NAMES.STACK_DETAILS)
|
|
55
|
+
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.STACK_DETAILS].EXPORTING, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
56
|
+
stackDetailsExportResult = await this.exportStack(stackData);
|
|
57
|
+
progress.completeProcess(utils_1.PROCESS_NAMES.STACK_DETAILS, true);
|
|
56
58
|
}
|
|
57
59
|
else {
|
|
58
60
|
cli_utilities_1.log.info('Skipping stack settings export: Operation is not supported when using a management token.', this.exportConfig.context);
|
|
61
|
+
progress
|
|
62
|
+
.startProcess(utils_1.PROCESS_NAMES.STACK_DETAILS)
|
|
63
|
+
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.STACK_DETAILS].EXPORTING, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
64
|
+
stackDetailsExportResult = await this.writeStackJsonFromConfigApiKeyOnly();
|
|
65
|
+
progress.completeProcess(utils_1.PROCESS_NAMES.STACK_DETAILS, true);
|
|
59
66
|
}
|
|
60
67
|
if (!this.exportConfig.preserveStackVersion && !this.exportConfig.hasOwnProperty('master_locale')) {
|
|
61
68
|
progress
|
|
@@ -71,13 +78,8 @@ class ExportStack extends base_class_1.default {
|
|
|
71
78
|
return masterLocale;
|
|
72
79
|
}
|
|
73
80
|
else if (this.exportConfig.preserveStackVersion) {
|
|
74
|
-
progress
|
|
75
|
-
.startProcess(utils_1.PROCESS_NAMES.STACK_DETAILS)
|
|
76
|
-
.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.STACK_DETAILS].EXPORTING, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
77
|
-
const stackResult = await this.exportStack();
|
|
78
|
-
progress.completeProcess(utils_1.PROCESS_NAMES.STACK_DETAILS, true);
|
|
79
81
|
this.completeProgress(true);
|
|
80
|
-
return
|
|
82
|
+
return stackDetailsExportResult;
|
|
81
83
|
}
|
|
82
84
|
else {
|
|
83
85
|
cli_utilities_1.log.debug('Locale locale already set, skipping locale fetch', this.exportConfig.context);
|
|
@@ -161,22 +163,30 @@ class ExportStack extends base_class_1.default {
|
|
|
161
163
|
throw error;
|
|
162
164
|
});
|
|
163
165
|
}
|
|
164
|
-
|
|
166
|
+
/**
|
|
167
|
+
* Reuse stack snapshot from `getStack()` when present so we do not call `stack.fetch()` twice
|
|
168
|
+
* (same GET /stacks payload as writing stack.json). Falls back to `this.stack.fetch()` otherwise.
|
|
169
|
+
*/
|
|
170
|
+
async exportStack(preloadedStack) {
|
|
171
|
+
var _a;
|
|
165
172
|
cli_utilities_1.log.debug(`Starting stack export for: '${this.exportConfig.apiKey}'...`, this.exportConfig.context);
|
|
166
173
|
await utils_1.fsUtil.makeDirectory(this.stackFolderPath);
|
|
167
174
|
cli_utilities_1.log.debug(`Created stack directory at: '${this.stackFolderPath}'`, this.exportConfig.context);
|
|
175
|
+
if (this.isStackFetchPayload(preloadedStack)) {
|
|
176
|
+
cli_utilities_1.log.debug('Reusing stack payload from analysis step (no extra stack.fetch).', this.exportConfig.context);
|
|
177
|
+
try {
|
|
178
|
+
return this.persistStackJsonPayload(preloadedStack);
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(false, 'stack export', (error === null || error === void 0 ? void 0 : error.message) || utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.STACK_DETAILS].FAILED, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
182
|
+
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
|
|
183
|
+
return undefined;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
168
186
|
return this.stack
|
|
169
187
|
.fetch()
|
|
170
188
|
.then((resp) => {
|
|
171
|
-
|
|
172
|
-
const stackFilePath = (0, node_path_1.resolve)(this.stackFolderPath, this.stackConfig.fileName);
|
|
173
|
-
cli_utilities_1.log.debug(`Writing stack data to: '${stackFilePath}'`, this.exportConfig.context);
|
|
174
|
-
utils_1.fsUtil.writeFile(stackFilePath, resp);
|
|
175
|
-
// Track progress for stack export completion
|
|
176
|
-
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `stack: ${this.exportConfig.apiKey}`, null, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
177
|
-
cli_utilities_1.log.success(`Stack details exported successfully for stack ${this.exportConfig.apiKey}`, this.exportConfig.context);
|
|
178
|
-
cli_utilities_1.log.debug('Stack export completed successfully.', this.exportConfig.context);
|
|
179
|
-
return resp;
|
|
189
|
+
return this.persistStackJsonPayload(resp);
|
|
180
190
|
})
|
|
181
191
|
.catch((error) => {
|
|
182
192
|
var _a;
|
|
@@ -185,6 +195,40 @@ class ExportStack extends base_class_1.default {
|
|
|
185
195
|
(0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.exportConfig.context));
|
|
186
196
|
});
|
|
187
197
|
}
|
|
198
|
+
isStackFetchPayload(data) {
|
|
199
|
+
return (typeof data === 'object' &&
|
|
200
|
+
data !== null &&
|
|
201
|
+
!Array.isArray(data) &&
|
|
202
|
+
('api_key' in data || 'uid' in data));
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Management-token exports cannot use Stack CMA endpoints for full metadata; write api_key from config only.
|
|
206
|
+
*/
|
|
207
|
+
async writeStackJsonFromConfigApiKeyOnly() {
|
|
208
|
+
var _a;
|
|
209
|
+
if (!this.exportConfig.apiKey || typeof this.exportConfig.apiKey !== 'string') {
|
|
210
|
+
throw new Error('Stack API key is required to write stack.json when using a management token.');
|
|
211
|
+
}
|
|
212
|
+
cli_utilities_1.log.debug('Writing config-based stack.json (api_key only, no stack fetch).', this.exportConfig.context);
|
|
213
|
+
await utils_1.fsUtil.makeDirectory(this.stackFolderPath);
|
|
214
|
+
const payload = { api_key: this.exportConfig.apiKey };
|
|
215
|
+
const stackFilePath = (0, node_path_1.resolve)(this.stackFolderPath, this.stackConfig.fileName);
|
|
216
|
+
utils_1.fsUtil.writeFile(stackFilePath, payload);
|
|
217
|
+
(_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.tick(true, `stack: ${this.exportConfig.apiKey}`, null, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
218
|
+
cli_utilities_1.log.success(`Stack identifier written to stack.json from config for stack ${this.exportConfig.apiKey}`, this.exportConfig.context);
|
|
219
|
+
return payload;
|
|
220
|
+
}
|
|
221
|
+
persistStackJsonPayload(resp) {
|
|
222
|
+
var _a, _b;
|
|
223
|
+
const sanitized = (0, omit_1.default)(resp, (_a = this.stackConfig.invalidKeys) !== null && _a !== void 0 ? _a : []);
|
|
224
|
+
const stackFilePath = (0, node_path_1.resolve)(this.stackFolderPath, this.stackConfig.fileName);
|
|
225
|
+
cli_utilities_1.log.debug(`Writing stack data to: '${stackFilePath}'`, this.exportConfig.context);
|
|
226
|
+
utils_1.fsUtil.writeFile(stackFilePath, sanitized);
|
|
227
|
+
(_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.tick(true, `stack: ${this.exportConfig.apiKey}`, null, utils_1.PROCESS_NAMES.STACK_DETAILS);
|
|
228
|
+
cli_utilities_1.log.success(`Stack details exported successfully for stack ${this.exportConfig.apiKey}`, this.exportConfig.context);
|
|
229
|
+
cli_utilities_1.log.debug('Stack export completed successfully.', this.exportConfig.context);
|
|
230
|
+
return sanitized;
|
|
231
|
+
}
|
|
188
232
|
async exportStackSettings() {
|
|
189
233
|
cli_utilities_1.log.info('Exporting stack settings...', this.exportConfig.context);
|
|
190
234
|
await utils_1.fsUtil.makeDirectory(this.stackFolderPath);
|
package/lib/types/index.d.ts
CHANGED
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contentstack/cli-cm-export",
|
|
3
3
|
"description": "Contentstack CLI plugin to export content from stack",
|
|
4
|
-
"version": "2.0.0-beta.
|
|
4
|
+
"version": "2.0.0-beta.14",
|
|
5
5
|
"author": "Contentstack",
|
|
6
6
|
"bugs": "https://github.com/contentstack/cli/issues",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@contentstack/cli-command": "~2.0.0-beta.
|
|
9
|
-
"@contentstack/cli-utilities": "~2.0.0-beta.
|
|
10
|
-
"@contentstack/cli-variants": "~2.0.0-beta.
|
|
8
|
+
"@contentstack/cli-command": "~2.0.0-beta.5",
|
|
9
|
+
"@contentstack/cli-utilities": "~2.0.0-beta.5",
|
|
10
|
+
"@contentstack/cli-variants": "~2.0.0-beta.11",
|
|
11
11
|
"@oclif/core": "^4.8.0",
|
|
12
12
|
"async": "^3.2.6",
|
|
13
13
|
"big-json": "^3.2.0",
|
|
14
14
|
"bluebird": "^3.7.2",
|
|
15
|
-
"chalk": "^
|
|
15
|
+
"chalk": "^5.6.2",
|
|
16
16
|
"lodash": "^4.17.23",
|
|
17
17
|
"merge": "^2.1.1",
|
|
18
18
|
"mkdirp": "^1.0.4",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"winston": "^3.17.0"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
|
-
"@contentstack/cli-auth": "~2.0.0-beta.
|
|
25
|
-
"@contentstack/cli-config": "~2.0.0-beta.
|
|
24
|
+
"@contentstack/cli-auth": "~2.0.0-beta.9",
|
|
25
|
+
"@contentstack/cli-config": "~2.0.0-beta.5",
|
|
26
26
|
"@contentstack/cli-dev-dependencies": "~2.0.0-beta.0",
|
|
27
27
|
"@oclif/plugin-help": "^6.2.28",
|
|
28
28
|
"@oclif/test": "^4.1.13",
|