@contentstack/cli-cm-import 1.29.0 → 1.30.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.
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const node_path_1 = require("node:path");
5
+ const cli_utilities_1 = require("@contentstack/cli-utilities");
6
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
7
+ const utils_1 = require("../../utils");
8
+ class ImportComposableStudio {
9
+ constructor({ importConfig }) {
10
+ this.importConfig = importConfig;
11
+ this.importConfig.context.module = 'composable-studio';
12
+ this.composableStudioConfig = importConfig.modules['composable-studio'];
13
+ // Setup paths
14
+ this.composableStudioPath = (0, node_path_1.join)(this.importConfig.backupDir, this.composableStudioConfig.dirName);
15
+ this.composableStudioFilePath = (0, node_path_1.join)(this.composableStudioPath, this.composableStudioConfig.fileName);
16
+ this.envUidMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'environments', 'uid-mapping.json');
17
+ this.envUidMapper = {};
18
+ // Initialize HttpClient with Studio API base URL
19
+ this.apiClient = new cli_utilities_1.HttpClient();
20
+ this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`);
21
+ }
22
+ /**
23
+ * Entry point for Studio import
24
+ */
25
+ async start() {
26
+ if (this.importConfig.management_token) {
27
+ cli_utilities_1.log.warn('Skipping Studio project import when using management token', this.importConfig.context);
28
+ return;
29
+ }
30
+ cli_utilities_1.log.debug('Starting Studio project import process...', this.importConfig.context);
31
+ try {
32
+ // Initialize authentication
33
+ const authInitialized = await this.addAuthHeaders();
34
+ if (!authInitialized) {
35
+ cli_utilities_1.log.warn('Skipping Studio project import when using OAuth authentication', this.importConfig.context);
36
+ return;
37
+ }
38
+ // Load environment UID mapper
39
+ await this.loadEnvironmentMapper();
40
+ // Read exported project data
41
+ const exportedProject = await this.readExportedProject();
42
+ if (!exportedProject) {
43
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.importConfig.context);
44
+ return;
45
+ }
46
+ cli_utilities_1.log.debug(`Exported project found: ${exportedProject.name}`, this.importConfig.context);
47
+ // Check if target stack already has a connected project
48
+ const existingProject = await this.getExistingProject();
49
+ if (existingProject) {
50
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SKIP_EXISTING'), this.importConfig.context);
51
+ return;
52
+ }
53
+ // Import the project with name conflict handling
54
+ await this.importProject(exportedProject);
55
+ cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_IMPORT_COMPLETE', exportedProject.name), this.importConfig.context);
56
+ }
57
+ catch (error) {
58
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
59
+ }
60
+ }
61
+ /**
62
+ * Initialize authentication headers for API calls
63
+ */
64
+ async addAuthHeaders() {
65
+ cli_utilities_1.log.debug('Initializing Studio API authentication...', this.importConfig.context);
66
+ // Get authentication details - following personalization-api-adapter pattern
67
+ await cli_utilities_1.authenticationHandler.getAuthDetails();
68
+ const token = cli_utilities_1.authenticationHandler.accessToken;
69
+ cli_utilities_1.log.debug(`Authentication type: ${cli_utilities_1.authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, this.importConfig.context);
70
+ // Set authentication headers based on auth type
71
+ if (cli_utilities_1.authenticationHandler.isOauthEnabled) {
72
+ cli_utilities_1.log.debug('Skipping setting OAuth authorization header when using OAuth authentication', this.importConfig.context);
73
+ return false;
74
+ }
75
+ else {
76
+ // TODO: Currenlty assuming if auth type is not OAuth, it is Basic Auth and we are setting authtoken header
77
+ cli_utilities_1.log.debug('Setting authtoken header', this.importConfig.context);
78
+ this.apiClient.headers({ authtoken: token });
79
+ }
80
+ // Set organization_uid header
81
+ this.apiClient.headers({
82
+ organization_uid: this.importConfig.org_uid,
83
+ 'Content-Type': 'application/json',
84
+ Accept: 'application/json',
85
+ });
86
+ cli_utilities_1.log.debug('Studio API authentication initialized', this.importConfig.context);
87
+ return true;
88
+ }
89
+ /**
90
+ * Load environment UID mapper from backup directory
91
+ */
92
+ async loadEnvironmentMapper() {
93
+ cli_utilities_1.log.debug('Loading environment UID mapper...', this.importConfig.context);
94
+ if (utils_1.fileHelper.fileExistsSync(this.envUidMapperPath)) {
95
+ this.envUidMapper = utils_1.fileHelper.readFileSync(this.envUidMapperPath);
96
+ cli_utilities_1.log.debug(`Environment mapper loaded with ${Object.keys(this.envUidMapper).length} mappings`, this.importConfig.context);
97
+ }
98
+ else {
99
+ cli_utilities_1.log.debug('No environment UID mapper found', this.importConfig.context);
100
+ }
101
+ }
102
+ /**
103
+ * Read exported project from file system
104
+ */
105
+ async readExportedProject() {
106
+ cli_utilities_1.log.debug(`Reading exported project from: ${this.composableStudioFilePath}`, this.importConfig.context);
107
+ if (!utils_1.fileHelper.fileExistsSync(this.composableStudioFilePath)) {
108
+ cli_utilities_1.log.debug('Studio project file does not exist', this.importConfig.context);
109
+ return null;
110
+ }
111
+ const projectData = utils_1.fileHelper.readFileSync(this.composableStudioFilePath);
112
+ if (!projectData || (0, isEmpty_1.default)(projectData)) {
113
+ cli_utilities_1.log.debug('Studio project file is empty', this.importConfig.context);
114
+ return null;
115
+ }
116
+ return projectData;
117
+ }
118
+ /**
119
+ * Check if target stack already has a connected project
120
+ */
121
+ async getExistingProject() {
122
+ var _a;
123
+ cli_utilities_1.log.debug('Checking if target stack already has a connected project...', this.importConfig.context);
124
+ try {
125
+ const apiUrl = '/projects';
126
+ cli_utilities_1.log.debug(`Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, this.importConfig.context);
127
+ const response = await this.apiClient.get(apiUrl);
128
+ if (response.status < 200 || response.status >= 300) {
129
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
130
+ }
131
+ const projects = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.projects) || [];
132
+ cli_utilities_1.log.debug(`Found ${projects.length} projects in organization`, this.importConfig.context);
133
+ // Filter projects by connected stack API key
134
+ const connectedProject = projects.find((project) => project.connectedStackApiKey === this.importConfig.apiKey);
135
+ if (connectedProject) {
136
+ cli_utilities_1.log.debug(`Target stack already has connected project: ${connectedProject.name}`, this.importConfig.context);
137
+ return connectedProject;
138
+ }
139
+ cli_utilities_1.log.debug('Target stack does not have a connected project', this.importConfig.context);
140
+ return null;
141
+ }
142
+ catch (error) {
143
+ cli_utilities_1.log.debug(`Error checking for existing project: ${error.message}`, this.importConfig.context);
144
+ throw error;
145
+ }
146
+ }
147
+ /**
148
+ * Import project with name conflict handling
149
+ */
150
+ async importProject(exportedProject) {
151
+ var _a, _b, _c;
152
+ cli_utilities_1.log.debug('Starting project import...', this.importConfig.context);
153
+ // Map environment UID
154
+ const mappedEnvironmentUid = this.mapEnvironmentUid(exportedProject.settings.configuration.environment);
155
+ // Prepare project data for import
156
+ const projectData = {
157
+ name: exportedProject.name,
158
+ connectedStackApiKey: this.importConfig.apiKey,
159
+ contentTypeUid: exportedProject.contentTypeUid,
160
+ description: exportedProject.description || '',
161
+ canvasUrl: exportedProject.canvasUrl || '/',
162
+ settings: {
163
+ configuration: {
164
+ environment: mappedEnvironmentUid,
165
+ locale: ((_b = (_a = exportedProject === null || exportedProject === void 0 ? void 0 : exportedProject.settings) === null || _a === void 0 ? void 0 : _a.configuration) === null || _b === void 0 ? void 0 : _b.locale) || '',
166
+ },
167
+ },
168
+ };
169
+ cli_utilities_1.log.debug(`Project data prepared: ${JSON.stringify(projectData, null, 2)}`, this.importConfig.context);
170
+ // Try to create project with name conflict retry loop
171
+ let projectCreated = false;
172
+ let currentName = projectData.name;
173
+ let attemptCount = 0;
174
+ while (!projectCreated) {
175
+ attemptCount++;
176
+ cli_utilities_1.log.debug(`Attempt ${attemptCount} to create project with name: ${currentName}`, this.importConfig.context);
177
+ projectData.name = currentName;
178
+ const response = await this.apiClient.post('/projects', projectData);
179
+ if (response.status >= 200 && response.status < 300) {
180
+ projectCreated = true;
181
+ cli_utilities_1.log.debug(`Project created successfully with UID: ${(_c = response.data) === null || _c === void 0 ? void 0 : _c.uid}`, this.importConfig.context);
182
+ }
183
+ else {
184
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
185
+ }
186
+ }
187
+ }
188
+ /**
189
+ * Map environment UID from source to target
190
+ */
191
+ mapEnvironmentUid(sourceEnvUid) {
192
+ if (!sourceEnvUid) {
193
+ cli_utilities_1.log.debug('Source environment UID is empty', this.importConfig.context);
194
+ return '';
195
+ }
196
+ cli_utilities_1.log.debug(`Mapping source environment UID: ${sourceEnvUid}`, this.importConfig.context);
197
+ if ((0, isEmpty_1.default)(this.envUidMapper)) {
198
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
199
+ return '';
200
+ }
201
+ const mappedUid = this.envUidMapper[sourceEnvUid];
202
+ if (!mappedUid) {
203
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
204
+ return '';
205
+ }
206
+ cli_utilities_1.log.debug(`Mapped environment UID: ${sourceEnvUid} → ${mappedUid}`, this.importConfig.context);
207
+ return mappedUid;
208
+ }
209
+ /**
210
+ * Prompt user for a new project name when conflict occurs
211
+ */
212
+ async promptForNewProjectName(currentName) {
213
+ const suggestedName = `Copy of ${currentName}`;
214
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NAME_CONFLICT', currentName), this.importConfig.context);
215
+ cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SUGGEST_NAME', suggestedName), this.importConfig.context);
216
+ const response = await cli_utilities_1.cliux.inquire({
217
+ type: 'input',
218
+ name: 'projectName',
219
+ message: 'Enter new project name:',
220
+ default: suggestedName,
221
+ });
222
+ const newName = response.projectName || suggestedName;
223
+ cli_utilities_1.log.debug(`User provided new project name: ${newName}`, this.importConfig.context);
224
+ return newName;
225
+ }
226
+ }
227
+ exports.default = ImportComposableStudio;
@@ -55,25 +55,25 @@ class ContentTypesImport extends base_class_1.default {
55
55
  */
56
56
  this.cTs = utils_1.fsUtil.readFile(path.join(this.cTsFolderPath, 'schema.json'));
57
57
  if (!this.cTs || (0, lodash_1.isEmpty)(this.cTs)) {
58
- cli_utilities_1.log.info('No content type found to import', this.importConfig.context);
58
+ cli_utilities_1.log.info('No content type found to import.', this.importConfig.context);
59
59
  return;
60
60
  }
61
61
  cli_utilities_1.log.debug(`Found ${this.cTs.length} content types to import`, this.importConfig.context);
62
62
  await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
63
- cli_utilities_1.log.debug('Created content types mapper directory', this.importConfig.context);
63
+ cli_utilities_1.log.debug('Created content types mapper directory.', this.importConfig.context);
64
64
  this.installedExtensions = (utils_1.fsUtil.readFile(this.marketplaceAppMapperPath) || { extension_uid: {} }).extension_uid;
65
65
  cli_utilities_1.log.debug(`Loaded ${(_a = Object.keys(this.installedExtensions)) === null || _a === void 0 ? void 0 : _a.length} installed extensions`, this.importConfig.context);
66
66
  this.taxonomies = utils_1.fsUtil.readFile(this.taxonomiesPath);
67
67
  const taxonomyCount = Object.keys(this.taxonomies || {}).length;
68
68
  cli_utilities_1.log.debug(`Loaded ${taxonomyCount} taxonomy definitions`, this.importConfig.context);
69
- cli_utilities_1.log.info('Starting content types seeding process', this.importConfig.context);
69
+ cli_utilities_1.log.info('Starting content types seeding process...', this.importConfig.context);
70
70
  await this.seedCTs();
71
71
  if ((_b = this.createdCTs) === null || _b === void 0 ? void 0 : _b.length) {
72
72
  utils_1.fsUtil.writeFile(this.cTsSuccessPath, this.createdCTs);
73
73
  cli_utilities_1.log.debug(`Written ${this.createdCTs.length} successful content types to file`, this.importConfig.context);
74
74
  }
75
75
  cli_utilities_1.log.success('Created content types', this.importConfig.context);
76
- cli_utilities_1.log.info('Starting content types update process', this.importConfig.context);
76
+ cli_utilities_1.log.info('Starting content types update process...', this.importConfig.context);
77
77
  await this.updateCTs();
78
78
  cli_utilities_1.log.success('Updated content types with references', this.importConfig.context);
79
79
  if (this.fieldRules.length > 0) {
@@ -85,10 +85,10 @@ class ContentTypesImport extends base_class_1.default {
85
85
  if (this.isExtensionsUpdate) {
86
86
  cli_utilities_1.log.success('Successfully updated the extensions.', this.importConfig.context);
87
87
  }
88
- cli_utilities_1.log.info('Starting pending global fields update', this.importConfig.context);
88
+ cli_utilities_1.log.info('Starting pending global fields update...', this.importConfig.context);
89
89
  this.pendingGFs = utils_1.fsUtil.readFile(this.gFsPendingPath);
90
90
  if (!this.pendingGFs || (0, lodash_1.isEmpty)(this.pendingGFs)) {
91
- cli_utilities_1.log.info('No pending global fields found to update', this.importConfig.context);
91
+ cli_utilities_1.log.info('No pending global fields found to update.', this.importConfig.context);
92
92
  return;
93
93
  }
94
94
  await this.updatePendingGFs().catch((error) => {
@@ -105,7 +105,7 @@ class ContentTypesImport extends base_class_1.default {
105
105
  };
106
106
  const onReject = ({ error, apiData: { content_type: { uid = null } = {} } = {} }) => {
107
107
  if (error.errorCode === 115 && (error.errors.uid || error.errors.title)) {
108
- cli_utilities_1.log.info(`${uid} content type already exist`, this.importConfig.context);
108
+ cli_utilities_1.log.info(`${uid} content type already exists.`, this.importConfig.context);
109
109
  cli_utilities_1.log.debug(`Skipping existing content type: ${uid}`, this.importConfig.context);
110
110
  }
111
111
  else {
@@ -252,7 +252,7 @@ class ContentTypesImport extends base_class_1.default {
252
252
  cli_utilities_1.log.debug(`Reading pending extensions from: ${this.extPendingPath}`, this.importConfig.context);
253
253
  if (!apiContent || (apiContent === null || apiContent === void 0 ? void 0 : apiContent.length) === 0) {
254
254
  cli_utilities_1.log.info(`No extensions found to be updated.`, this.importConfig.context);
255
- cli_utilities_1.log.debug('Skipping extensions update - no pending extensions', this.importConfig.context);
255
+ cli_utilities_1.log.debug('Skipping extensions update no pending extensions.', this.importConfig.context);
256
256
  return;
257
257
  }
258
258
  cli_utilities_1.log.debug(`Found ${apiContent.length} extensions to update`, this.importConfig.context);
@@ -274,7 +274,7 @@ class ContentTypesImport extends base_class_1.default {
274
274
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { uid }), `Failed to update '${uid}' extension`);
275
275
  }
276
276
  };
277
- cli_utilities_1.log.debug('Starting extensions update process', this.importConfig.context);
277
+ cli_utilities_1.log.debug('Starting extensions update process...', this.importConfig.context);
278
278
  return await this.makeConcurrentCall({
279
279
  apiContent,
280
280
  processName: 'update extensions',
@@ -21,7 +21,7 @@ class ImportCustomRoles extends base_class_1.default {
21
21
  cli_utilities_1.log.debug(`Transformed ${originalEnvs} environment UIDs for rule`, this.importConfig.context);
22
22
  }
23
23
  else {
24
- cli_utilities_1.log.debug('No environment UID mappings available for transformation', this.importConfig.context);
24
+ cli_utilities_1.log.debug('No environment UID mappings available for transformation.', this.importConfig.context);
25
25
  }
26
26
  }
27
27
  else if (rule.module === 'locale') {
@@ -31,7 +31,7 @@ class ImportCustomRoles extends base_class_1.default {
31
31
  cli_utilities_1.log.debug(`Transformed ${originalLocales} locale UIDs for rule`, this.importConfig.context);
32
32
  }
33
33
  else {
34
- cli_utilities_1.log.debug('No locale UID mappings available for transformation', this.importConfig.context);
34
+ cli_utilities_1.log.debug('No locale UID mappings available for transformation.', this.importConfig.context);
35
35
  }
36
36
  }
37
37
  else if (rule.module === 'entry') {
@@ -41,7 +41,7 @@ class ImportCustomRoles extends base_class_1.default {
41
41
  cli_utilities_1.log.debug(`Transformed ${originalEntries} entry UIDs for rule`, this.importConfig.context);
42
42
  }
43
43
  else {
44
- cli_utilities_1.log.debug('No entry UID mappings available for transformation', this.importConfig.context);
44
+ cli_utilities_1.log.debug('No entry UID mappings available for transformation.', this.importConfig.context);
45
45
  }
46
46
  }
47
47
  return rule;
@@ -70,7 +70,7 @@ class ImportCustomRoles extends base_class_1.default {
70
70
  */
71
71
  async start() {
72
72
  var _a, _b, _c;
73
- cli_utilities_1.log.debug('Checking for custom roles folder existence', this.importConfig.context);
73
+ cli_utilities_1.log.debug('Checking for custom roles folder existence...', this.importConfig.context);
74
74
  //Step1 check folder exists or not
75
75
  if (utils_1.fileHelper.fileExistsSync(this.customRolesFolderPath)) {
76
76
  cli_utilities_1.log.debug(`Found custom roles folder: ${this.customRolesFolderPath}`, this.importConfig.context);
@@ -78,21 +78,21 @@ class ImportCustomRoles extends base_class_1.default {
78
78
  this.customRolesLocales = utils_1.fsUtil.readFile((0, node_path_1.join)(this.customRolesFolderPath, this.customRolesConfig.customRolesLocalesFileName), true);
79
79
  }
80
80
  else {
81
- cli_utilities_1.log.info(`No custom-rules are found - '${this.customRolesFolderPath}'`, this.importConfig.context);
81
+ cli_utilities_1.log.info(`No custom roles found in: ${this.customRolesFolderPath}`, this.importConfig.context);
82
82
  return;
83
83
  }
84
84
  //create webhooks in mapper directory
85
- cli_utilities_1.log.debug('Creating custom roles mapper directory', this.importConfig.context);
85
+ cli_utilities_1.log.debug('Creating custom roles mapper directory...', this.importConfig.context);
86
86
  await utils_1.fsUtil.makeDirectory(this.customRolesMapperPath);
87
- cli_utilities_1.log.debug('Loading existing custom roles UID data', this.importConfig.context);
87
+ cli_utilities_1.log.debug('Loading existing custom roles UID data...', this.importConfig.context);
88
88
  this.customRolesUidMapper = utils_1.fileHelper.fileExistsSync(this.customRolesUidMapperPath)
89
89
  ? utils_1.fsUtil.readFile((0, node_path_1.join)(this.customRolesUidMapperPath), true) || {}
90
90
  : {};
91
- cli_utilities_1.log.debug('Loading environments UID data', this.importConfig.context);
91
+ cli_utilities_1.log.debug('Loading environments UID data...', this.importConfig.context);
92
92
  this.environmentsUidMap = utils_1.fileHelper.fileExistsSync(this.envUidMapperFolderPath)
93
93
  ? utils_1.fsUtil.readFile((0, node_path_1.join)(this.envUidMapperFolderPath, 'uid-mapping.json'), true) || {}
94
94
  : {};
95
- cli_utilities_1.log.debug('Loading entries UID data', this.importConfig.context);
95
+ cli_utilities_1.log.debug('Loading entries UID data...', this.importConfig.context);
96
96
  this.entriesUidMap = utils_1.fileHelper.fileExistsSync(this.entriesUidMapperFolderPath)
97
97
  ? utils_1.fsUtil.readFile((0, node_path_1.join)(this.entriesUidMapperFolderPath, 'uid-mapping.json'), true) || {}
98
98
  : {};
@@ -101,28 +101,28 @@ class ImportCustomRoles extends base_class_1.default {
101
101
  cli_utilities_1.log.debug(`Loaded existing custom roles UID data: ${customRolesUidCount} items`, this.importConfig.context);
102
102
  }
103
103
  else {
104
- cli_utilities_1.log.debug('No existing custom roles UID data found', this.importConfig.context);
104
+ cli_utilities_1.log.debug('No existing custom roles UID data found.', this.importConfig.context);
105
105
  }
106
106
  if (this.environmentsUidMap && ((_a = Object.keys(this.environmentsUidMap || {})) === null || _a === void 0 ? void 0 : _a.length) > 0) {
107
107
  const envUidCount = Object.keys(this.environmentsUidMap || {}).length;
108
108
  cli_utilities_1.log.debug(`Loaded environments UID data: ${envUidCount} items`, this.importConfig.context);
109
109
  }
110
110
  else {
111
- cli_utilities_1.log.debug('No environments UID data found', this.importConfig.context);
111
+ cli_utilities_1.log.debug('No environments UID data found.', this.importConfig.context);
112
112
  }
113
113
  if (this.entriesUidMap && Object.keys(this.entriesUidMap || {}).length > 0) {
114
114
  const entriesUidCount = Object.keys(this.entriesUidMap || {}).length;
115
115
  cli_utilities_1.log.debug(`Loaded entries UID data: ${entriesUidCount} items`, this.importConfig.context);
116
116
  }
117
117
  else {
118
- cli_utilities_1.log.debug('No entries UID data found', this.importConfig.context);
118
+ cli_utilities_1.log.debug('No entries UID data found.', this.importConfig.context);
119
119
  }
120
120
  //source and target stack locale map
121
- cli_utilities_1.log.debug('Getting locales UID mapping', this.importConfig.context);
121
+ cli_utilities_1.log.debug('Getting locales UID mapping...', this.importConfig.context);
122
122
  await this.getLocalesUidMap();
123
- cli_utilities_1.log.debug('Starting custom roles import', this.importConfig.context);
123
+ cli_utilities_1.log.debug('Starting custom roles import...', this.importConfig.context);
124
124
  await this.importCustomRoles();
125
- cli_utilities_1.log.debug('Processing custom roles import results', this.importConfig.context);
125
+ cli_utilities_1.log.debug('Processing custom roles import results...', this.importConfig.context);
126
126
  if ((_b = this.createdCustomRoles) === null || _b === void 0 ? void 0 : _b.length) {
127
127
  utils_1.fsUtil.writeFile(this.createdCustomRolesPath, this.createdCustomRoles);
128
128
  cli_utilities_1.log.debug(`Written ${this.createdCustomRoles.length} successful custom roles to file`, this.importConfig.context);
@@ -134,7 +134,7 @@ class ImportCustomRoles extends base_class_1.default {
134
134
  cli_utilities_1.log.success('Custom roles have been imported successfully!', this.importConfig.context);
135
135
  }
136
136
  async getLocalesUidMap() {
137
- cli_utilities_1.log.debug('Fetching target stack locales', this.importConfig.context);
137
+ cli_utilities_1.log.debug('Fetching target stack locales...', this.importConfig.context);
138
138
  const { items } = await this.stack
139
139
  .locale()
140
140
  .query()
@@ -145,21 +145,21 @@ class ImportCustomRoles extends base_class_1.default {
145
145
  return data;
146
146
  })
147
147
  .catch((error) => {
148
- cli_utilities_1.log.debug('Error fetching target stack locales', this.importConfig.context);
148
+ cli_utilities_1.log.debug('Error fetching target stack locales!', this.importConfig.context);
149
149
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
150
150
  });
151
151
  this.targetLocalesMap = {};
152
152
  this.sourceLocalesMap = {};
153
- cli_utilities_1.log.debug('Building target locales mapping', this.importConfig.context);
153
+ cli_utilities_1.log.debug('Building target locales mapping...', this.importConfig.context);
154
154
  (0, lodash_1.forEach)(items, (locale) => {
155
155
  this.targetLocalesMap[locale.code] = locale.uid;
156
156
  });
157
- cli_utilities_1.log.debug('Building source locales mapping', this.importConfig.context);
157
+ cli_utilities_1.log.debug('Building source locales mapping...', this.importConfig.context);
158
158
  for (const key in this.customRolesLocales) {
159
159
  const sourceLocales = this.customRolesLocales[key];
160
160
  this.sourceLocalesMap[sourceLocales.code] = key;
161
161
  }
162
- cli_utilities_1.log.debug('Creating locale UID mapping', this.importConfig.context);
162
+ cli_utilities_1.log.debug('Creating locale UID mapping...', this.importConfig.context);
163
163
  for (const key in this.sourceLocalesMap) {
164
164
  const sourceLocaleKey = this.sourceLocalesMap[key];
165
165
  this.localesUidMap[sourceLocaleKey] = this.targetLocalesMap[key];
@@ -168,9 +168,9 @@ class ImportCustomRoles extends base_class_1.default {
168
168
  cli_utilities_1.log.debug(`Created ${localesMappingCount} locale UID mappings`, this.importConfig.context);
169
169
  }
170
170
  async importCustomRoles() {
171
- cli_utilities_1.log.debug('Starting custom roles import process', this.importConfig.context);
171
+ cli_utilities_1.log.debug('Starting custom roles import process...', this.importConfig.context);
172
172
  if (this.customRoles === undefined || (0, isEmpty_1.default)(this.customRoles)) {
173
- cli_utilities_1.log.info('No custom-roles found', this.importConfig.context);
173
+ cli_utilities_1.log.info('No custom roles found', this.importConfig.context);
174
174
  return;
175
175
  }
176
176
  const apiContent = (0, values_1.default)(this.customRoles);
@@ -188,7 +188,7 @@ class ImportCustomRoles extends base_class_1.default {
188
188
  const { name } = apiData;
189
189
  cli_utilities_1.log.debug(`Custom role '${name}' import failed`, this.importConfig.context);
190
190
  if ((_a = err === null || err === void 0 ? void 0 : err.errors) === null || _a === void 0 ? void 0 : _a.name) {
191
- cli_utilities_1.log.info(`custom-role '${name}' already exists`, this.importConfig.context);
191
+ cli_utilities_1.log.info(`Custom role '${name}' already exists.`, this.importConfig.context);
192
192
  }
193
193
  else {
194
194
  this.failedCustomRoles.push(apiData);
@@ -208,7 +208,7 @@ class ImportCustomRoles extends base_class_1.default {
208
208
  },
209
209
  concurrencyLimit: this.importConfig.fetchConcurrency || 1,
210
210
  }, undefined, false);
211
- cli_utilities_1.log.debug('Custom roles import process completed', this.importConfig.context);
211
+ cli_utilities_1.log.debug('Custom roles import process completed.', this.importConfig.context);
212
212
  }
213
213
  /**
214
214
  * @method serializeWebhooks
@@ -53,21 +53,21 @@ class EntriesImport extends base_class_1.default {
53
53
  }
54
54
  cli_utilities_1.log.debug(`Found ${this.cTs.length} content types for entry import`, this.importConfig.context);
55
55
  this.installedExtensions = (utils_1.fsUtil.readFile(this.marketplaceAppMapperPath) || { extension_uid: {} }).extension_uid;
56
- cli_utilities_1.log.debug('Loaded installed extensions for entry processing', this.importConfig.context);
56
+ cli_utilities_1.log.debug('Loaded installed extensions for entry processing.', this.importConfig.context);
57
57
  this.assetUidMapper = utils_1.fsUtil.readFile(this.assetUidMapperPath) || {};
58
58
  this.assetUrlMapper = utils_1.fsUtil.readFile(this.assetUrlMapperPath) || {};
59
- cli_utilities_1.log.debug(`Loaded asset mappings - UIDs: ${Object.keys(this.assetUidMapper).length}, URLs: ${Object.keys(this.assetUrlMapper).length}`, this.importConfig.context);
59
+ cli_utilities_1.log.debug(`Loaded asset mappings UIDs: ${Object.keys(this.assetUidMapper).length}`, this.importConfig.context);
60
60
  this.taxonomies = (utils_1.fsUtil.readFile(this.taxonomiesPath) || {});
61
- cli_utilities_1.log.debug('Loaded taxonomy data for entry processing', this.importConfig.context);
61
+ cli_utilities_1.log.debug('Loaded taxonomy data for entry processing.', this.importConfig.context);
62
62
  utils_1.fsUtil.makeDirectory(this.entriesMapperPath);
63
- cli_utilities_1.log.debug('Created entries mapper directory', this.importConfig.context);
64
- cli_utilities_1.log.info('Preparing content types for entry import', this.importConfig.context);
63
+ cli_utilities_1.log.debug('Created entries mapper directory.', this.importConfig.context);
64
+ cli_utilities_1.log.info('Preparing content types for entry import...', this.importConfig.context);
65
65
  await this.disableMandatoryCTReferences();
66
66
  this.locales = (0, lodash_1.values)((utils_1.fsUtil.readFile(this.localesPath) || []));
67
67
  this.locales.unshift(this.importConfig.master_locale); // adds master locale to the list
68
68
  cli_utilities_1.log.debug(`Processing entries for ${(0, lodash_1.values)(this.locales).length} locales`, this.importConfig.context);
69
69
  //Create Entries
70
- cli_utilities_1.log.info('Starting entry creation process', this.importConfig.context);
70
+ cli_utilities_1.log.info('Starting entry creation process...', this.importConfig.context);
71
71
  const entryRequestOptions = this.populateEntryCreatePayload();
72
72
  cli_utilities_1.log.debug(`Generated ${entryRequestOptions.length} entry creation tasks`, this.importConfig.context);
73
73
  for (let entryRequestOption of entryRequestOptions) {
@@ -76,7 +76,7 @@ class EntriesImport extends base_class_1.default {
76
76
  cli_utilities_1.log.success('Entry creation process completed', this.importConfig.context);
77
77
  if (this.importConfig.replaceExisting) {
78
78
  // Note: Instead of using entryRequestOptions, we can prepare request options for replace, to avoid unnecessary operations
79
- cli_utilities_1.log.info('Starting entry replacement process', this.importConfig.context);
79
+ cli_utilities_1.log.info('Starting entry replacement process...', this.importConfig.context);
80
80
  for (let entryRequestOption of entryRequestOptions) {
81
81
  await this.replaceEntries(entryRequestOption).catch((error) => {
82
82
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign(Object.assign({}, this.importConfig.context), { cTUid: entryRequestOption.cTUid, locale: entryRequestOption.locale }), 'Error while replacing existing entries');
@@ -84,18 +84,18 @@ class EntriesImport extends base_class_1.default {
84
84
  }
85
85
  cli_utilities_1.log.success('Entry replacement process completed', this.importConfig.context);
86
86
  }
87
- cli_utilities_1.log.debug('Writing entry UID mappings to file', this.importConfig.context);
87
+ cli_utilities_1.log.debug('Writing entry UID mappings to file...', this.importConfig.context);
88
88
  await utils_1.fileHelper.writeLargeFile(path.join(this.entriesMapperPath, 'uid-mapping.json'), this.entriesUidMapper); // TBD: manages mapper in one file, should find an alternative
89
89
  utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
90
90
  if (((_a = this.autoCreatedEntries) === null || _a === void 0 ? void 0 : _a.length) > 0) {
91
- cli_utilities_1.log.info(`Removing ${this.autoCreatedEntries.length} entries from master language which got created by default`, this.importConfig.context);
91
+ cli_utilities_1.log.info(`Removing ${this.autoCreatedEntries.length} auto-created entries from the master language...`, this.importConfig.context);
92
92
  await this.removeAutoCreatedEntries().catch((error) => {
93
93
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context), 'Error while removing auto created entries in master locale');
94
94
  });
95
95
  cli_utilities_1.log.success('Auto-created entries cleanup completed', this.importConfig.context);
96
96
  }
97
97
  // Update entries with references
98
- cli_utilities_1.log.info('Starting entry references update process', this.importConfig.context);
98
+ cli_utilities_1.log.info('Starting entry references update process...', this.importConfig.context);
99
99
  const entryUpdateRequestOptions = this.populateEntryUpdatePayload();
100
100
  cli_utilities_1.log.debug(`Generated ${entryUpdateRequestOptions.length} entry update tasks`, this.importConfig.context);
101
101
  for (let entryUpdateRequestOption of entryUpdateRequestOptions) {
@@ -105,27 +105,27 @@ class EntriesImport extends base_class_1.default {
105
105
  }
106
106
  utils_1.fsUtil.writeFile(path.join(this.entriesMapperPath, 'failed-entries.json'), this.failedEntries);
107
107
  cli_utilities_1.log.success('Entry references update process completed', this.importConfig.context);
108
- cli_utilities_1.log.info('Restoring content type changes', this.importConfig.context);
108
+ cli_utilities_1.log.info('Restoring content type changes...', this.importConfig.context);
109
109
  await this.enableMandatoryCTReferences().catch((error) => {
110
110
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context), 'Error while updating content type references');
111
111
  });
112
112
  cli_utilities_1.log.success('Content type references restored successfully', this.importConfig.context);
113
113
  // Update field rule of content types which are got removed earlier
114
- cli_utilities_1.log.info('Updating the field rules of content type', this.importConfig.context);
114
+ cli_utilities_1.log.info('Updating field rules of content type...', this.importConfig.context);
115
115
  await this.updateFieldRules().catch((error) => {
116
116
  (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context), 'Error while updating field rules of content type');
117
117
  });
118
118
  cli_utilities_1.log.success('Entries imported successfully', this.importConfig.context);
119
119
  // Publishing entries
120
120
  if (!this.importConfig.skipEntriesPublish) {
121
- cli_utilities_1.log.info('Starting entry publishing process', this.importConfig.context);
121
+ cli_utilities_1.log.info('Starting entry publishing process...', this.importConfig.context);
122
122
  this.envs = utils_1.fileHelper.readFileSync(this.envPath) || {};
123
123
  if (Object.keys(this.envs).length === 0) {
124
124
  cli_utilities_1.log.warn(`No environments file found at ${this.envPath}. Entries will not be published.`, this.importConfig.context);
125
125
  return;
126
126
  }
127
127
  else {
128
- cli_utilities_1.log.debug(`Loaded ${Object.keys(this.envs).length} environments for publishing`, this.importConfig.context);
128
+ cli_utilities_1.log.debug(`Loaded ${Object.keys(this.envs).length} environments.`, this.importConfig.context);
129
129
  }
130
130
  for (let entryRequestOption of entryRequestOptions) {
131
131
  await this.publishEntries(entryRequestOption).catch((error) => {
@@ -135,9 +135,9 @@ class EntriesImport extends base_class_1.default {
135
135
  cli_utilities_1.log.success('All the entries have been published successfully', this.importConfig.context);
136
136
  }
137
137
  else {
138
- cli_utilities_1.log.info('Skipping entry publishing as per configuration', this.importConfig.context);
138
+ cli_utilities_1.log.info('Skipping entry publishing as per configuration...', this.importConfig.context);
139
139
  }
140
- cli_utilities_1.log.debug('Creating entry data for variant entries', this.importConfig.context);
140
+ cli_utilities_1.log.debug('Creating entry data for variant entries...', this.importConfig.context);
141
141
  this.createEntryDataForVariantEntry();
142
142
  }
143
143
  catch (error) {
@@ -372,6 +372,23 @@ class EntriesImport extends base_class_1.default {
372
372
  });
373
373
  }
374
374
  }
375
+ /**
376
+ * Why Delay Here ?
377
+ * ==================
378
+ * When the file is written to the disk, the file is not yet available to be read by the next operation.
379
+ * existing entries file is written here and used in the replace entries operation. Sometimes it happens that the file is not completed writing to the disk, so replace operation fails.
380
+ * Solution:
381
+ * =========
382
+ * Add a delay to ensure that the file is completed writing to the disk.
383
+ * This is a temporary workaround, TODO: find a better way to do this.
384
+ * When replaceEntries tries to read the file immediately after, the file might still be incomplete because:
385
+ * completeFile() calls write('}') (line 294) - buffered, not yet on disk
386
+ * closeFile() calls end() (line 318) - closes stream but doesn't wait for flush
387
+ * replaceEntries immediately tries to read - file is incomplete!
388
+ * The completeFile() method in FsUtility needs to wait for the stream to finish flushing before returning. Here's what needs to be changed in the FsUtility
389
+ * */
390
+ await new Promise((resolve) => setTimeout(resolve, 200));
391
+ cli_utilities_1.log.success(`Completed creating entries for content type ${cTUid} in locale ${locale}`, this.importConfig.context);
375
392
  }
376
393
  /**
377
394
  * @method serializeEntries
@@ -730,7 +747,7 @@ class EntriesImport extends base_class_1.default {
730
747
  var _a, _b, _c;
731
748
  let cTsWithFieldRules = (utils_1.fsUtil.readFile(path.join(this.cTsPath + '/field_rules_uid.json')) || []);
732
749
  if (!cTsWithFieldRules || (cTsWithFieldRules === null || cTsWithFieldRules === void 0 ? void 0 : cTsWithFieldRules.length) === 0) {
733
- cli_utilities_1.log.debug('No content types with field rules found to update', this.importConfig.context);
750
+ cli_utilities_1.log.debug('No content types with field rules found to update.', this.importConfig.context);
734
751
  return;
735
752
  }
736
753
  cli_utilities_1.log.debug(`Found ${cTsWithFieldRules.length} content types with field rules to update`, this.importConfig.context);
@@ -745,7 +762,7 @@ class EntriesImport extends base_class_1.default {
745
762
  const field = contentType.schema[i].uid;
746
763
  fieldDatatypeMap[field] = contentType.schema[i].data_type;
747
764
  }
748
- cli_utilities_1.log.debug(`Built field datatype map for ${Object.keys(fieldDatatypeMap).length} fields`, this.importConfig.context);
765
+ cli_utilities_1.log.debug(`Built field datatype map for ${Object.keys(fieldDatatypeMap).length} fields.`, this.importConfig.context);
749
766
  let fieldRuleLength = (_b = contentType.field_rules) === null || _b === void 0 ? void 0 : _b.length;
750
767
  let updatedRulesCount = 0;
751
768
  for (let k = 0; k < fieldRuleLength; k++) {