@contentstack/cli-cm-import 2.0.0-beta.1 → 2.0.0-beta.11

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 (54) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +50 -96
  3. package/lib/commands/cm/stacks/import.d.ts +0 -1
  4. package/lib/commands/cm/stacks/import.js +13 -46
  5. package/lib/config/index.js +7 -0
  6. package/lib/constants/index.d.ts +57 -0
  7. package/lib/constants/index.js +59 -0
  8. package/lib/import/module-importer.js +4 -4
  9. package/lib/import/modules/assets.js +18 -9
  10. package/lib/import/modules/base-class.d.ts +21 -4
  11. package/lib/import/modules/base-class.js +31 -1
  12. package/lib/import/modules/composable-studio.d.ts +44 -0
  13. package/lib/import/modules/composable-studio.js +235 -0
  14. package/lib/import/modules/content-types.d.ts +2 -0
  15. package/lib/import/modules/content-types.js +52 -13
  16. package/lib/import/modules/custom-roles.js +10 -10
  17. package/lib/import/modules/entries.d.ts +2 -0
  18. package/lib/import/modules/entries.js +41 -36
  19. package/lib/import/modules/environments.js +6 -6
  20. package/lib/import/modules/extensions.js +7 -7
  21. package/lib/import/modules/global-fields.d.ts +1 -1
  22. package/lib/import/modules/global-fields.js +10 -10
  23. package/lib/import/modules/labels.js +6 -6
  24. package/lib/import/modules/locales.d.ts +1 -1
  25. package/lib/import/modules/locales.js +8 -8
  26. package/lib/import/modules/marketplace-apps.js +6 -6
  27. package/lib/import/modules/personalize.js +2 -3
  28. package/lib/import/modules/stack.js +5 -5
  29. package/lib/import/modules/taxonomies.d.ts +26 -3
  30. package/lib/import/modules/taxonomies.js +180 -63
  31. package/lib/import/modules/variant-entries.js +5 -5
  32. package/lib/import/modules/webhooks.js +6 -6
  33. package/lib/import/modules/workflows.d.ts +1 -1
  34. package/lib/import/modules/workflows.js +7 -7
  35. package/lib/types/default-config.d.ts +6 -0
  36. package/lib/types/index.d.ts +37 -11
  37. package/lib/utils/asset-helper.js +1 -1
  38. package/lib/utils/common-helper.d.ts +1 -1
  39. package/lib/utils/common-helper.js +8 -7
  40. package/lib/utils/content-type-helper.d.ts +1 -1
  41. package/lib/utils/content-type-helper.js +3 -3
  42. package/lib/utils/extension-helper.js +5 -4
  43. package/lib/utils/file-helper.js +1 -1
  44. package/lib/utils/import-config-handler.js +7 -13
  45. package/lib/utils/import-path-resolver.js +2 -8
  46. package/lib/utils/logger.d.ts +1 -1
  47. package/lib/utils/logger.js +2 -2
  48. package/lib/utils/login-handler.d.ts +1 -1
  49. package/lib/utils/login-handler.js +4 -4
  50. package/lib/utils/marketplace-app-helper.js +9 -6
  51. package/lib/utils/taxonomies-helper.js +1 -1
  52. package/messages/index.json +10 -1
  53. package/oclif.manifest.json +4 -48
  54. package/package.json +16 -18
@@ -54,6 +54,34 @@ class BaseClass {
54
54
  (_a = this.progressManager) === null || _a === void 0 ? void 0 : _a.complete(success, error);
55
55
  this.progressManager = null;
56
56
  }
