@contentstack/cli-cm-export 1.5.8 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/README.md +2 -2
  2. package/lib/commands/cm/stacks/export.d.ts +10 -0
  3. package/lib/commands/cm/stacks/export.js +108 -0
  4. package/lib/config/index.d.ts +3 -0
  5. package/lib/config/index.js +393 -0
  6. package/lib/export/index.d.ts +1 -0
  7. package/lib/export/index.js +8 -0
  8. package/lib/export/module-exporter.d.ts +15 -0
  9. package/lib/export/module-exporter.js +93 -0
  10. package/lib/export/modules/assets.d.ts +54 -0
  11. package/lib/export/modules/assets.js +303 -0
  12. package/lib/export/modules/base-class.d.ts +48 -0
  13. package/lib/export/modules/base-class.js +117 -0
  14. package/lib/export/modules/index.d.ts +3 -0
  15. package/lib/export/modules/index.js +38 -0
  16. package/lib/export/modules/locales.d.ts +16 -0
  17. package/lib/export/modules/locales.js +68 -0
  18. package/lib/export/modules-js/assets.d.ts +43 -0
  19. package/lib/export/modules-js/assets.js +391 -0
  20. package/lib/export/modules-js/content-types.d.ts +21 -0
  21. package/lib/export/modules-js/content-types.js +75 -0
  22. package/lib/export/modules-js/custom-roles.d.ts +21 -0
  23. package/lib/export/modules-js/custom-roles.js +76 -0
  24. package/lib/export/modules-js/entries.d.ts +18 -0
  25. package/lib/export/modules-js/entries.js +141 -0
  26. package/lib/export/modules-js/environments.d.ts +16 -0
  27. package/lib/export/modules-js/environments.js +62 -0
  28. package/lib/export/modules-js/extensions.d.ts +18 -0
  29. package/lib/export/modules-js/extensions.js +57 -0
  30. package/lib/export/modules-js/global-fields.d.ts +22 -0
  31. package/lib/export/modules-js/global-fields.js +107 -0
  32. package/lib/export/modules-js/index.d.ts +1 -0
  33. package/lib/export/modules-js/index.js +33 -0
  34. package/lib/export/modules-js/labels.d.ts +14 -0
  35. package/lib/export/modules-js/labels.js +56 -0
  36. package/lib/export/modules-js/locales.d.ts +23 -0
  37. package/lib/export/modules-js/locales.js +67 -0
  38. package/lib/export/modules-js/marketplace-apps.d.ts +21 -0
  39. package/lib/export/modules-js/marketplace-apps.js +144 -0
  40. package/lib/export/modules-js/stack.d.ts +18 -0
  41. package/lib/export/modules-js/stack.js +91 -0
  42. package/lib/export/modules-js/webhooks.d.ts +18 -0
  43. package/lib/export/modules-js/webhooks.js +60 -0
  44. package/lib/export/modules-js/workflows.d.ts +16 -0
  45. package/lib/export/modules-js/workflows.js +89 -0
  46. package/lib/types/default-config.d.ts +158 -0
  47. package/lib/types/default-config.js +2 -0
  48. package/lib/types/export-config.d.ts +34 -0
  49. package/lib/types/export-config.js +2 -0
  50. package/lib/types/index.d.ts +45 -0
  51. package/lib/types/index.js +2 -0
  52. package/lib/utils/basic-login.d.ts +8 -0
  53. package/lib/utils/basic-login.js +45 -0
  54. package/lib/utils/common-helper.d.ts +11 -0
  55. package/lib/utils/common-helper.js +78 -0
  56. package/lib/utils/export-config-handler.d.ts +3 -0
  57. package/lib/utils/export-config-handler.js +72 -0
  58. package/lib/utils/file-helper.d.ts +14 -0
  59. package/lib/utils/file-helper.js +120 -0
  60. package/lib/utils/index.d.ts +10 -0
  61. package/lib/utils/index.js +21 -0
  62. package/lib/utils/interactive.d.ts +6 -0
  63. package/lib/utils/interactive.js +71 -0
  64. package/lib/utils/logger.d.ts +8 -0
  65. package/lib/utils/logger.js +154 -0
  66. package/lib/utils/marketplace-app-helper.d.ts +1 -0
  67. package/lib/utils/marketplace-app-helper.js +23 -0
  68. package/lib/utils/setup-branches.d.ts +3 -0
  69. package/lib/utils/setup-branches.js +49 -0
  70. package/lib/utils/setup-export-dir.d.ts +2 -0
  71. package/lib/utils/setup-export-dir.js +12 -0
  72. package/messages/index.json +1 -7
  73. package/oclif.manifest.json +1 -1
  74. package/package.json +37 -23
  75. package/src/app.js +0 -161
  76. package/src/commands/cm/stacks/export.js +0 -202
  77. package/src/config/default.js +0 -360
  78. package/src/lib/export/assets.js +0 -451
  79. package/src/lib/export/content-types.js +0 -90
  80. package/src/lib/export/custom-roles.js +0 -93
  81. package/src/lib/export/entries.js +0 -200
  82. package/src/lib/export/environments.js +0 -74
  83. package/src/lib/export/extensions.js +0 -69
  84. package/src/lib/export/global-fields.js +0 -122
  85. package/src/lib/export/labels.js +0 -69
  86. package/src/lib/export/locales.js +0 -72
  87. package/src/lib/export/marketplace-apps.js +0 -184
  88. package/src/lib/export/stack.js +0 -99
  89. package/src/lib/export/webhooks.js +0 -76
  90. package/src/lib/export/workflows.js +0 -110
  91. package/src/lib/util/export-flags.js +0 -193
  92. package/src/lib/util/helper.js +0 -113
  93. package/src/lib/util/index.js +0 -80
  94. package/src/lib/util/log.js +0 -158
  95. package/src/lib/util/login.js +0 -79
  96. package/src/lib/util/marketplace-app-helper.js +0 -24
  97. package/src/lib/util/setup-branches.js +0 -56
