@contentstack/cli-cm-import 2.0.0-beta.2 → 2.0.0-beta.4

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 (42) 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 +9 -42
  5. package/lib/config/index.js +7 -0
  6. package/lib/import/module-importer.js +0 -4
  7. package/lib/import/modules/composable-studio.d.ts +44 -0
  8. package/lib/import/modules/composable-studio.js +234 -0
  9. package/lib/import/modules/content-types.d.ts +2 -0
  10. package/lib/import/modules/content-types.js +48 -9
  11. package/lib/import/modules/entries.d.ts +2 -0
  12. package/lib/import/modules/entries.js +19 -10
  13. package/lib/import/modules/global-fields.d.ts +1 -1
  14. package/lib/import/modules/global-fields.js +8 -8
  15. package/lib/import/modules/locales.d.ts +1 -1
  16. package/lib/import/modules/locales.js +6 -6
  17. package/lib/import/modules/marketplace-apps.js +2 -2
  18. package/lib/import/modules/personalize.js +1 -1
  19. package/lib/import/modules/stack.js +1 -1
  20. package/lib/import/modules/variant-entries.js +2 -2
  21. package/lib/import/modules/workflows.js +1 -1
  22. package/lib/types/default-config.d.ts +6 -0
  23. package/lib/types/import-config.d.ts +0 -1
  24. package/lib/types/index.d.ts +37 -11
  25. package/lib/utils/asset-helper.js +1 -1
  26. package/lib/utils/common-helper.d.ts +1 -1
  27. package/lib/utils/common-helper.js +6 -6
  28. package/lib/utils/content-type-helper.d.ts +1 -1
  29. package/lib/utils/content-type-helper.js +3 -3
  30. package/lib/utils/extension-helper.js +1 -1
  31. package/lib/utils/file-helper.js +1 -1
  32. package/lib/utils/import-config-handler.js +7 -11
  33. package/lib/utils/import-path-resolver.js +2 -8
  34. package/lib/utils/logger.d.ts +1 -1
  35. package/lib/utils/logger.js +2 -2
  36. package/lib/utils/login-handler.d.ts +1 -1
  37. package/lib/utils/login-handler.js +4 -4
  38. package/lib/utils/marketplace-app-helper.js +9 -6
  39. package/lib/utils/taxonomies-helper.js +1 -1
  40. package/messages/index.json +10 -1
  41. package/oclif.manifest.json +4 -48
  42. package/package.json +9 -13
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Contentstack
3
+ Copyright (c) 2026 Contentstack
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -47,7 +47,7 @@ $ npm install -g @contentstack/cli-cm-import
47
47
  $ csdx COMMAND
48
48
  running command...
49
49
  $ csdx (--version)
50
- @contentstack/cli-cm-import/2.0.0-beta.2 linux-x64 node-v22.21.1
50
+ @contentstack/cli-cm-import/2.0.0-beta.4 linux-x64 node-v22.22.0
51
51
  $ csdx --help [COMMAND]
52
52
  USAGE
53
53
  $ csdx COMMAND
@@ -58,127 +58,81 @@ USAGE
58
58
  # Commands
59
59
 
60
60
  <!-- commands -->