57
+ /**
58
+ * Complete progress and log success/warning message based on errors
59
+ * Checks the progress manager's failure count to determine if errors occurred
60
+ * @param options - Options object containing:
61
+ * - moduleName: The module name to generate the message (e.g., 'Content types', 'Entries')
62
+ * If not provided, uses this.currentModuleName
63
+ * - customSuccessMessage: Optional custom success message. If not provided, generates: "{moduleName} have been imported successfully!"
64
+ * - customWarningMessage: Optional custom warning message. If not provided, generates: "{moduleName} have been imported with some errors. Please check the logs at: {sessionLogPath}"
65
+ * - context: Optional context for logging
66
+ */
67
+ completeProgressWithMessage(options) {
68
+ var _a, _b;
69
+ const logContext = (options === null || options === void 0 ? void 0 : options.context) || ((_a = this.importConfig) === null || _a === void 0 ? void 0 : _a.context) || {};
70
+ const failureCount = ((_b = this.progressManager) === null || _b === void 0 ? void 0 : _b.getFailureCount()) || 0;
71
+ const hasErrors = failureCount > 0;
72
+ const name = (options === null || options === void 0 ? void 0 : options.moduleName) || this.currentModuleName || 'Module';
73
+ // Generate default messages if not provided
74
+ const successMessage = (options === null || options === void 0 ? void 0 : options.customSuccessMessage) || `${name} have been imported successfully!`;
75
+ const sessionLogPath = (0, cli_utilities_1.getSessionLogPath)();
76
+ const warningMessage = (options === null || options === void 0 ? void 0 : options.customWarningMessage) || `${name} have been imported with some errors. Please check the logs at: ${sessionLogPath}`;
77
+ this.completeProgress(true);
78
+ if (hasErrors) {
79
+ cli_utilities_1.log.warn(warningMessage, logContext);
80
+ }
81
+ else {
82
+ cli_utilities_1.log.success(successMessage, logContext);
83
+ }
84
+ }
57
85
  async withLoadingSpinner(message, action) {
58
86
  var _a;
59
87
  const logConfig = cli_utilities_1.configHandler.get('log') || {};
@@ -337,7 +365,9 @@ class BaseClass {
337
365
  if (!apiData || !apiData.filePath) {
338
366
  return Promise.resolve();
339
367
  }
340
- return this.stack.taxonomy(uid).import({ taxonomy: apiData.filePath }).then(onSuccess).catch(onReject);
368
+ const importParams = { taxonomy: apiData.filePath };
369
+ const importQueryParam = apiOptions.queryParam || {};
370
+ return this.stack.taxonomy(uid).import(importParams, importQueryParam).then(onSuccess).catch(onReject);
341
371
  default:
342
372
  return Promise.resolve();
343
373
  }
@@ -0,0 +1,44 @@
1
+ import { ModuleClassParams, ComposableStudioProject } from '../../types';
2
+ export default class ImportComposableStudio {
3
+ private importConfig;
4
+ private composableStudioConfig;
5
+ private composableStudioPath;
6
+ private composableStudioFilePath;
7
+ private apiClient;
8
+ private envUidMapperPath;
9
+ private envUidMapper;
10
+ private projectMapperPath;
11
+ constructor({ importConfig }: ModuleClassParams);
12
+ /**
13
+ * Entry point for Studio import
14
+ */
15
+ start(): Promise<void>;
16
+ /**
17
+ * Initialize authentication headers for API calls
18
+ */
19
+ addAuthHeaders(): Promise<boolean>;
20
+ /**
21
+ * Load environment UID mapper from backup directory
22
+ */
23
+ loadEnvironmentMapper(): Promise<void>;
24
+ /**
25
+ * Read exported project from file system
26
+ */
27
+ readExportedProject(): Promise<ComposableStudioProject | null>;
28
+ /**
29
+ * Check if target stack already has a connected project
30
+ */
31
+ getExistingProject(): Promise<ComposableStudioProject | null>;
32
+ /**
33
+ * Import project with name conflict handling
34
+ */
35
+ importProject(exportedProject: ComposableStudioProject): Promise<void>;
36
+ /**
37
+ * Map environment UID from source to target
38
+ */
39
+ mapEnvironmentUid(sourceEnvUid: string): string;
40
+ /**
41
+ * Prompt user for a new project name when conflict occurs
42
+ */
43
+ promptForNewProjectName(currentName: string): Promise<string>;
44
+ }
@@ -0,0 +1,235 @@
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 constants_1 = require("../../constants");
7
+ const isEmpty_1 = tslib_1.__importDefault(require("lodash/isEmpty"));
8
+ const utils_1 = require("../../utils");
9
+ class ImportComposableStudio {
10
+ constructor({ importConfig }) {
11
+ this.importConfig = importConfig;
12
+ this.importConfig.context.module = 'composable-studio';
13
+ this.composableStudioConfig = importConfig.modules['composable-studio'];
14
+ // Setup paths
15
+ this.composableStudioPath = (0, node_path_1.join)(this.importConfig.backupDir, this.composableStudioConfig.dirName);
16
+ this.projectMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, this.composableStudioConfig.dirName);
17
+ this.composableStudioFilePath = (0, node_path_1.join)(this.composableStudioPath, this.composableStudioConfig.fileName);
18
+ this.envUidMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.ENVIRONMENTS, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
19
+ this.envUidMapper = {};
20
+ // Initialize HttpClient with Studio API base URL
21
+ this.apiClient = new cli_utilities_1.HttpClient();
22
+ this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`);
23
+ }
24
+ /**
25
+ * Entry point for Studio import
26
+ */
27
+ async start() {
28
+ if (this.importConfig.management_token) {
29
+ cli_utilities_1.log.warn('Skipping Studio project import when using management token', this.importConfig.context);
30
+ return;
31
+ }
32
+ cli_utilities_1.log.debug('Starting Studio project import process...', this.importConfig.context);
33
+ try {
34
+ // Initialize authentication
35
+ const authInitialized = await this.addAuthHeaders();
36
+ if (!authInitialized) {
37
+ cli_utilities_1.log.warn('Skipping Studio project import when using OAuth authentication', this.importConfig.context);
38
+ return;
39
+ }
40
+ // Load environment UID mapper
41
+ await this.loadEnvironmentMapper();
42
+ // Read exported project data
43
+ const exportedProject = await this.readExportedProject();
44
+ if (!exportedProject) {
45
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.importConfig.context);
46
+ return;
47
+ }
48
+ cli_utilities_1.log.debug(`Exported project found: ${exportedProject.name}`, this.importConfig.context);
49
+ // Check if target stack already has a connected project
50
+ const existingProject = await this.getExistingProject();
51
+ if (existingProject) {
52
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SKIP_EXISTING'), this.importConfig.context);
53
+ return;
54
+ }
55
+ // Import the project with name conflict handling
56
+ await this.importProject(exportedProject);
57
+ cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_IMPORT_COMPLETE', exportedProject.name), this.importConfig.context);
58
+ }
59
+ catch (error) {
60
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
61
+ }
62
+ }
63
+ /**
64
+ * Initialize authentication headers for API calls
65
+ */
66
+ async addAuthHeaders() {
67
+ cli_utilities_1.log.debug('Initializing Studio API authentication...', this.importConfig.context);
68
+ // Get authentication details - following personalization-api-adapter pattern
69
+ await cli_utilities_1.authenticationHandler.getAuthDetails();
70
+ const token = cli_utilities_1.authenticationHandler.accessToken;
71
+ cli_utilities_1.log.debug(`Authentication type: ${cli_utilities_1.authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, this.importConfig.context);
72
+ // Set authentication headers based on auth type
73
+ if (cli_utilities_1.authenticationHandler.isOauthEnabled) {
74
+ cli_utilities_1.log.debug('Skipping setting OAuth authorization header when using OAuth authentication', this.importConfig.context);
75
+ return false;
76
+ }
77
+ else {
78
+ // TODO: Currenlty assuming if auth type is not OAuth, it is Basic Auth and we are setting authtoken header
79
+ cli_utilities_1.log.debug('Setting authtoken header', this.importConfig.context);
80
+ this.apiClient.headers({ authtoken: token });
81
+ }
82
+ // Set organization_uid header
83
+ this.apiClient.headers({
84
+ organization_uid: this.importConfig.org_uid,
85
+ 'Content-Type': 'application/json',
86
+ Accept: 'application/json',
87
+ });
88
+ cli_utilities_1.log.debug('Studio API authentication initialized', this.importConfig.context);
89
+ return true;
90
+ }
91
+ /**
92
+ * Load environment UID mapper from backup directory
93
+ */
94
+ async loadEnvironmentMapper() {
95
+ cli_utilities_1.log.debug('Loading environment UID mapper...', this.importConfig.context);
96
+ if (utils_1.fileHelper.fileExistsSync(this.envUidMapperPath)) {
97
+ this.envUidMapper = utils_1.fileHelper.readFileSync(this.envUidMapperPath);
98
+ cli_utilities_1.log.debug(`Environment mapper loaded with ${Object.keys(this.envUidMapper).length} mappings`, this.importConfig.context);
99
+ }
100
+ else {
101
+ cli_utilities_1.log.debug('No environment UID mapper found', this.importConfig.context);
102
+ }
103
+ }
104
+ /**
105
+ * Read exported project from file system
106
+ */
107
+ async readExportedProject() {
108
+ cli_utilities_1.log.debug(`Reading exported project from: ${this.composableStudioFilePath}`, this.importConfig.context);
109
+ if (!utils_1.fileHelper.fileExistsSync(this.composableStudioFilePath)) {
110
+ cli_utilities_1.log.debug('Studio project file does not exist', this.importConfig.context);
111
+ return null;
112
+ }
113
+ const projectData = utils_1.fileHelper.readFileSync(this.composableStudioFilePath);
114
+ if (!projectData || (0, isEmpty_1.default)(projectData)) {
115
+ cli_utilities_1.log.debug('Studio project file is empty', this.importConfig.context);
116
+ return null;
117
+ }
118
+ return projectData;
119
+ }
120
+ /**
121
+ * Check if target stack already has a connected project
122
+ */
123
+ async getExistingProject() {
124
+ var _a;
125
+ cli_utilities_1.log.debug('Checking if target stack already has a connected project...', this.importConfig.context);
126
+ try {
127
+ const apiUrl = '/projects';
128
+ cli_utilities_1.log.debug(`Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, this.importConfig.context);
129
+ const response = await this.apiClient.get(apiUrl);
130
+ if (response.status < 200 || response.status >= 300) {
131
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
132
+ }
133
+ const projects = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.projects) || [];
134
+ cli_utilities_1.log.debug(`Found ${projects.length} projects in organization`, this.importConfig.context);
135
+ // Filter projects by connected stack API key
136
+ const connectedProject = projects.find((project) => project.connectedStackApiKey === this.importConfig.apiKey);
137
+ if (connectedProject) {
138
+ cli_utilities_1.log.debug(`Target stack already has connected project: ${connectedProject.name}`, this.importConfig.context);
139
+ return connectedProject;
140
+ }
141
+ cli_utilities_1.log.debug('Target stack does not have a connected project', this.importConfig.context);
142
+ return null;
143
+ }
144
+ catch (error) {
145
+ cli_utilities_1.log.debug(`Error checking for existing project: ${error.message}`, this.importConfig.context);
146
+ throw error;
147
+ }
148
+ }
149
+ /**
150
+ * Import project with name conflict handling
151
+ */
152
+ async importProject(exportedProject) {
153
+ var _a, _b, _c;
154
+ cli_utilities_1.log.debug('Starting project import...', this.importConfig.context);
155
+ // Map environment UID
156
+ const mappedEnvironmentUid = this.mapEnvironmentUid(exportedProject.settings.configuration.environment);
157
+ // Prepare project data for import
158
+ const projectData = {
159
+ name: exportedProject.name,
160
+ connectedStackApiKey: this.importConfig.apiKey,
161
+ contentTypeUid: exportedProject.contentTypeUid,
162
+ description: exportedProject.description || '',
163
+ canvasUrl: exportedProject.canvasUrl || '/',
164
+ settings: {
165
+ configuration: {
166
+ environment: mappedEnvironmentUid,
167
+ 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) || '',
168
+ },
169
+ },
170
+ };
171
+ cli_utilities_1.log.debug(`Project data prepared: ${JSON.stringify(projectData, null, 2)}`, this.importConfig.context);
172
+ // Try to create project with name conflict retry loop
173
+ let projectCreated = false;
174
+ let currentName = projectData.name;
175
+ let attemptCount = 0;
176
+ while (!projectCreated) {
177
+ attemptCount++;
178
+ cli_utilities_1.log.debug(`Attempt ${attemptCount} to create project with name: ${currentName}`, this.importConfig.context);
179
+ projectData.name = currentName;
180
+ const response = await this.apiClient.post('/projects', projectData);
181
+ if (response.status >= 200 && response.status < 300) {
182
+ projectCreated = true;
183
+ cli_utilities_1.log.debug(`Project created successfully with UID: ${(_c = response.data) === null || _c === void 0 ? void 0 : _c.uid}`, this.importConfig.context);
184
+ // Create mapper directory if it doesn't exist
185
+ await utils_1.fsUtil.makeDirectory(this.projectMapperPath);
186
+ // write the project to file
187
+ const projectFileSuccessPath = (0, node_path_1.join)(this.projectMapperPath, this.composableStudioConfig.fileName);
188
+ utils_1.fsUtil.writeFile(projectFileSuccessPath, response.data);
189
+ cli_utilities_1.log.debug(`Project written to: ${projectFileSuccessPath}`, this.importConfig.context);
190
+ }
191
+ else {
192
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
193
+ }
194
+ }
195
+ }
196
+ /**
197
+ * Map environment UID from source to target
198
+ */
199
+ mapEnvironmentUid(sourceEnvUid) {
200
+ if (!sourceEnvUid) {
201
+ cli_utilities_1.log.debug('Source environment UID is empty', this.importConfig.context);
202
+ return '';
203
+ }
204
+ cli_utilities_1.log.debug(`Mapping source environment UID: ${sourceEnvUid}`, this.importConfig.context);
205
+ if ((0, isEmpty_1.default)(this.envUidMapper)) {
206
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
207
+ return '';
208
+ }
209
+ const mappedUid = this.envUidMapper[sourceEnvUid];
210
+ if (!mappedUid) {
211
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
212
+ return '';
213
+ }
214
+ cli_utilities_1.log.debug(`Mapped environment UID: ${sourceEnvUid} → ${mappedUid}`, this.importConfig.context);
215
+ return mappedUid;
216
+ }
217
+ /**
218
+ * Prompt user for a new project name when conflict occurs
219
+ */
220
+ async promptForNewProjectName(currentName) {
221
+ const suggestedName = `Copy of ${currentName}`;
222
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NAME_CONFLICT', currentName), this.importConfig.context);
223
+ cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SUGGEST_NAME', suggestedName), this.importConfig.context);
224
+ const response = await cli_utilities_1.cliux.inquire({
225
+ type: 'input',
226
+ name: 'projectName',
227
+ message: 'Enter new project name:',
228
+ default: suggestedName,
229
+ });
230
+ const newName = response.projectName || suggestedName;
231
+ cli_utilities_1.log.debug(`User provided new project name: ${newName}`, this.importConfig.context);
232
+ return newName;
233
+ }
234
+ }
235
+ exports.default = ImportComposableStudio;
@@ -25,6 +25,8 @@ export default class ContentTypesImport extends BaseClass {
25
25
  private extPendingPath;
26
26
  private isExtensionsUpdate;
27
27
  private pendingExts;
28
+ private composableStudioSuccessPath;
29
+ private composableStudioExportPath;
28
30
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
29
31
  start(): Promise<any>;
30
32
  seedCTs(): Promise<any>;
@@ -1,9 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
+ /* eslint-disable no-prototype-builtins */
5
+ /*!
6
+ * Contentstack Import
7
+ * Copyright (c) 2026 Contentstack LLC
8
+ * MIT Licensed
9
+ */
4
10
  const path = tslib_1.__importStar(require("path"));
5
11
  const lodash_1 = require("lodash");
6
12
  const cli_utilities_1 = require("@contentstack/cli-utilities");
13
+ const constants_1 = require("../../constants");
7
14
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
8
15
  const content_type_helper_1 = require("../../utils/content-type-helper");
9
16
  const utils_1 = require("../../utils");
@@ -16,19 +23,28 @@ class ContentTypesImport extends base_class_1.default {
16
23
  this.cTsConfig = importConfig.modules['content-types'];
17
24
  this.gFsConfig = importConfig.modules['global-fields'];
18
25
  this.reqConcurrency = this.cTsConfig.writeConcurrency || this.importConfig.writeConcurrency;
19
- this.cTsFolderPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.data), (0, cli_utilities_1.sanitizePath)(this.cTsConfig.dirName));
20
- this.cTsMapperPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.data), 'mapper', 'content_types');
21
- this.cTsSuccessPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.data), 'mapper', 'content_types', 'success.json');
22
- this.gFsFolderPath = path.resolve((0, cli_utilities_1.sanitizePath)(this.importConfig.data), (0, cli_utilities_1.sanitizePath)(this.gFsConfig.dirName));
23
- this.gFsMapperFolderPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.data), 'mapper', 'global_fields', 'success.json');
24
- this.gFsPendingPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.data), 'mapper', 'global_fields', 'pending_global_fields.js');
25
- this.marketplaceAppMapperPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.data), 'mapper', 'marketplace_apps', 'uid-mapping.json');
26
+ this.cTsFolderPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.contentDir), (0, cli_utilities_1.sanitizePath)(this.cTsConfig.dirName));
27
+ this.cTsMapperPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.CONTENT_TYPES);
28
+ this.cTsSuccessPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.CONTENT_TYPES, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
29
+ this.gFsFolderPath = path.resolve((0, cli_utilities_1.sanitizePath)(this.importConfig.backupDir), (0, cli_utilities_1.sanitizePath)(this.gFsConfig.dirName));
30
+ this.gFsMapperFolderPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.GLOBAL_FIELDS, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
31
+ this.gFsPendingPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.GLOBAL_FIELDS, constants_1.PATH_CONSTANTS.FILES.PENDING_GLOBAL_FIELDS);
32
+ this.marketplaceAppMapperPath = path.join((0, cli_utilities_1.sanitizePath)(this.importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.MARKETPLACE_APPS, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
26
33
  this.ignoredFilesInContentTypesFolder = new Map([
27
34
  ['__master.json', 'true'],
28
35
  ['__priority.json', 'true'],
29
- ['schema.json', 'true'],
36
+ [constants_1.PATH_CONSTANTS.FILES.SCHEMA, 'true'],
30
37
  ['.DS_Store', 'true'],
31
38
  ]);
39
+ // Initialize composable studio paths if config exists
40
+ if (this.importConfig.modules['composable-studio']) {
41
+ this.composableStudioSuccessPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.backupDir), constants_1.PATH_CONSTANTS.MAPPER, this.importConfig.modules['composable-studio'].dirName, this.importConfig.modules['composable-studio'].fileName);
42
+ this.composableStudioExportPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.backupDir), this.importConfig.modules['composable-studio'].dirName, this.importConfig.modules['composable-studio'].fileName);
43
+ }
44
+ else {
45
+ this.composableStudioSuccessPath = '';
46
+ this.composableStudioExportPath = '';
47
+ }
32
48
  this.cTs = [];
33
49
  this.createdCTs = [];
34
50
  this.titleToUIdMap = new Map();
@@ -37,8 +53,8 @@ class ContentTypesImport extends base_class_1.default {
37
53
  this.createdGFs = [];
38
54
  this.pendingGFs = [];
39
55
  this.pendingExts = [];
40
- this.taxonomiesPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.data), 'mapper', 'taxonomies', 'success.json');
41
- this.extPendingPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.data), 'mapper', 'extensions', 'pending_extensions.js');
56
+ this.taxonomiesPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.contentDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.TAXONOMIES, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
57
+ this.extPendingPath = path.join((0, cli_utilities_1.sanitizePath)(importConfig.contentDir), constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.EXTENSIONS, constants_1.PATH_CONSTANTS.FILES.PENDING_EXTENSIONS);
42
58
  }
43
59
  async start() {
44
60
  var _a;
@@ -49,6 +65,30 @@ class ContentTypesImport extends base_class_1.default {
49
65
  cli_utilities_1.log.info('No content type found to import', this.importConfig.context);
50
66
  return;
51
67
  }
68
+ // If success file doesn't exist but export file does, skip the composition content type
69
+ // Only check if composable studio paths are configured
70
+ if (this.composableStudioSuccessPath &&
71
+ this.composableStudioExportPath &&
72
+ !utils_1.fileHelper.fileExistsSync(this.composableStudioSuccessPath) &&
73
+ utils_1.fileHelper.fileExistsSync(this.composableStudioExportPath)) {
74
+ const exportedProject = utils_1.fileHelper.readFileSync(this.composableStudioExportPath);
75
+ if (exportedProject === null || exportedProject === void 0 ? void 0 : exportedProject.contentTypeUid) {
76
+ const originalCount = this.cTs.length;
77
+ this.cTs = this.cTs.filter((ct) => {
78
+ const shouldSkip = ct.uid === exportedProject.contentTypeUid;
79
+ if (shouldSkip) {
80
+ cli_utilities_1.log.info(`Skipping content type '${ct.uid}' as Composable Studio project was not created successfully`, this.importConfig.context);
81
+ }
82
+ return !shouldSkip;
83
+ });
84
+ const skippedCount = originalCount - this.cTs.length;
85
+ if (skippedCount > 0) {
86
+ cli_utilities_1.log.debug(`Filtered out ${skippedCount} composition content type(s) from import`, this.importConfig.context);
87
+ }
88
+ }
89
+ }
90
+ await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
91
+ cli_utilities_1.log.debug('Created content types mapper directory.', this.importConfig.context);
52
92
  await utils_1.fsUtil.makeDirectory(this.cTsMapperPath);
53
93
  cli_utilities_1.log.debug('Created content types mapper directory', this.importConfig.context);
54
94
  const progress = this.initializeProgress();
@@ -66,8 +106,7 @@ class ContentTypesImport extends base_class_1.default {
66
106
  if (this.pendingGFs.length > 0) {
67
107
  await this.handlePendingGlobalFields(progress);
68
108
  }
69
- this.completeProgress(true);
70
- cli_utilities_1.log.success('Content types have been imported successfully!', this.importConfig.context);
109
+ this.completeProgressWithMessage();
71
110
  }
72
111
  catch (error) {
73
112
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Content types import failed');
@@ -282,7 +321,7 @@ class ContentTypesImport extends base_class_1.default {
282
321
  async analyzeImportData() {
283
322
  var _a, _b, _c, _d, _e;
284
323
  const [cts, gfs, pendingGfs, pendingExt] = await this.withLoadingSpinner('CONTENT TYPES: Analyzing import data...', async () => {
285
- const cts = utils_1.fsUtil.readFile(path.join(this.cTsFolderPath, 'schema.json'));
324
+ const cts = (0, cli_utilities_1.readContentTypeSchemas)(this.cTsFolderPath);
286
325
  const gfs = utils_1.fsUtil.readFile(path.resolve(this.gFsFolderPath, this.gFsConfig.fileName));
287
326
  const pendingGfs = utils_1.fsUtil.readFile(this.gFsPendingPath);
288
327
  const pendingExt = utils_1.fsUtil.readFile(this.extPendingPath);
@@ -6,6 +6,7 @@ const values_1 = tslib_1.__importDefault(require("lodash/values"));
6
6
  const node_path_1 = require("node:path");
7
7
  const lodash_1 = require("lodash");
8
8
  const cli_utilities_1 = require("@contentstack/cli-utilities");
9
+ const constants_1 = require("../../constants");
9
10
  const utils_1 = require("../../utils");
10
11
  const base_class_1 = tslib_1.__importDefault(require("./base-class"));
11
12
  class ImportCustomRoles extends base_class_1.default {
@@ -49,13 +50,13 @@ class ImportCustomRoles extends base_class_1.default {
49
50
  this.importConfig.context.module = utils_1.MODULE_CONTEXTS.CUSTOM_ROLES;
50
51
  this.currentModuleName = utils_1.MODULE_NAMES[utils_1.MODULE_CONTEXTS.CUSTOM_ROLES];
51
52
  this.customRolesConfig = importConfig.modules.customRoles;
52
- this.customRolesMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'custom-roles');
53
+ this.customRolesMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.CUSTOM_ROLES);
53
54
  this.customRolesFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, this.customRolesConfig.dirName);
54
- this.customRolesUidMapperPath = (0, node_path_1.join)(this.customRolesMapperPath, 'uid-mapping.json');
55
- this.envUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'environments');
56
- this.entriesUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'entries');
57
- this.createdCustomRolesPath = (0, node_path_1.join)(this.customRolesMapperPath, 'success.json');
58
- this.customRolesFailsPath = (0, node_path_1.join)(this.customRolesMapperPath, 'fails.json');
55
+ this.customRolesUidMapperPath = (0, node_path_1.join)(this.customRolesMapperPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING);
56
+ this.envUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.ENVIRONMENTS);
57
+ this.entriesUidMapperFolderPath = (0, node_path_1.join)(this.importConfig.backupDir, constants_1.PATH_CONSTANTS.MAPPER, constants_1.PATH_CONSTANTS.MAPPER_MODULES.ENTRIES);
58
+ this.createdCustomRolesPath = (0, node_path_1.join)(this.customRolesMapperPath, constants_1.PATH_CONSTANTS.FILES.SUCCESS);
59
+ this.customRolesFailsPath = (0, node_path_1.join)(this.customRolesMapperPath, constants_1.PATH_CONSTANTS.FILES.FAILS);
59
60
  this.customRoles = {};
60
61
  this.failedCustomRoles = [];
61
62
  this.createdCustomRoles = [];
@@ -84,8 +85,7 @@ class ImportCustomRoles extends base_class_1.default {
84
85
  progress.updateStatus(utils_1.PROCESS_STATUS[utils_1.PROCESS_NAMES.CUSTOM_ROLES_IMPORT].IMPORTING);
85
86
  await this.importCustomRoles();
86
87
  this.handleImportResults();
87
- this.completeProgress(true);
88
- cli_utilities_1.log.success('Custom roles have been imported successfully!', this.importConfig.context);
88
+ this.completeProgressWithMessage();
89
89
  }
90
90
  catch (error) {
91
91
  this.completeProgress(false, (error === null || error === void 0 ? void 0 : error.message) || 'Custom roles import failed');
@@ -233,8 +233,8 @@ class ImportCustomRoles extends base_class_1.default {
233
233
  cli_utilities_1.log.debug('Creating custom roles mapper directory', this.importConfig.context);
234
234
  await utils_1.fsUtil.makeDirectory(this.customRolesMapperPath);
235
235
  this.customRolesUidMapper = this.loadJsonFileIfExists(this.customRolesUidMapperPath, 'custom roles');
236
- this.environmentsUidMap = this.loadJsonFileIfExists((0, node_path_1.join)(this.envUidMapperFolderPath, 'uid-mapping.json'), 'environments');
237
- this.entriesUidMap = this.loadJsonFileIfExists((0, node_path_1.join)(this.entriesUidMapperFolderPath, 'uid-mapping.json'), 'entries');
236
+ this.environmentsUidMap = this.loadJsonFileIfExists((0, node_path_1.join)(this.envUidMapperFolderPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING), 'environments');
237
+ this.entriesUidMap = this.loadJsonFileIfExists((0, node_path_1.join)(this.entriesUidMapperFolderPath, constants_1.PATH_CONSTANTS.FILES.UID_MAPPING), 'entries');
238
238
  }
239
239
  loadJsonFileIfExists(path, label) {
240
240
  if (utils_1.fileHelper.fileExistsSync(path)) {
@@ -38,6 +38,8 @@ export default class EntriesImport extends BaseClass {
38
38
  locale: string;
39
39
  entry_uid: string;
40
40
  }>;
41
+ private composableStudioSuccessPath;
42
+ private composableStudioExportPath;
41
43
  constructor({ importConfig, stackAPIClient }: ModuleClassParams);
42
44
  start(): Promise<any>;
43
45
  private analyzeEntryData;