@@ -0,0 +1,54 @@
1
+ import { ModuleClassParams } from '../../types';
2
+ import BaseClass from './base-class';
3
+ export default class ExportAssets extends BaseClass {
4
+ private assetsRootPath;
5
+ assetConfig: {
6
+ dirName: string;
7
+ fileName: string;
8
+ batchLimit: number;
9
+ host: string;
10
+ invalidKeys: string[];
11
+ chunkFileSize: number;
12
+ downloadLimit: number;
13
+ fetchConcurrency: number;
14
+ assetsMetaKeys: string[];
15
+ securedAssets: boolean;
16
+ displayExecutionTime: boolean;
17
+ enableDownloadStatus: boolean;
18
+ includeVersionedAssets: boolean;
19
+ dependencies?: import("../../types").Modules[];
20
+ };
21
+ private assetsFolder;
22
+ versionedAssets: Record<string, unknown>[];
23
+ constructor({ exportConfig, stackAPIClient }: ModuleClassParams);
24
+ get commonQueryParam(): Record<string, unknown>;
25
+ start(): Promise<void>;
26
+ /**
27
+ * @method getAssetsFolders
28
+ * @param {number} totalCount number
29
+ * @returns Promise<any|void>
30
+ */
31
+ getAssetsFolders(totalCount: number | void): Promise<Promise<void> | void>;
32
+ /**
33
+ * @method getAssets
34
+ * @param totalCount number
35
+ * @returns Promise<void>
36
+ */
37
+ getAssets(totalCount: number | void): Promise<any | void>;
38
+ /**
39
+ * @method getVersionedAssets
40
+ * @returns Promise<any|void>
41
+ */
42
+ getVersionedAssets(): Promise<any | void>;
43
+ /**
44
+ * @method getAssetsCount
45
+ * @param isDir boolean
46
+ * @returns Promise<number|undefined>
47
+ */
48
+ getAssetsCount(isDir?: boolean): Promise<number | void>;
49
+ /**
50
+ * @method downloadAssets
51
+ * @returns Promise<any|void>
52
+ */
53
+ downloadAssets(): Promise<any | void>;
54
+ }
@@ -0,0 +1,303 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const map_1 = tslib_1.__importDefault(require("lodash/map"));
5
+ const chunk_1 = tslib_1.__importDefault(require("lodash/chunk"));
6
+ const first_1 = tslib_1.__importDefault(require("lodash/first"));
7
+ const merge_1 = tslib_1.__importDefault(require("lodash/merge"));
8
+ const filter_1 = tslib_1.__importDefault(require("lodash/filter"));
9
+ const uniqBy_1 = tslib_1.__importDefault(require("lodash/uniqBy"));
10
+ const values_1 = tslib_1.__importDefault(require("lodash/values"));
11
+ const entries_1 = tslib_1.__importDefault(require("lodash/entries"));
12
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
13
+ const includes_1 = tslib_1.__importDefault(require("lodash/includes"));
14
+ const progress_stream_1 = tslib_1.__importDefault(require("progress-stream"));
15
+ const node_fs_1 = require("node:fs");
16
+ const node_path_1 = require("node:path");
17
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
18
+ const config_1 = tslib_1.__importDefault(require("../../config"));
19
+ const utils_1 = require("../../utils");
20
+ const base_class_1 = tslib_1.__importDefault(require("./base-class"));
21
+ class ExportAssets extends base_class_1.default {
22
+ constructor({ exportConfig, stackAPIClient }) {
23
+ super({ exportConfig, stackAPIClient });
24
+ this.assetConfig = config_1.default.modules.assets;
25
+ this.assetsFolder = [];
26
+ this.versionedAssets = [];
27
+ }
28
+ get commonQueryParam() {
29
+ return {
30
+ skip: 0,
31
+ asc: 'created_at',
32
+ include_count: false,
33
+ };
34
+ }
35
+ async start() {
36
+ this.assetsRootPath = (0, node_path_1.resolve)(this.exportConfig.data, this.exportConfig.branchName || '', this.assetConfig.dirName);
37
+ // NOTE step 1: Get assets and it's folder count in parallel
38
+ const [assetsCount, assetsFolderCount] = await Promise.all([this.getAssetsCount(), this.getAssetsCount(true)]);
39
+ // NOTE step 2: Get assets and it's folder data in parallel
40
+ await Promise.all([this.getAssetsFolders(assetsFolderCount), this.getAssets(assetsCount)]);
41
+ // NOTE step 3: Get versioned assets
42
+ if (!(0, isEmpty_1.default)(this.versionedAssets) && this.assetConfig.includeVersionedAssets) {
43
+ await this.getVersionedAssets();
44
+ }
45
+ // NOTE step 4: Download all assets
46
+ await this.downloadAssets();
47
+ (0, utils_1.log)(this.exportConfig, 'Assets exported successfully.!', 'info');
48
+ }
49
+ /**
50
+ * @method getAssetsFolders
51
+ * @param {number} totalCount number
52
+ * @returns Promise<any|void>
53
+ */
54
+ getAssetsFolders(totalCount) {
55
+ if (!totalCount)
56
+ return Promise.resolve();
57
+ const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { query: { is_dir: true } });
58
+ const onSuccess = ({ response: { items } }) => {
59
+ if (!(0, isEmpty_1.default)(items))
60
+ this.assetsFolder.push(...items);
61
+ };
62
+ const onReject = ({ error }) => {
63
+ (0, utils_1.log)(this.exportConfig, 'Export asset folder query failed', 'error');
64
+ (0, utils_1.log)(this.exportConfig, error, 'error');
65
+ };
66
+ return this.makeConcurrentCall({
67
+ totalCount,
68
+ apiParams: {
69
+ queryParam,
70
+ module: 'assets',
71
+ reject: onReject,
72
+ resolve: onSuccess,
73
+ },
74
+ module: 'assets folders',
75
+ concurrencyLimit: this.assetConfig.fetchConcurrency,
76
+ }).then(() => {
77
+ if (!(0, isEmpty_1.default)(this.assetsFolder)) {
78
+ new cli_utilities_1.FsUtility({ basePath: this.assetsRootPath }).writeFile((0, node_path_1.resolve)(this.assetsRootPath, 'folders.json'), this.assetsFolder);
79
+ }
80
+ (0, utils_1.log)(this.exportConfig, 'Assets folder Exported successfully.!', 'info');
81
+ });
82
+ }
83
+ /**
84
+ * @method getAssets
85
+ * @param totalCount number
86
+ * @returns Promise<void>
87
+ */
88
+ getAssets(totalCount) {
89
+ if (!totalCount)
90
+ return Promise.resolve();
91
+ let fs;
92
+ let metaHandler;
93
+ const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { include_publish_details: true, except: { BASE: this.assetConfig.invalidKeys } });
94
+ if (this.assetConfig.includeVersionedAssets) {
95
+ const customHandler = (array) => {
96
+ const versionAssets = (0, filter_1.default)(array, ({ _version }) => _version > 1);
97
+ if (!(0, isEmpty_1.default)(versionAssets)) {
98
+ this.versionedAssets.push(...(0, map_1.default)(versionAssets, ({ uid, _version }) => ({
99
+ [uid]: _version,
100
+ })));
101
+ }
102
+ };
103
+ metaHandler = customHandler;
104
+ }
105
+ const onReject = ({ error }) => {
106
+ (0, utils_1.log)(this.exportConfig, 'Export asset query failed', 'error');
107
+ (0, utils_1.log)(this.exportConfig, error.message, 'error');
108
+ };
109
+ const onSuccess = ({ response: { items } }) => {
110
+ if (!fs && !(0, isEmpty_1.default)(items)) {
111
+ fs = new cli_utilities_1.FsUtility({
112
+ metaHandler,
113
+ moduleName: 'assets',
114
+ indexFileName: 'assets.json',
115
+ basePath: this.assetsRootPath,
116
+ chunkFileSize: this.assetConfig.chunkFileSize,
117
+ metaPickKeys: (0, merge_1.default)(['uid', 'url', 'filename'], this.assetConfig.assetsMetaKeys),
118
+ });
119
+ }
120
+ if (!(0, isEmpty_1.default)(items))
121
+ fs === null || fs === void 0 ? void 0 : fs.writeIntoFile(items, { mapKeyVal: true });
122
+ };
123
+ return this.makeConcurrentCall({
124
+ module: 'assets',
125
+ totalCount,
126
+ apiParams: {
127
+ queryParam,
128
+ module: 'assets',
129
+ reject: onReject,
130
+ resolve: onSuccess,
131
+ },
132
+ concurrencyLimit: this.assetConfig.fetchConcurrency,
133
+ }).then(() => {
134
+ fs === null || fs === void 0 ? void 0 : fs.completeFile(true);
135
+ (0, utils_1.log)(this.exportConfig, 'Assets metadata exported successfully.!', 'info');
136
+ });
137
+ }
138
+ /**
139
+ * @method getVersionedAssets
140
+ * @returns Promise<any|void>
141
+ */
142
+ getVersionedAssets() {
143
+ let fs;
144
+ const queryParam = Object.assign(Object.assign({}, this.commonQueryParam), { include_publish_details: true, except: { BASE: this.assetConfig.invalidKeys } });
145
+ const versionedAssets = (0, map_1.default)(this.versionedAssets, (element) => {
146
+ const batch = [];
147
+ const [uid, version] = (0, first_1.default)((0, entries_1.default)(element));
148
+ for (let index = 1; index < version; index++) {
149
+ batch.push({ [uid]: index });
150
+ }
151
+ return batch;
152
+ }).flat();
153
+ const apiBatches = (0, chunk_1.default)(versionedAssets, this.assetConfig.fetchConcurrency);
154
+ const promisifyHandler = (input) => {
155
+ const { index, batchIndex, apiParams, isLastRequest } = input;
156
+ const batch = apiBatches[batchIndex][index];
157
+ const [uid, version] = (0, first_1.default)((0, entries_1.default)(batch));
158
+ if (apiParams === null || apiParams === void 0 ? void 0 : apiParams.queryParam) {
159
+ apiParams.uid = uid;
160
+ apiParams.queryParam.version = version;
161
+ return this.makeAPICall(apiParams, isLastRequest);
162
+ }
163
+ return Promise.resolve();
164
+ };
165
+ const onSuccess = ({ response }) => {
166
+ if (!fs && !(0, isEmpty_1.default)(response)) {
167
+ fs = new cli_utilities_1.FsUtility({
168
+ moduleName: 'assets',
169
+ indexFileName: 'versioned-assets.json',
170
+ chunkFileSize: this.assetConfig.chunkFileSize,
171
+ basePath: (0, node_path_1.resolve)(this.assetsRootPath, 'versions'),
172
+ metaPickKeys: (0, merge_1.default)(['uid', 'url', 'filename', '_version'], this.assetConfig.assetsMetaKeys),
173
+ });
174
+ }
175
+ if (!(0, isEmpty_1.default)(response))
176
+ fs === null || fs === void 0 ? void 0 : fs.writeIntoFile([response], {
177
+ mapKeyVal: true,
178
+ keyName: ['uid', '_version'],
179
+ });
180
+ };
181
+ const onReject = ({ error }) => {
182
+ (0, utils_1.log)(this.exportConfig, 'Export versioned asset query failed', 'error');
183
+ (0, utils_1.log)(this.exportConfig, error, 'error');
184
+ };
185
+ return this.makeConcurrentCall({
186
+ apiBatches,
187
+ apiParams: {
188
+ queryParam,
189
+ module: 'asset',
190
+ reject: onReject,
191
+ resolve: onSuccess,
192
+ },
193
+ module: 'versioned assets',
194
+ totalCount: versionedAssets.length,
195
+ concurrencyLimit: this.assetConfig.fetchConcurrency,
196
+ }, promisifyHandler).then(() => {
197
+ fs === null || fs === void 0 ? void 0 : fs.completeFile(true);
198
+ (0, utils_1.log)(this.exportConfig, 'Assets folder Exported successfully.!', 'info');
199
+ });
200
+ }
201
+ /**
202
+ * @method getAssetsCount
203
+ * @param isDir boolean
204
+ * @returns Promise<number|undefined>
205
+ */
206
+ getAssetsCount(isDir = false) {
207
+ const queryParam = Object.assign(Object.assign({ limit: 1 }, this.commonQueryParam), { skip: 10 ** 100 });
208
+ if (isDir)
209
+ queryParam.query = { is_dir: true };
210
+ return this.stack
211
+ .asset()
212
+ .query(queryParam)
213
+ .count()
214
+ .then(({ assets }) => assets)
215
+ .catch((error) => {
216
+ (0, utils_1.log)(this.exportConfig, 'Get count query failed', 'error');
217
+ (0, utils_1.log)(this.exportConfig, error, 'error');
218
+ });
219
+ }
220
+ /**
221
+ * @method downloadAssets
222
+ * @returns Promise<any|void>
223
+ */
224
+ async downloadAssets() {
225
+ const fs = new cli_utilities_1.FsUtility({
226
+ fileExt: 'json',
227
+ createDirIfNotExist: false,
228
+ basePath: this.assetsRootPath,
229
+ });
230
+ const assetsMetaData = fs.getPlainMeta();
231
+ let listOfAssets = (0, values_1.default)(assetsMetaData).flat();
232
+ if (this.assetConfig.includeVersionedAssets) {
233
+ const versionedAssetsMetaData = fs.getPlainMeta((0, node_path_1.resolve)(this.assetsRootPath, 'versions', 'metadata.json'));
234
+ listOfAssets.push(...(0, values_1.default)(versionedAssetsMetaData).flat());
235
+ }
236
+ listOfAssets = (0, uniqBy_1.default)(listOfAssets, 'url');
237
+ const apiBatches = (0, chunk_1.default)(listOfAssets, this.assetConfig.downloadLimit);
238
+ const downloadedAssetsDirs = await (0, cli_utilities_1.getDirectories)((0, node_path_1.resolve)(this.assetsRootPath, 'files'));
239
+ const onSuccess = ({ response: { data }, additionalInfo }) => {
240
+ const { asset } = additionalInfo;
241
+ const assetFolderPath = (0, node_path_1.resolve)(this.assetsRootPath, 'files', asset.uid);
242
+ const assetFilePath = (0, node_path_1.resolve)(assetFolderPath, asset.filename);
243
+ if (!(0, includes_1.default)(downloadedAssetsDirs, asset.uid)) {
244
+ fs.createFolderIfNotExist(assetFolderPath);
245
+ }
246
+ const assetWriterStream = (0, node_fs_1.createWriteStream)(assetFilePath);
247
+ assetWriterStream.on('error', (error) => {
248
+ (0, utils_1.log)(this.exportConfig, `Downloaded failed ${asset.filename}: ${asset.uid}!`, 'error');
249
+ (0, utils_1.log)(this.exportConfig, error, 'error');
250
+ });
251
+ /**
252
+ * NOTE if pipe not working as expected add the following code below to fix the issue
253
+ * https://oramind.com/using-streams-efficiently-in-nodejs/
254
+ * import * as stream from "stream";
255
+ * import { promisify } from "util";
256
+ * const finished = promisify(stream.finished);
257
+ * await finished(assetWriterStream);
258
+ */
259
+ if (this.assetConfig.enableDownloadStatus) {
260
+ const str = (0, progress_stream_1.default)({
261
+ time: 5000,
262
+ length: data.headers['content-length'],
263
+ });
264
+ str.on('progress', function (progressData) {
265
+ console.log(`${asset.filename}: ${Math.round(progressData.percentage)}%`);
266
+ });
267
+ data.pipe(str).pipe(assetWriterStream);
268
+ }
269
+ else {
270
+ data.pipe(assetWriterStream);
271
+ }
272
+ (0, utils_1.log)(this.exportConfig, `Downloaded ${asset.filename}: ${asset.uid} successfully!`, 'success');
273
+ };
274
+ const onReject = ({ error, additionalInfo }) => {
275
+ const { asset } = additionalInfo;
276
+ (0, utils_1.log)(this.exportConfig, `Downloaded failed ${asset.filename}: ${asset.uid}!`, 'error');
277
+ (0, utils_1.log)(this.exportConfig, error, 'error');
278
+ };
279
+ const promisifyHandler = (input) => {
280
+ const { index, batchIndex } = input;
281
+ const asset = apiBatches[batchIndex][index];
282
+ const url = this.assetConfig.securedAssets
283
+ ? `${asset.url}?authtoken=${cli_utilities_1.configHandler.get('authtoken')}`
284
+ : asset.url;
285
+ return this.makeAPICall({
286
+ reject: onReject,
287
+ resolve: onSuccess,
288
+ url: encodeURI(url),
289
+ module: 'download-asset',
290
+ additionalInfo: { asset },
291
+ });
292
+ };
293
+ return this.makeConcurrentCall({
294
+ apiBatches,
295
+ module: 'assets download',
296
+ totalCount: listOfAssets.length,
297
+ concurrencyLimit: this.assetConfig.downloadLimit,
298
+ }, promisifyHandler).then(() => {
299
+ (0, utils_1.log)(this.exportConfig, 'Assets download completed successfully.!', 'info');
300
+ });
301
+ }
302
+ }
303
+ exports.default = ExportAssets;
@@ -0,0 +1,48 @@
1
+ import { ExportConfig, ModuleClassParams } from '../../types';
2
+ export type ApiOptions = {
3
+ uid?: string;
4
+ url?: string;
5
+ module: ApiModuleType;
6
+ queryParam?: Record<any, any>;
7
+ resolve: (value: any) => void;
8
+ reject: (error: any) => void;
9
+ additionalInfo?: Record<any, any>;
10
+ };
11
+ export type EnvType = {
12
+ module: string;
13
+ totalCount: number;
14
+ apiBatches?: number[];
15
+ concurrencyLimit: number;
16
+ apiParams?: ApiOptions;
17
+ };
18
+ export type CustomPromiseHandlerInput = {
19
+ index: number;
20
+ batchIndex: number;
21
+ apiParams?: ApiOptions;
22
+ isLastRequest: boolean;
23
+ };
24
+ export type CustomPromiseHandler = (input: CustomPromiseHandlerInput) => Promise<any>;
25
+ export type ApiModuleType = 'stack' | 'asset' | 'assets' | 'entry' | 'entries' | 'content-type' | 'content-types' | 'stacks' | 'download-asset';
26
+ export default abstract class BaseClass {
27
+ readonly client: any;
28
+ exportConfig: ExportConfig;
29
+ constructor({ exportConfig, stackAPIClient }: Omit<ModuleClassParams, 'moduleName'>);
30
+ get stack(): any;
31
+ delay(ms: number): Promise<void>;
32
+ makeConcurrentCall(env: EnvType, promisifyHandler?: CustomPromiseHandler): Promise<void>;
33
+ /**
34
+ * @method logMsgAndWaitIfRequired
35
+ * @param module string
36
+ * @param start number
37
+ * @param batchNo number
38
+ * @returns Promise<void>
39
+ */
40
+ logMsgAndWaitIfRequired(module: string, start: number, batchNo: number): Promise<void>;
41
+ /**
42
+ * @method makeAPICall
43
+ * @param {Record<string, any>} options - Api related params
44
+ * @param {Record<string, any>} isLastRequest - Boolean
45
+ * @returns Promise<any>
46
+ */
47
+ makeAPICall({ module: moduleName, reject, resolve, url, uid, additionalInfo, queryParam }: ApiOptions, isLastRequest?: boolean): Promise<any>;
48
+ }
@@ -0,0 +1,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const map_1 = tslib_1.__importDefault(require("lodash/map"));
5
+ const fill_1 = tslib_1.__importDefault(require("lodash/fill"));
6
+ const last_1 = tslib_1.__importDefault(require("lodash/last"));
7
+ const chunk_1 = tslib_1.__importDefault(require("lodash/chunk"));
8
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
9
+ const entries_1 = tslib_1.__importDefault(require("lodash/entries"));
10
+ const isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual"));
11
+ const utils_1 = require("../../utils");
12
+ class BaseClass {
13
+ constructor({ exportConfig, stackAPIClient }) {
14
+ this.client = stackAPIClient;
15
+ this.exportConfig = exportConfig;
16
+ }
17
+ get stack() {
18
+ return this.client;
19
+ }
20
+ delay(ms) {
21
+ /* eslint-disable no-promise-executor-return */
22
+ return new Promise((resolve) => setTimeout(resolve, ms <= 0 ? 0 : ms));
23
+ }
24
+ makeConcurrentCall(env, promisifyHandler) {
25
+ const { module, apiBatches, totalCount, apiParams, concurrencyLimit } = env;
26
+ /* eslint-disable no-async-promise-executor */
27
+ return new Promise(async (resolve) => {
28
+ let batchNo = 0;
29
+ let isLastRequest = false;
30
+ const batch = (0, fill_1.default)(Array.from({ length: Number.parseInt(String(totalCount / 100), 10) }), 100);
31
+ if (totalCount % 100)
32
+ batch.push(100);
33
+ const batches = apiBatches ||
34
+ (0, chunk_1.default)((0, map_1.default)(batch, (skip, i) => skip * i), concurrencyLimit);
35
+ /* eslint-disable no-promise-executor-return */
36
+ if ((0, isEmpty_1.default)(batches))
37
+ return resolve();
38
+ for (const [batchIndex, batch] of (0, entries_1.default)(batches)) {
39
+ batchNo += 1;
40
+ const allPromise = [];
41
+ const start = Date.now();
42
+ for (const [index, element] of (0, entries_1.default)(batch)) {
43
+ let promise;
44
+ isLastRequest = (0, isEqual_1.default)((0, last_1.default)(batch), element) && (0, isEqual_1.default)((0, last_1.default)(batches), batch);
45
+ if (promisifyHandler instanceof Function) {
46
+ promise = promisifyHandler({
47
+ apiParams,
48
+ isLastRequest,
49
+ index: Number(index),
50
+ batchIndex: Number(batchIndex),
51
+ });
52
+ }
53
+ else if (apiParams === null || apiParams === void 0 ? void 0 : apiParams.queryParam) {
54
+ apiParams.queryParam.skip = element;
55
+ promise = this.makeAPICall(apiParams, isLastRequest);
56
+ }
57
+ allPromise.push(promise);
58
+ }
59
+ /* eslint-disable no-await-in-loop */
60
+ await Promise.allSettled(allPromise);
61
+ /* eslint-disable no-await-in-loop */
62
+ await this.logMsgAndWaitIfRequired(module, start, batchNo);
63
+ if (isLastRequest)
64
+ resolve();
65
+ }
66
+ });
67
+ }
68
+ /**
69
+ * @method logMsgAndWaitIfRequired
70
+ * @param module string
71
+ * @param start number
72
+ * @param batchNo number
73
+ * @returns Promise<void>
74
+ */
75
+ async logMsgAndWaitIfRequired(module, start, batchNo) {
76
+ const end = Date.now();
77
+ const exeTime = end - start;
78
+ (0, utils_1.log)(this.exportConfig, `Batch No. ${batchNo} of ${module} is complete.`, 'success');
79
+ if (this.exportConfig.modules.assets.displayExecutionTime) {
80
+ console.log(`Time taken to execute: ${exeTime} milliseconds; wait time: ${exeTime < 1000 ? 1000 - exeTime : 0} milliseconds`);
81
+ }
82
+ if (exeTime < 1000)
83
+ await this.delay(1000 - exeTime);
84
+ }
85
+ /**
86
+ * @method makeAPICall
87
+ * @param {Record<string, any>} options - Api related params
88
+ * @param {Record<string, any>} isLastRequest - Boolean
89
+ * @returns Promise<any>
90
+ */
91
+ makeAPICall({ module: moduleName, reject, resolve, url = '', uid = '', additionalInfo, queryParam = {} }, isLastRequest = false) {
92
+ switch (moduleName) {
93
+ case 'asset':
94
+ return this.stack
95
+ .asset(uid)
96
+ .fetch(queryParam)
97
+ .then((response) => resolve({ response, isLastRequest, additionalInfo }))
98
+ .catch((error) => reject({ error, isLastRequest, additionalInfo }));
99
+ case 'assets':
100
+ return this.stack
101
+ .asset()
102
+ .query(queryParam)
103
+ .find()
104
+ .then((response) => resolve({ response, isLastRequest, additionalInfo }))
105
+ .catch((error) => reject({ error, isLastRequest, additionalInfo }));
106
+ case 'download-asset':
107
+ return this.stack
108
+ .asset()
109
+ .download({ url, responseType: 'stream' })
110
+ .then((response) => resolve({ response, isLastRequest, additionalInfo }))
111
+ .catch((error) => reject({ error, isLastRequest, additionalInfo }));
112
+ default:
113
+ return Promise.resolve();
114
+ }
115
+ }
116
+ }
117
+ exports.default = BaseClass;
@@ -0,0 +1,3 @@
1
+ import { ModuleClassParams } from '../../types';
2
+ export default function startModuleExport(modulePayload: ModuleClassParams): Promise<any>;
3
+ export { default as ExportAssets } from './assets';
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ var __importDefault = (this && this.__importDefault) || function (mod) {
26
+ return (mod && mod.__esModule) ? mod : { "default": mod };
27
+ };
28
+ var _a;
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.ExportAssets = void 0;
31
+ async function startModuleExport(modulePayload) {
32
+ const { default: ModuleRunner } = await (_a = `./${modulePayload.moduleName}`, Promise.resolve().then(() => __importStar(require(_a))));
33
+ const moduleRunner = new ModuleRunner(modulePayload);
34
+ return moduleRunner.start();
35
+ }
36
+ exports.default = startModuleExport;
37
+ var assets_1 = require("./assets");
38
+ Object.defineProperty(exports, "ExportAssets", { enumerable: true, get: function () { return __importDefault(assets_1).default; } });
@@ -0,0 +1,16 @@
1
+ import { ExportConfig, ModuleClassParams } from '../../types';
2
+ import BaseClass from './base-class';
3
+ export default class LocaleExport extends BaseClass {
4
+ private stackAPIClient;
5
+ exportConfig: ExportConfig;
6
+ private masterLocaleConfig;
7
+ private qs;
8
+ private localeConfig;
9
+ private localesPath;
10
+ private masterLocale;
11
+ private locales;
12
+ constructor({ exportConfig, stackAPIClient }: ModuleClassParams);
13
+ start(): Promise<void>;
14
+ getLocales(skip?: number): Promise<any>;
15
+ sanitizeAttribs(locales: Record<string, string>[]): void;
16
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const path = tslib_1.__importStar(require("path"));
5
+ const utils_1 = require("../../utils");
6
+ const base_class_1 = tslib_1.__importDefault(require("./base-class"));
7
+ class LocaleExport extends base_class_1.default {
8
+ constructor({ exportConfig, stackAPIClient }) {
9
+ super({ exportConfig, stackAPIClient });
10
+ this.stackAPIClient = stackAPIClient;
11
+ this.localeConfig = exportConfig.modules.locales;
12
+ this.masterLocaleConfig = exportConfig.modules.masterLocale;
13
+ this.qs = {
14
+ include_count: true,
15
+ asc: 'updated_at',
16
+ only: {
17
+ BASE: this.localeConfig.requiredKeys,
18
+ },
19
+ };
20
+ this.localesPath = path.resolve(exportConfig.data, exportConfig.branchName || '', this.localeConfig.dirName);
21
+ this.locales = {};
22
+ this.masterLocale = {};
23
+ }
24
+ async start() {
25
+ try {
26
+ (0, utils_1.log)(this.exportConfig, 'Starting locale export', 'success');
27
+ await utils_1.fsUtil.makeDirectory(this.localesPath);
28
+ await this.getLocales();
29
+ utils_1.fsUtil.writeFile(path.join(this.localesPath, this.localeConfig.fileName), this.locales);
30
+ utils_1.fsUtil.writeFile(path.join(this.localesPath, this.masterLocaleConfig.fileName), this.masterLocale);
31
+ (0, utils_1.log)(this.exportConfig, 'Completed locale export', 'success');
32
+ }
33
+ catch (error) {
34
+ (0, utils_1.log)(this.exportConfig, `Failed to export locales. ${(0, utils_1.formatError)(error)}`, 'error');
35
+ throw new Error('Failed to export locales');
36
+ }
37
+ }
38
+ async getLocales(skip = 0) {
39
+ if (skip) {
40
+ this.qs.skip = skip;
41
+ }
42
+ let localesFetchResponse = await this.stackAPIClient.locale().query(this.qs).find();
43
+ if (Array.isArray(localesFetchResponse.items) && localesFetchResponse.items.length > 0) {
44
+ this.sanitizeAttribs(localesFetchResponse.items);
45
+ skip += this.localeConfig.limit || 100;
46
+ if (skip > localesFetchResponse.count) {
47
+ return;
48
+ }
49
+ return await this.getLocales(skip);
50
+ }
51
+ }
52
+ sanitizeAttribs(locales) {
53
+ locales.forEach((locale) => {
54
+ for (let key in locale) {
55
+ if (this.localeConfig.requiredKeys.indexOf(key) === -1) {
56
+ delete locale[key];
57
+ }
58
+ }
59
+ if (locale.code === this.exportConfig.master_locale.code) {
60
+ this.masterLocale[locale.uid] = locale;
61
+ }
62
+ else {
63
+ this.locales[locale.uid] = locale;
64
+ }
65
+ });
66
+ }
67
+ }
68
+ exports.default = LocaleExport;