61
- * [`csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`](#csdx-cmstacksimport--c-value--k-value--d-value--a-value---module-value---backup-dir-value---branch-value---import-webhook-status-disablecurrent)
62
- * [`csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`](#csdx-cmstacksimport--c-value--k-value--d-value--a-value---module-value---backup-dir-value---branch-value---import-webhook-status-disablecurrent)
61
+ * [`csdx cm:stacks:import [--config <value>] [--stack-api-key <value>] [--data-dir <value>] [--alias <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`](#csdx-cmstacksimport---config-value---stack-api-key-value---data-dir-value---alias-value---module-value---backup-dir-value---branch-value---import-webhook-status-disablecurrent)
63
62
 
64
- ## `csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`
63
+ ## `csdx cm:stacks:import [--config <value>] [--stack-api-key <value>] [--data-dir <value>] [--alias <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`
65
64
 
66
65
  Import content from a stack
67
66
 
68
67
  ```
69
68
  USAGE
70
- $ csdx cm:import cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>]
71
- [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]
69
+ $ csdx cm:stacks:import [--config <value>] [--stack-api-key <value>] [--data-dir <value>] [--alias <value>]
70
+ [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]
72
71
 
73
72
  FLAGS
74
- -B, --branch=<value> The name of the branch where you want to import your content. If you don't
75
- mention the branch name, then by default the content will be imported to the
76
- main branch.
77
- -a, --alias=<value> The management token of the destination stack where you will import the
78
- content.
79
- -b, --backup-dir=<value> [optional] Backup directory name when using specific module.
80
- -c, --config=<value> [optional] The path of the configuration JSON file containing all the options
81
- for a single run.
82
- -d, --data-dir=<value> The path or the location in your file system where the content, you intend to
83
- import, is stored. For example, -d "C:\Users\Name\Desktop\cli\content". If the
84
- export folder has branches involved, then the path should point till the
85
- particular branch. For example, “-d
86
- "C:\Users\Name\Desktop\cli\content\branch_name"
87
- -k, --stack-api-key=<value> API Key of the target stack
88
- -m, --module=<value> [optional] Specify the module to import into the target stack. If not
89
- specified, the import command will import all the modules into the stack. The
90
- available modules are assets, content-types, entries, environments,
91
- extensions, marketplace-apps, global-fields, labels, locales, webhooks,
92
- workflows, custom-roles, personalize projects, and taxonomies.
93
- -y, --yes [optional] Force override all Marketplace prompts.
94
- --branch-alias=<value> Specify the branch alias where you want to import your content. If not
95
- specified, the content is imported into the main branch by default.
96
- --exclude-global-modules Excludes the branch-independent module from the import operation.
97
- --import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
98
- same state of webhooks as the source stack. <options: disable|current>
99
- <options: disable|current>
100
- --personalize-project-name=<value> (optional) Provide a unique name for the Personalize project.
101
- --replace-existing Replaces the existing module in the target stack.
102
- --skip-app-recreation (optional) Skips the recreation of private apps if they already exist.
103
- --skip-assets-publish Skips asset publishing during the import process.
104
- --skip-audit Skips the audit fix that occurs during an import operation.
105
- --skip-entries-publish Skips entry publishing during the import process
106
- --skip-existing Skips the module exists warning messages.
73
+ -a, --alias=<value>
74
+ The management token of the destination stack where you will import the content.
107
75
 
108
- DESCRIPTION
109
- Import content from a stack
76
+ -c, --config=<value>
77
+ [optional] The path of the configuration JSON file containing all the options for a single run.
110
78
 
111
- ALIASES
112
- $ csdx cm:import
79
+ -d, --data-dir=<value>
80
+ The path or the location in your file system where the content, you intend to import, is stored. For example, -d
81
+ "C:\Users\Name\Desktop\cli\content". If the export folder has branches involved, then the path should point till the
82
+ particular branch. For example, “-d "C:\Users\Name\Desktop\cli\content\branch_name"
113
83
 
114
- EXAMPLES
115
- $ csdx cm:stacks:import --stack-api-key <stack_api_key> --data-dir <path/of/export/destination/dir>
84
+ -k, --stack-api-key=<value>
85
+ API Key of the target stack
116
86
 
117
- $ csdx cm:stacks:import --config <path/of/config/dir>
87
+ -y, --yes
88
+ [optional] Force override all Marketplace prompts.
118
89
 
119
- $ csdx cm:stacks:import --module <single module name>
90
+ --backup-dir=<value>
91
+ [optional] Backup directory name when using specific module.
120
92
 
121
- $ csdx cm:stacks:import --module <single module name> --backup-dir <backup dir>
93
+ --branch=<value>
94
+ The name of the branch where you want to import your content. If you don't mention the branch name, then by default
95
+ the content will be imported to the main branch.
122
96
 
123
- $ csdx cm:stacks:import --alias <management_token_alias>
97
+ --branch-alias=<value>
98
+ Specify the branch alias where you want to import your content. If not specified, the content is imported into the
99
+ main branch by default.
124
100
 
125
- $ csdx cm:stacks:import --alias <management_token_alias> --data-dir <path/of/export/destination/dir>
101
+ --exclude-global-modules
102
+ Excludes the branch-independent module from the import operation.
126
103
 
127
- $ csdx cm:stacks:import --alias <management_token_alias> --config <path/of/config/file>
104
+ --import-webhook-status=<option>
105
+ [default: disable] [default: disable] (optional) This webhook state keeps the same state of webhooks as the source
106
+ stack. <options: disable|current>
107
+ <options: disable|current>
128
108
 
129
- $ csdx cm:stacks:import --branch <branch name> --yes --skip-audit
130
- ```
109
+ --module=<value>
110
+ [optional] Specify the module to import into the target stack. If not specified, the import command will import all
111
+ the modules into the stack. The available modules are assets, content-types, entries, environments, extensions,
112
+ marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects,
113
+ taxonomies, and composable-studio.
131
114
 
132
- ## `csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]`
115
+ --personalize-project-name=<value>
116
+ (optional) Provide a unique name for the Personalize project.
133
117
 
134
- Import content from a stack
118
+ --replace-existing
119
+ Replaces the existing module in the target stack.
135
120
 
136
- ```
137
- USAGE
138
- $ csdx cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir
139
- <value>] [--branch <value>] [--import-webhook-status disable|current]
121
+ --skip-assets-publish
122
+ Skips asset publishing during the import process.
140
123
 
141
- FLAGS
142
- -B, --branch=<value> The name of the branch where you want to import your content. If you don't
143
- mention the branch name, then by default the content will be imported to the
144
- main branch.
145
- -a, --alias=<value> The management token of the destination stack where you will import the
146
- content.
147
- -b, --backup-dir=<value> [optional] Backup directory name when using specific module.
148
- -c, --config=<value> [optional] The path of the configuration JSON file containing all the options
149
- for a single run.
150
- -d, --data-dir=<value> The path or the location in your file system where the content, you intend to
151
- import, is stored. For example, -d "C:\Users\Name\Desktop\cli\content". If the
152
- export folder has branches involved, then the path should point till the
153
- particular branch. For example, “-d
154
- "C:\Users\Name\Desktop\cli\content\branch_name"
155
- -k, --stack-api-key=<value> API Key of the target stack
156
- -m, --module=<value> [optional] Specify the module to import into the target stack. If not
157
- specified, the import command will import all the modules into the stack. The
158
- available modules are assets, content-types, entries, environments,
159
- extensions, marketplace-apps, global-fields, labels, locales, webhooks,
160
- workflows, custom-roles, personalize projects, and taxonomies.
161
- -y, --yes [optional] Force override all Marketplace prompts.
162
- --branch-alias=<value> Specify the branch alias where you want to import your content. If not
163
- specified, the content is imported into the main branch by default.
164
- --exclude-global-modules Excludes the branch-independent module from the import operation.
165
- --import-webhook-status=<option> [default: disable] [default: disable] (optional) This webhook state keeps the
166
- same state of webhooks as the source stack. <options: disable|current>
167
- <options: disable|current>
168
- --personalize-project-name=<value> (optional) Provide a unique name for the Personalize project.
169
- --replace-existing Replaces the existing module in the target stack.
170
- --skip-app-recreation (optional) Skips the recreation of private apps if they already exist.
171
- --skip-assets-publish Skips asset publishing during the import process.
172
- --skip-audit Skips the audit fix that occurs during an import operation.
173
- --skip-entries-publish Skips entry publishing during the import process
174
- --skip-existing Skips the module exists warning messages.
124
+ --skip-audit
125
+ Skips the audit fix that occurs during an import operation.
126
+
127
+ --skip-entries-publish
128
+ Skips entry publishing during the import process
129
+
130
+ --skip-existing
131
+ Skips the module exists warning messages.
175
132
 
176
133
  DESCRIPTION
177
134
  Import content from a stack
178
135
 
179
- ALIASES
180
- $ csdx cm:import
181
-
182
136
  EXAMPLES
183
137
  $ csdx cm:stacks:import --stack-api-key <stack_api_key> --data-dir <path/of/export/destination/dir>
184
138
 
@@ -4,7 +4,6 @@ export default class ImportCommand extends Command {
4
4
  static description: string;
5
5
  static examples: string[];
6
6
  static flags: FlagInput;
7
- static aliases: string[];
8
7
  static usage: string;
9
8
  run(): Promise<void>;
10
9
  private logAndPrintErrorDetails;
@@ -6,6 +6,7 @@ const import_1 = require("../../../import");
6
6
  const utils_1 = require("../../../utils");
7
7
  class ImportCommand extends cli_command_1.Command {
8
8
  async run() {
9
+ var _a, _b;
9
10
  // setup import config
10
11
  // initialize the importer
11
12
  // start import
@@ -15,6 +16,7 @@ class ImportCommand extends cli_command_1.Command {
15
16
  const { flags } = await this.parse(ImportCommand);
16
17
  importConfig = await (0, utils_1.setupImportConfig)(flags);
17
18
  // Prepare the context object
19
+ (0, cli_utilities_1.createLogContext)(((_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.info) === null || _b === void 0 ? void 0 : _b.command) || 'cm:stacks:export', importConfig.apiKey, importConfig.authenticationMethod);
18
20
  const context = this.createImportContext(importConfig.apiKey, importConfig.authenticationMethod);
19
21
  importConfig.context = Object.assign({}, context);
20
22
  //log.info(`Using Cli Version: ${this.context?.cliVersion}`, importConfig.context);
@@ -25,6 +27,8 @@ class ImportCommand extends cli_command_1.Command {
25
27
  importConfig.developerHubBaseUrl = this.developerHubUrl;
26
28
  if (this.personalizeUrl)
27
29
  importConfig.modules.personalize.baseURL[importConfig.region.name] = this.personalizeUrl;
30
+ if (this.composableStudioUrl)
31
+ importConfig.modules['composable-studio'].apiBaseUrl = this.composableStudioUrl;
28
32
  const managementAPIClient = await (0, cli_utilities_1.managementSDKClient)(importConfig);
29
33
  if (flags.branch) {
30
34
  cli_utilities_1.CLIProgressManager.initializeGlobalSummary(`IMPORT-${flags.branch}`, flags.branch, `Importing content into "${flags.branch}" branch...`);
@@ -35,12 +39,7 @@ class ImportCommand extends cli_command_1.Command {
35
39
  const moduleImporter = new import_1.ModuleImporter(managementAPIClient, importConfig);
36
40
  const result = await moduleImporter.start();
37
41
  backupDir = importConfig.backupDir;
38
- if (!(result === null || result === void 0 ? void 0 : result.noSuccessMsg)) {
39
- const successMessage = importConfig.stackName
40
- ? `Successfully imported the content to the stack named ${importConfig.stackName} with the API key ${importConfig.apiKey} .`
41
- : `The content has been imported to the stack ${importConfig.apiKey} successfully!`;
42
- cli_utilities_1.log.success(successMessage, importConfig.context);
43
- }
42
+ //Note: Final summary is now handled by summary manager
44
43
  cli_utilities_1.CLIProgressManager.printGlobalSummary();
45
44
  this.logSuccessAndBackupMessages(backupDir, importConfig);
46
45
  // Clear progress module setting now that import is complete
@@ -92,6 +91,7 @@ class ImportCommand extends cli_command_1.Command {
92
91
  command: ((_b = (_a = this.context) === null || _a === void 0 ? void 0 : _a.info) === null || _b === void 0 ? void 0 : _b.command) || 'cm:stacks:import',
93
92
  module: '',
94
93
  userId: cli_utilities_1.configHandler.get('userUid') || '',
94
+ email: cli_utilities_1.configHandler.get('email') || '',
95
95
  sessionId: (_c = this.context) === null || _c === void 0 ? void 0 : _c.sessionId,
96
96
  apiKey: apiKey || '',
97
97
  orgId: cli_utilities_1.configHandler.get('oauthOrgUid') || '',
@@ -116,21 +116,10 @@ ImportCommand.flags = {
116
116
  char: 'c',
117
117
  description: '[optional] The path of the configuration JSON file containing all the options for a single run.',
118
118
  }),
119
- 'stack-uid': cli_utilities_1.flags.string({
120
- char: 's',
121
- description: 'API key of the target stack.',
122
- hidden: true,
123
- parse: (0, cli_utilities_1.printFlagDeprecation)(['-s', '--stack-uid'], ['-k', '--stack-api-key']),
124
- }),
125
119
  'stack-api-key': cli_utilities_1.flags.string({
126
120
  char: 'k',
127
121
  description: 'API Key of the target stack',
128
122
  }),
129
- data: cli_utilities_1.flags.string({
130
- description: 'path and location where data is stored',
131
- hidden: true,
132
- parse: (0, cli_utilities_1.printFlagDeprecation)(['--data'], ['--data-dir']),
133
- }),
134
123
  'data-dir': cli_utilities_1.flags.string({
135
124
  char: 'd',
136
125
  description: `The path or the location in your file system where the content, you intend to import, is stored. For example, -d "C:\\Users\\Name\\Desktop\\cli\\content". If the export folder has branches involved, then the path should point till the particular branch. For example, “-d "C:\\Users\\Name\\Desktop\\cli\\content\\branch_name"`,
@@ -139,36 +128,19 @@ ImportCommand.flags = {
139
128
  char: 'a',
140
129
  description: 'The management token of the destination stack where you will import the content.',
141
130
  }),
142
- 'management-token-alias': cli_utilities_1.flags.string({
143
- description: 'alias of the management token',
144
- hidden: true,
145
- parse: (0, cli_utilities_1.printFlagDeprecation)(['--management-token-alias'], ['-a', '--alias']),
146
- }),
147
- 'auth-token': cli_utilities_1.flags.boolean({
148
- char: 'A',
149
- description: 'to use auth token',
150
- hidden: true,
151
- parse: (0, cli_utilities_1.printFlagDeprecation)(['-A', '--auth-token']),
152
- }),
153
131
  module: cli_utilities_1.flags.string({
154
132
  required: false,
155
- char: 'm',
156
- description: '[optional] Specify the module to import into the target stack. If not specified, the import command will import all the modules into the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects, and taxonomies.',
157
- parse: (0, cli_utilities_1.printFlagDeprecation)(['-m'], ['--module']),
133
+ description: '[optional] Specify the module to import into the target stack. If not specified, the import command will import all the modules into the stack. The available modules are assets, content-types, entries, environments, extensions, marketplace-apps, global-fields, labels, locales, webhooks, workflows, custom-roles, personalize projects, taxonomies, and composable-studio.',
158
134
  }),
159
135
  'backup-dir': cli_utilities_1.flags.string({
160
- char: 'b',
161
136
  description: '[optional] Backup directory name when using specific module.',
162
- parse: (0, cli_utilities_1.printFlagDeprecation)(['-b'], ['--backup-dir']),
163
137
  }),
164
138
  branch: cli_utilities_1.flags.string({
165
- char: 'B',
166
139
  description: "The name of the branch where you want to import your content. If you don't mention the branch name, then by default the content will be imported to the main branch.",
167
- parse: (0, cli_utilities_1.printFlagDeprecation)(['-B'], ['--branch']),
168
140
  exclusive: ['branch-alias'],
169
141
  }),
170
142
  'branch-alias': cli_utilities_1.flags.string({
171
- description: "Specify the branch alias where you want to import your content. If not specified, the content is imported into the main branch by default.",
143
+ description: 'Specify the branch alias where you want to import your content. If not specified, the content is imported into the main branch by default.',
172
144
  exclusive: ['branch'],
173
145
  }),
174
146
  'import-webhook-status': cli_utilities_1.flags.string({
@@ -182,10 +154,6 @@ ImportCommand.flags = {
182
154
  required: false,
183
155
  description: '[optional] Force override all Marketplace prompts.',
184
156
  }),
185
- 'skip-app-recreation': cli_utilities_1.flags.boolean({
186
- description: '(optional) Skips the recreation of private apps if they already exist.',
187
- parse: (0, cli_utilities_1.printFlagDeprecation)(['--skip-app-recreation']),
188
- }),
189
157
  'replace-existing': cli_utilities_1.flags.boolean({
190
158
  required: false,
191
159
  description: 'Replaces the existing module in the target stack.',
@@ -215,5 +183,4 @@ ImportCommand.flags = {
215
183
  default: false,
216
184
  }),
217
185
  };
218
- ImportCommand.aliases = ['cm:import'];
219
- ImportCommand.usage = 'cm:stacks:import [-c <value>] [-k <value>] [-d <value>] [-a <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]';
186
+ ImportCommand.usage = 'cm:stacks:import [--config <value>] [--stack-api-key <value>] [--data-dir <value>] [--alias <value>] [--module <value>] [--backup-dir <value>] [--branch <value>] [--import-webhook-status disable|current]';
@@ -33,6 +33,7 @@ const config = {
33
33
  'stack',
34
34
  'assets',
35
35
  'taxonomies',
36
+ 'composable-studio',
36
37
  'extensions',
37
38
  'marketplace-apps',
38
39
  'global-fields',
@@ -199,6 +200,12 @@ const config = {
199
200
  locale: 'en-us',
200
201
  },
201
202
  },
203
+ 'composable-studio': {
204
+ dirName: 'composable_studio',
205
+ fileName: 'composable_studio.json',
206
+ apiBaseUrl: 'https://composable-studio-api.contentstack.com',
207
+ apiVersion: 'v1',
208
+ },
202
209
  },
203
210
  languagesCode: [
204
211
  'af-za',
@@ -37,8 +37,6 @@ class ModuleImporter {
37
37
  const backupDir = await (0, utils_1.backupHandler)(this.importConfig);
38
38
  if (backupDir) {
39
39
  this.importConfig.backupDir = backupDir;
40
- // To support the old config
41
- this.importConfig.data = backupDir;
42
40
  }
43
41
  // NOTE audit and fix the import content.
44
42
  if (!this.importConfig.skipAudit &&
@@ -66,8 +64,6 @@ class ModuleImporter {
66
64
  }
67
65
  async importByModuleByName(moduleName) {
68
66
  cli_utilities_1.log.info(`Starting import of ${moduleName} module`, this.importConfig.context);
69
- // import the modules by name
70
- // calls the module runner which inturn calls the module itself
71
67
  return (0, modules_1.default)({
72
68
  stackAPIClient: this.stackAPIClient,
73
69
  importConfig: this.importConfig,
@@ -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,234 @@
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.projectMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', this.composableStudioConfig.dirName);
16
+ this.composableStudioFilePath = (0, node_path_1.join)(this.composableStudioPath, this.composableStudioConfig.fileName);
17
+ this.envUidMapperPath = (0, node_path_1.join)(this.importConfig.backupDir, 'mapper', 'environments', 'uid-mapping.json');
18
+ this.envUidMapper = {};
19
+ // Initialize HttpClient with Studio API base URL
20
+ this.apiClient = new cli_utilities_1.HttpClient();
21
+ this.apiClient.baseUrl(`${this.composableStudioConfig.apiBaseUrl}/${this.composableStudioConfig.apiVersion}`);
22
+ }
23
+ /**
24
+ * Entry point for Studio import
25
+ */
26
+ async start() {
27
+ if (this.importConfig.management_token) {
28
+ cli_utilities_1.log.warn('Skipping Studio project import when using management token', this.importConfig.context);
29
+ return;
30
+ }
31
+ cli_utilities_1.log.debug('Starting Studio project import process...', this.importConfig.context);
32
+ try {
33
+ // Initialize authentication
34
+ const authInitialized = await this.addAuthHeaders();
35
+ if (!authInitialized) {
36
+ cli_utilities_1.log.warn('Skipping Studio project import when using OAuth authentication', this.importConfig.context);
37
+ return;
38
+ }
39
+ // Load environment UID mapper
40
+ await this.loadEnvironmentMapper();
41
+ // Read exported project data
42
+ const exportedProject = await this.readExportedProject();
43
+ if (!exportedProject) {
44
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NOT_FOUND'), this.importConfig.context);
45
+ return;
46
+ }
47
+ cli_utilities_1.log.debug(`Exported project found: ${exportedProject.name}`, this.importConfig.context);
48
+ // Check if target stack already has a connected project
49
+ const existingProject = await this.getExistingProject();
50
+ if (existingProject) {
51
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SKIP_EXISTING'), this.importConfig.context);
52
+ return;
53
+ }
54
+ // Import the project with name conflict handling
55
+ await this.importProject(exportedProject);
56
+ cli_utilities_1.log.success(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_IMPORT_COMPLETE', exportedProject.name), this.importConfig.context);
57
+ }
58
+ catch (error) {
59
+ (0, cli_utilities_1.handleAndLogError)(error, Object.assign({}, this.importConfig.context));
60
+ }
61
+ }
62
+ /**
63
+ * Initialize authentication headers for API calls
64
+ */
65
+ async addAuthHeaders() {
66
+ cli_utilities_1.log.debug('Initializing Studio API authentication...', this.importConfig.context);
67
+ // Get authentication details - following personalization-api-adapter pattern
68
+ await cli_utilities_1.authenticationHandler.getAuthDetails();
69
+ const token = cli_utilities_1.authenticationHandler.accessToken;
70
+ cli_utilities_1.log.debug(`Authentication type: ${cli_utilities_1.authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, this.importConfig.context);
71
+ // Set authentication headers based on auth type
72
+ if (cli_utilities_1.authenticationHandler.isOauthEnabled) {
73
+ cli_utilities_1.log.debug('Skipping setting OAuth authorization header when using OAuth authentication', this.importConfig.context);
74
+ return false;
75
+ }
76
+ else {
77
+ // TODO: Currenlty assuming if auth type is not OAuth, it is Basic Auth and we are setting authtoken header
78
+ cli_utilities_1.log.debug('Setting authtoken header', this.importConfig.context);
79
+ this.apiClient.headers({ authtoken: token });
80
+ }
81
+ // Set organization_uid header
82
+ this.apiClient.headers({
83
+ organization_uid: this.importConfig.org_uid,
84
+ 'Content-Type': 'application/json',
85
+ Accept: 'application/json',
86
+ });
87
+ cli_utilities_1.log.debug('Studio API authentication initialized', this.importConfig.context);
88
+ return true;
89
+ }
90
+ /**
91
+ * Load environment UID mapper from backup directory
92
+ */
93
+ async loadEnvironmentMapper() {
94
+ cli_utilities_1.log.debug('Loading environment UID mapper...', this.importConfig.context);
95
+ if (utils_1.fileHelper.fileExistsSync(this.envUidMapperPath)) {
96
+ this.envUidMapper = utils_1.fileHelper.readFileSync(this.envUidMapperPath);
97
+ cli_utilities_1.log.debug(`Environment mapper loaded with ${Object.keys(this.envUidMapper).length} mappings`, this.importConfig.context);
98
+ }
99
+ else {
100
+ cli_utilities_1.log.debug('No environment UID mapper found', this.importConfig.context);
101
+ }
102
+ }
103
+ /**
104
+ * Read exported project from file system
105
+ */
106
+ async readExportedProject() {
107
+ cli_utilities_1.log.debug(`Reading exported project from: ${this.composableStudioFilePath}`, this.importConfig.context);
108
+ if (!utils_1.fileHelper.fileExistsSync(this.composableStudioFilePath)) {
109
+ cli_utilities_1.log.debug('Studio project file does not exist', this.importConfig.context);
110
+ return null;
111
+ }
112
+ const projectData = utils_1.fileHelper.readFileSync(this.composableStudioFilePath);
113
+ if (!projectData || (0, isEmpty_1.default)(projectData)) {
114
+ cli_utilities_1.log.debug('Studio project file is empty', this.importConfig.context);
115
+ return null;
116
+ }
117
+ return projectData;
118
+ }
119
+ /**
120
+ * Check if target stack already has a connected project
121
+ */
122
+ async getExistingProject() {
123
+ var _a;
124
+ cli_utilities_1.log.debug('Checking if target stack already has a connected project...', this.importConfig.context);
125
+ try {
126
+ const apiUrl = '/projects';
127
+ cli_utilities_1.log.debug(`Fetching projects from: ${this.composableStudioConfig.apiBaseUrl}${apiUrl}`, this.importConfig.context);
128
+ const response = await this.apiClient.get(apiUrl);
129
+ if (response.status < 200 || response.status >= 300) {
130
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
131
+ }
132
+ const projects = ((_a = response.data) === null || _a === void 0 ? void 0 : _a.projects) || [];
133
+ cli_utilities_1.log.debug(`Found ${projects.length} projects in organization`, this.importConfig.context);
134
+ // Filter projects by connected stack API key
135
+ const connectedProject = projects.find((project) => project.connectedStackApiKey === this.importConfig.apiKey);
136
+ if (connectedProject) {
137
+ cli_utilities_1.log.debug(`Target stack already has connected project: ${connectedProject.name}`, this.importConfig.context);
138
+ return connectedProject;
139
+ }
140
+ cli_utilities_1.log.debug('Target stack does not have a connected project', this.importConfig.context);
141
+ return null;
142
+ }
143
+ catch (error) {
144
+ cli_utilities_1.log.debug(`Error checking for existing project: ${error.message}`, this.importConfig.context);
145
+ throw error;
146
+ }
147
+ }
148
+ /**
149
+ * Import project with name conflict handling
150
+ */
151
+ async importProject(exportedProject) {
152
+ var _a, _b, _c;
153
+ cli_utilities_1.log.debug('Starting project import...', this.importConfig.context);
154
+ // Map environment UID
155
+ const mappedEnvironmentUid = this.mapEnvironmentUid(exportedProject.settings.configuration.environment);
156
+ // Prepare project data for import
157
+ const projectData = {
158
+ name: exportedProject.name,
159
+ connectedStackApiKey: this.importConfig.apiKey,
160
+ contentTypeUid: exportedProject.contentTypeUid,
161
+ description: exportedProject.description || '',
162
+ canvasUrl: exportedProject.canvasUrl || '/',
163
+ settings: {
164
+ configuration: {
165
+ environment: mappedEnvironmentUid,
166
+ 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) || '',
167
+ },
168
+ },
169
+ };
170
+ cli_utilities_1.log.debug(`Project data prepared: ${JSON.stringify(projectData, null, 2)}`, this.importConfig.context);
171
+ // Try to create project with name conflict retry loop
172
+ let projectCreated = false;
173
+ let currentName = projectData.name;
174
+ let attemptCount = 0;
175
+ while (!projectCreated) {
176
+ attemptCount++;
177
+ cli_utilities_1.log.debug(`Attempt ${attemptCount} to create project with name: ${currentName}`, this.importConfig.context);
178
+ projectData.name = currentName;
179
+ const response = await this.apiClient.post('/projects', projectData);
180
+ if (response.status >= 200 && response.status < 300) {
181
+ projectCreated = true;
182
+ cli_utilities_1.log.debug(`Project created successfully with UID: ${(_c = response.data) === null || _c === void 0 ? void 0 : _c.uid}`, this.importConfig.context);
183
+ // Create mapper directory if it doesn't exist
184
+ await utils_1.fsUtil.makeDirectory(this.projectMapperPath);
185
+ // write the project to file
186
+ const projectFileSuccessPath = (0, node_path_1.join)(this.projectMapperPath, this.composableStudioConfig.fileName);
187
+ utils_1.fsUtil.writeFile(projectFileSuccessPath, response.data);
188
+ cli_utilities_1.log.debug(`Project written to: ${projectFileSuccessPath}`, this.importConfig.context);
189
+ }
190
+ else {
191
+ throw new Error(`API call failed with status ${response.status}: ${JSON.stringify(response.data)}`);
192
+ }
193
+ }
194
+ }
195
+ /**
196
+ * Map environment UID from source to target
197
+ */
198
+ mapEnvironmentUid(sourceEnvUid) {
199
+ if (!sourceEnvUid) {
200
+ cli_utilities_1.log.debug('Source environment UID is empty', this.importConfig.context);
201
+ return '';
202
+ }
203
+ cli_utilities_1.log.debug(`Mapping source environment UID: ${sourceEnvUid}`, this.importConfig.context);
204
+ if ((0, isEmpty_1.default)(this.envUidMapper)) {
205
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
206
+ return '';
207
+ }
208
+ const mappedUid = this.envUidMapper[sourceEnvUid];
209
+ if (!mappedUid) {
210
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_ENV_MAPPING_FAILED', sourceEnvUid), this.importConfig.context);
211
+ return '';
212
+ }
213
+ cli_utilities_1.log.debug(`Mapped environment UID: ${sourceEnvUid} → ${mappedUid}`, this.importConfig.context);
214
+ return mappedUid;
215
+ }
216
+ /**
217
+ * Prompt user for a new project name when conflict occurs
218
+ */
219
+ async promptForNewProjectName(currentName) {
220
+ const suggestedName = `Copy of ${currentName}`;
221
+ cli_utilities_1.log.warn(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_NAME_CONFLICT', currentName), this.importConfig.context);
222
+ cli_utilities_1.log.info(cli_utilities_1.messageHandler.parse('COMPOSABLE_STUDIO_SUGGEST_NAME', suggestedName), this.importConfig.context);
223
+ const response = await cli_utilities_1.cliux.inquire({
224
+ type: 'input',
225
+ name: 'projectName',
226
+ message: 'Enter new project name:',
227
+ default: suggestedName,
228
+ });
229
+ const newName = response.projectName || suggestedName;
230
+ cli_utilities_1.log.debug(`User provided new project name: ${newName}`, this.importConfig.context);
231
+ return newName;
232
+ }
233
+ }
234
+ exports.default = ImportComposableStudio;