@contentstack/cli-variants 1.3.2 → 2.0.0-beta

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 (55) hide show
  1. package/lib/export/attributes.d.ts +2 -2
  2. package/lib/export/attributes.js +51 -23
  3. package/lib/export/audiences.d.ts +2 -2
  4. package/lib/export/audiences.js +50 -24
  5. package/lib/export/events.d.ts +2 -2
  6. package/lib/export/events.js +52 -24
  7. package/lib/export/experiences.js +87 -54
  8. package/lib/export/projects.d.ts +3 -2
  9. package/lib/export/projects.js +55 -63
  10. package/lib/export/variant-entries.d.ts +19 -0
  11. package/lib/export/variant-entries.js +76 -1
  12. package/lib/import/attribute.d.ts +2 -0
  13. package/lib/import/attribute.js +83 -37
  14. package/lib/import/audiences.d.ts +2 -0
  15. package/lib/import/audiences.js +85 -41
  16. package/lib/import/events.d.ts +3 -1
  17. package/lib/import/events.js +86 -30
  18. package/lib/import/experiences.d.ts +2 -0
  19. package/lib/import/experiences.js +93 -39
  20. package/lib/import/project.d.ts +2 -0
  21. package/lib/import/project.js +81 -22
  22. package/lib/import/variant-entries.d.ts +10 -0
  23. package/lib/import/variant-entries.js +139 -53
  24. package/lib/index.d.ts +1 -0
  25. package/lib/index.js +1 -0
  26. package/lib/types/export-config.d.ts +0 -2
  27. package/lib/types/import-config.d.ts +0 -1
  28. package/lib/types/utils.d.ts +1 -1
  29. package/lib/utils/constants.d.ts +91 -0
  30. package/lib/utils/constants.js +93 -0
  31. package/lib/utils/personalization-api-adapter.d.ts +34 -1
  32. package/lib/utils/personalization-api-adapter.js +180 -53
  33. package/lib/utils/variant-api-adapter.d.ts +28 -1
  34. package/lib/utils/variant-api-adapter.js +89 -32
  35. package/package.json +2 -2
  36. package/src/export/attributes.ts +84 -34
  37. package/src/export/audiences.ts +87 -41
  38. package/src/export/events.ts +84 -41
  39. package/src/export/experiences.ts +155 -83
  40. package/src/export/projects.ts +71 -39
  41. package/src/export/variant-entries.ts +136 -12
  42. package/src/import/attribute.ts +105 -49
  43. package/src/import/audiences.ts +110 -54
  44. package/src/import/events.ts +104 -41
  45. package/src/import/experiences.ts +140 -62
  46. package/src/import/project.ts +108 -38
  47. package/src/import/variant-entries.ts +188 -75
  48. package/src/index.ts +2 -1
  49. package/src/types/export-config.ts +0 -2
  50. package/src/types/import-config.ts +0 -1
  51. package/src/types/utils.ts +1 -1
  52. package/src/utils/constants.ts +98 -0
  53. package/src/utils/personalization-api-adapter.ts +212 -76
  54. package/src/utils/variant-api-adapter.ts +137 -50
  55. package/tsconfig.json +1 -1
@@ -0,0 +1,98 @@
1
+ export const PROCESS_NAMES = {
2
+ PROJECTS: 'Projects',
3
+ ATTRIBUTES: 'Attributes',
4
+ AUDIENCES: 'Audiences',
5
+ EVENTS: 'Events',
6
+ EXPERIENCES: 'Experiences',
7
+ VARIANT_ENTRIES: 'Variant Entries',
8
+ } as const;
9
+
10
+ export const MODULE_DISPLAY_MAPPER = {
11
+ events: PROCESS_NAMES.EVENTS,
12
+ attributes: PROCESS_NAMES.ATTRIBUTES,
13
+ audiences: PROCESS_NAMES.AUDIENCES,
14
+ experiences: PROCESS_NAMES.EXPERIENCES,
15
+ projects: PROCESS_NAMES.PROJECTS,
16
+ 'variant-entries': PROCESS_NAMES.VARIANT_ENTRIES,
17
+ } as const;
18
+
19
+ export const MODULE_CONTEXTS = {
20
+ PROJECTS: 'projects',
21
+ ATTRIBUTES: 'attributes',
22
+ AUDIENCES: 'audiences',
23
+ EVENTS: 'events',
24
+ EXPERIENCES: 'experiences',
25
+ VARIANT_ENTRIES: 'variant-entries',
26
+ } as const;
27
+
28
+ // Export process status messages
29
+ export const EXPORT_PROCESS_STATUS = {
30
+ [PROCESS_NAMES.PROJECTS]: {
31
+ FETCHING: 'Fetching projects...',
32
+ EXPORTING: 'Exporting projects...',
33
+ FAILED: 'Failed to export projects.',
34
+ },
35
+ [PROCESS_NAMES.ATTRIBUTES]: {
36
+ FETCHING: 'Fetching attributes...',
37
+ EXPORTING: 'Exporting attributes...',
38
+ FAILED: 'Failed to export attributes.',
39
+ },
40
+ [PROCESS_NAMES.AUDIENCES]: {
41
+ FETCHING: 'Fetching audiences...',
42
+ EXPORTING: 'Exporting audiences...',
43
+ FAILED: 'Failed to export audiences.',
44
+ },
45
+ [PROCESS_NAMES.EVENTS]: {
46
+ FETCHING: 'Fetching events...',
47
+ EXPORTING: 'Exporting events...',
48
+ FAILED: 'Failed to export events.',
49
+ },
50
+ [PROCESS_NAMES.EXPERIENCES]: {
51
+ FETCHING: 'Fetching experiences...',
52
+ EXPORTING: 'Exporting experiences...',
53
+ FAILED: 'Failed to export experiences.',
54
+ },
55
+ [PROCESS_NAMES.VARIANT_ENTRIES]: {
56
+ PROCESSING: 'Processing variant entries...',
57
+ EXPORTING: 'Exporting variant entries...',
58
+ FAILED: 'Failed to export variant entries.',
59
+ },
60
+ } as const;
61
+
62
+ // Import process status messages
63
+ export const IMPORT_PROCESS_STATUS = {
64
+ [PROCESS_NAMES.PROJECTS]: {
65
+ CREATING: 'Creating projects...',
66
+ IMPORTING: 'Importing projects...',
67
+ FAILED: 'Failed to import projects.',
68
+ },
69
+ [PROCESS_NAMES.ATTRIBUTES]: {
70
+ CREATING: 'Creating attributes...',
71
+ IMPORTING: 'Importing attributes...',
72
+ FAILED: 'Failed to import attributes.',
73
+ },
74
+ [PROCESS_NAMES.AUDIENCES]: {
75
+ CREATING: 'Creating audiences...',
76
+ IMPORTING: 'Importing audiences...',
77
+ FAILED: 'Failed to import audiences.',
78
+ },
79
+ [PROCESS_NAMES.EVENTS]: {
80
+ CREATING: 'Creating events...',
81
+ IMPORTING: 'Importing events...',
82
+ FAILED: 'Failed to import events.',
83
+ },
84
+ [PROCESS_NAMES.EXPERIENCES]: {
85
+ CREATING: 'Creating experiences...',
86
+ IMPORTING: 'Importing experiences...',
87
+ FAILED: 'Failed to import experiences.',
88
+ },
89
+ [PROCESS_NAMES.VARIANT_ENTRIES]: {
90
+ PROCESSING: 'Processing variant entries...',
91
+ IMPORTING: 'Importing variant entries...',
92
+ FAILED: 'Failed to import variant entries.',
93
+ },
94
+ } as const;
95
+
96
+ export type ProcessName = typeof PROCESS_NAMES[keyof typeof PROCESS_NAMES];
97
+ export type ModuleKey = keyof typeof MODULE_DISPLAY_MAPPER;
98
+ export type ModuleContext = typeof MODULE_CONTEXTS[keyof typeof MODULE_CONTEXTS];
@@ -1,5 +1,5 @@
1
1
  import { AdapterHelper } from './adapter-helper';
2
- import { HttpClient, authenticationHandler, log } from '@contentstack/cli-utilities';
2
+ import { HttpClient, authenticationHandler, log, CLIProgressManager, configHandler } from '@contentstack/cli-utilities';
3
3
 
4
4
  import {
5
5
  ProjectStruct,
@@ -23,51 +23,164 @@ import {
23
23
  VariantGroupStruct,
24
24
  VariantGroup,
25
25
  CreateExperienceVersionInput,
26
- ExportConfig
26
+ ExportConfig,
27
27
  } from '../types';
28
28
  import { formatErrors } from './error-helper';
29
29
 
30
30
  export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> implements Personalization<T> {
31
31
  public exportConfig?: ExportConfig; // Add exportConfig property to access context
32
+ protected progressManager: CLIProgressManager | null = null;
33
+ protected parentProgressManager: CLIProgressManager | null = null; // Add parent progress manager
34
+ protected currentModuleName: string = '';
35
+ protected cachedData: any[] | null = null; // Add cached data property
32
36
 
33
37
  constructor(options: APIConfig) {
34
38
  super(options);
35
39
  log.debug('PersonalizationAdapter initialized', this.exportConfig?.context);
36
40
  }
37
41
 
42
+ /**
43
+ * Set parent progress manager for sub-module integration
44
+ */
45
+ public setParentProgressManager(parentProgress: CLIProgressManager): void {
46
+ this.parentProgressManager = parentProgress;
47
+ }
48
+
49
+ /**
50
+ * Set cached data to avoid redundant API calls
51
+ */
52
+ public setCachedData(data: any[]): void {
53
+ this.cachedData = data;
54
+ log.debug(`Cached data set with ${data?.length || 0} items`, this.exportConfig?.context);
55
+ }
56
+
57
+ /**
58
+ * Create simple progress manager for single process tracking
59
+ */
60
+ protected createSimpleProgress(moduleName: string, total?: number): CLIProgressManager {
61
+ this.currentModuleName = moduleName;
62
+
63
+ // If we have a parent progress manager, use it instead of creating a new one
64
+ if (this.parentProgressManager) {
65
+ this.progressManager = this.parentProgressManager;
66
+ return this.progressManager;
67
+ }
68
+
69
+ const logConfig = configHandler.get('log') || {};
70
+ const showConsoleLogs = logConfig.showConsoleLogs ?? false;
71
+ this.progressManager = CLIProgressManager.createSimple(moduleName, total, showConsoleLogs);
72
+ return this.progressManager;
73
+ }
74
+
75
+ /**
76
+ * Create nested progress manager for multi-process tracking
77
+ */
78
+ protected createNestedProgress(moduleName: string): CLIProgressManager {
79
+ this.currentModuleName = moduleName;
80
+
81
+ // If we have a parent progress manager, use it instead of creating a new one
82
+ if (this.parentProgressManager) {
83
+ this.progressManager = this.parentProgressManager;
84
+ return this.progressManager;
85
+ }
86
+
87
+ const logConfig = configHandler.get('log') || {};
88
+ const showConsoleLogs = logConfig.showConsoleLogs ?? false;
89
+ this.progressManager = CLIProgressManager.createNested(moduleName, showConsoleLogs);
90
+ return this.progressManager;
91
+ }
92
+
93
+ /**
94
+ * Complete progress manager
95
+ */
96
+ protected completeProgress(success: boolean = true, error?: string): void {
97
+ // Only complete progress if we own the progress manager (no parent)
98
+ if (!this.parentProgressManager) {
99
+ this.progressManager?.complete(success, error);
100
+ }
101
+ this.progressManager = null;
102
+ }
103
+
104
+ /**
105
+ * Execute action with loading spinner for initial setup tasks
106
+ */
107
+ protected async withLoadingSpinner<T>(message: string, action: () => Promise<T>): Promise<T> {
108
+ const logConfig = configHandler.get('log') || {};
109
+ const showConsoleLogs = logConfig.showConsoleLogs ?? false;
110
+
111
+ if (showConsoleLogs) {
112
+ // If console logs are enabled, don't show spinner, just execute the action
113
+ return await action();
114
+ }
115
+ return await CLIProgressManager.withLoadingSpinner(message, action);
116
+ }
117
+
118
+ /**
119
+ * Update progress for a specific item
120
+ */
121
+ protected updateProgress(success: boolean, itemName: string, error?: string, processName?: string): void {
122
+ if (this.parentProgressManager) {
123
+ this.parentProgressManager.tick(success, itemName, error, processName);
124
+ } else if (this.progressManager) {
125
+ this.progressManager.tick(success, itemName, error, processName);
126
+ }
127
+ }
128
+
129
+ static printFinalSummary(): void {
130
+ CLIProgressManager.printGlobalSummary();
131
+ }
132
+
38
133
  async init(): Promise<void> {
39
- log.debug('Initializing personalization adapter...', this.exportConfig?.context );
40
- await authenticationHandler.getAuthDetails();
41
- const token = authenticationHandler.accessToken;
42
- log.debug(`Authentication type: ${authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`, this.exportConfig?.context );
43
-
44
- if (authenticationHandler.isOauthEnabled) {
45
- log.debug('Setting OAuth authorization header', this.exportConfig?.context );
46
- this.apiClient.headers({ authorization: token });
47
- if (this.adapterConfig.cmaConfig) {
48
- log.debug('Setting OAuth authorization header for CMA client', this.exportConfig?.context );
49
- this.cmaAPIClient?.headers({ authorization: token });
50
- }
51
- } else {
52
- log.debug('Setting authtoken header', this.exportConfig?.context );
53
- this.apiClient.headers({ authtoken: token });
54
- if (this.adapterConfig.cmaConfig) {
55
- log.debug('Setting authtoken header for CMA client', this.exportConfig?.context );
56
- this.cmaAPIClient?.headers({ authtoken: token });
134
+ try {
135
+ log.debug('Initializing personalization adapter...', this.exportConfig?.context);
136
+ await authenticationHandler.getAuthDetails();
137
+ const token = authenticationHandler.accessToken;
138
+ log.debug(
139
+ `Authentication type: ${authenticationHandler.isOauthEnabled ? 'OAuth' : 'Token'}`,
140
+ this.exportConfig?.context,
141
+ );
142
+
143
+ if (authenticationHandler.isOauthEnabled) {
144
+ log.debug('Setting OAuth authorization header', this.exportConfig?.context);
145
+ this.apiClient.headers({ authorization: token });
146
+ if (this.adapterConfig.cmaConfig) {
147
+ log.debug('Setting OAuth authorization header for CMA client', this.exportConfig?.context);
148
+ this.cmaAPIClient?.headers({ authorization: token });
149
+ }
150
+ } else {
151
+ log.debug('Setting authtoken header', this.exportConfig?.context);
152
+ this.apiClient.headers({ authtoken: token });
153
+ if (this.adapterConfig.cmaConfig) {
154
+ log.debug('Setting authtoken header for CMA client', this.exportConfig?.context);
155
+ this.cmaAPIClient?.headers({ authtoken: token });
156
+ }
57
157
  }
158
+ log.debug('Personalization adapter initialization completed', this.exportConfig?.context);
159
+ } catch (error: any) {
160
+ log.debug(`Personalization adapter initialization failed: ${error}`, this.exportConfig?.context);
58
161
  }
59
- log.debug('Personalization adapter initialization completed', this.exportConfig?.context );
60
162
  }
61
163
 
62
164
  async projects(options: GetProjectsParams): Promise<ProjectStruct[]> {
63
- log.debug(`Fetching projects for stack API key: ${options.connectedStackApiKey}`, this.exportConfig?.context );
64
165
  await this.init();
65
166
  const getProjectEndPoint = `/projects?connectedStackApiKey=${options.connectedStackApiKey}`;
66
- log.debug(`Making API call to: ${getProjectEndPoint}`, this.exportConfig?.context );
67
- const data = await this.apiClient.get(getProjectEndPoint);
68
- const result = (await this.handleVariantAPIRes(data)) as ProjectStruct[];
69
- log.debug(`Fetched ${result?.length || 0} projects`, this.exportConfig?.context );
70
- return result;
167
+ log.debug(`Making API call to: ${getProjectEndPoint}`, this.exportConfig?.context);
168
+
169
+ try {
170
+ const data = await this.apiClient.get(getProjectEndPoint);
171
+ const result = (await this.handleVariantAPIRes(data)) as ProjectStruct[];
172
+ log.debug(`Fetched ${result?.length || 0} projects`, this.exportConfig?.context);
173
+
174
+ // Update progress for each project fetched
175
+ result?.forEach((project) => {
176
+ this.updateProgress(true, `project: ${project.name || project.uid}`, undefined, 'Projects');
177
+ });
178
+
179
+ return result;
180
+ } catch (error: any) {
181
+ log.debug(`Failed to fetch projects: ${error}`, this.exportConfig?.context);
182
+ throw error;
183
+ }
71
184
  }
72
185
 
73
186
  /**
@@ -81,10 +194,10 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
81
194
  * `ProjectStruct` object or `void`.
82
195
  */
83
196
  async createProject(project: CreateProjectInput): Promise<ProjectStruct> {
84
- log.debug(`Creating project: ${project.name}`, this.exportConfig?.context );
197
+ log.debug(`Creating project: ${project.name}`, this.exportConfig?.context);
85
198
  const data = await this.apiClient.post<ProjectStruct>('/projects', project);
86
199
  const result = (await this.handleVariantAPIRes(data)) as ProjectStruct;
87
- log.debug(`Project created successfully: ${result.uid}`, this.exportConfig?.context );
200
+ log.info(`Project created successfully: ${result?.uid}`, this.exportConfig?.context);
88
201
  return result;
89
202
  }
90
203
 
@@ -98,43 +211,55 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
98
211
  * `ProjectStruct`.
99
212
  */
100
213
  async createAttribute(attribute: CreateAttributeInput): Promise<AttributeStruct> {
101
- log.debug(`Creating attribute: ${attribute.name}`, this.exportConfig?.context );
214
+ log.debug(`Creating attribute: ${attribute.name}`, this.exportConfig?.context);
102
215
  const data = await this.apiClient.post<AttributeStruct>('/attributes', attribute);
103
216
  const result = (await this.handleVariantAPIRes(data)) as AttributeStruct;
104
- log.debug(`Attribute created successfully: ${result.uid}`, this.exportConfig?.context );
217
+ log.info(`Attribute created successfully: ${result?.name || result?.uid}`, this.exportConfig?.context );
105
218
  return result;
106
219
  }
107
220
 
108
221
  async getExperiences(): Promise<ExperienceStruct[]> {
109
- log.debug('Fetching experiences from personalization API', this.exportConfig?.context );
222
+ log.debug('Fetching experiences from personalization API', this.exportConfig?.context);
110
223
  const getExperiencesEndPoint = `/experiences`;
111
- const data = await this.apiClient.get(getExperiencesEndPoint);
112
- const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct[];
113
- log.debug(`Fetched ${result?.length || 0} experiences`, this.exportConfig?.context );
114
- return result;
224
+
225
+ try {
226
+ const data = await this.apiClient.get(getExperiencesEndPoint);
227
+ const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct[];
228
+ log.debug(`Fetched ${result?.length || 0} experiences`, this.exportConfig?.context);
229
+
230
+ // Update progress for each experience fetched
231
+ result?.forEach((experience) => {
232
+ this.updateProgress(true, `experience: ${experience.name || experience.uid}`, undefined, 'Experiences');
233
+ });
234
+
235
+ return result;
236
+ } catch (error: any) {
237
+ log.debug(`Failed to fetch experiences: ${error}`, this.exportConfig?.context);
238
+ throw error;
239
+ }
115
240
  }
116
241
 
117
242
  async getExperience(experienceUid: string): Promise<ExperienceStruct | void> {
118
- log.debug(`Fetching experience: ${experienceUid}`, this.exportConfig?.context );
243
+ log.debug(`Fetching experience: ${experienceUid}`, this.exportConfig?.context);
119
244
  const getExperiencesEndPoint = `/experiences/${experienceUid}`;
120
245
  if (this.apiClient.requestConfig?.().data) {
121
246
  delete this.apiClient.requestConfig?.().data; // explicitly prevent any accidental body
122
247
  }
123
248
  const data = await this.apiClient.get(getExperiencesEndPoint);
124
249
  const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct;
125
- log.debug(`Experience fetched successfully: ${result?.uid}`, this.exportConfig?.context );
250
+ log.debug(`Experience fetched successfully: ${result?.uid}`, this.exportConfig?.context);
126
251
  return result;
127
252
  }
128
253
 
129
254
  async getExperienceVersions(experienceUid: string): Promise<ExperienceStruct | void> {
130
- log.debug(`Fetching versions for experience: ${experienceUid}`, this.exportConfig?.context );
255
+ log.debug(`Fetching versions for experience: ${experienceUid}`, this.exportConfig?.context);
131
256
  const getExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions`;
132
257
  if (this.apiClient.requestConfig?.().data) {
133
258
  delete this.apiClient.requestConfig?.().data; // explicitly prevent any accidental body
134
259
  }
135
260
  const data = await this.apiClient.get(getExperiencesVersionsEndPoint);
136
261
  const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct;
137
- log.debug(`Experience versions fetched successfully for: ${experienceUid}`, this.exportConfig?.context );
262
+ log.info(`Experience versions fetched successfully for: ${experienceUid}`, this.exportConfig?.context );
138
263
  return result;
139
264
  }
140
265
 
@@ -142,11 +267,11 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
142
267
  experienceUid: string,
143
268
  input: CreateExperienceVersionInput,
144
269
  ): Promise<ExperienceStruct | void> {
145
- log.debug(`Creating experience version for: ${experienceUid}`, this.exportConfig?.context );
270
+ log.debug(`Creating experience version for: ${experienceUid}`, this.exportConfig?.context);
146
271
  const createExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions`;
147
272
  const data = await this.apiClient.post(createExperiencesVersionsEndPoint, input);
148
273
  const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct;
149
- log.debug(`Experience version created successfully for: ${experienceUid}`, this.exportConfig?.context );
274
+ log.debug(`Experience version created successfully for: ${experienceUid}`, this.exportConfig?.context);
150
275
  return result;
151
276
  }
152
277
 
@@ -155,76 +280,87 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
155
280
  versionId: string,
156
281
  input: CreateExperienceVersionInput,
157
282
  ): Promise<ExperienceStruct | void> {
158
- log.debug(`Updating experience version: ${versionId} for experience: ${experienceUid}`, this.exportConfig?.context );
283
+ log.debug(`Updating experience version: ${versionId} for experience: ${experienceUid}`, this.exportConfig?.context);
159
284
  // loop through input and remove shortId from variant
160
285
  if (input?.variants) {
161
286
  input.variants = input.variants.map(({ shortUid, ...rest }) => rest);
162
- log.debug(`Processed ${input.variants.length} variants for update`, this.exportConfig?.context );
287
+ log.debug(`Processed ${input.variants.length} variants for update`, this.exportConfig?.context);
163
288
  }
164
289
  const updateExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions/${versionId}`;
165
290
  const data = await this.apiClient.put(updateExperiencesVersionsEndPoint, input);
166
291
  const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct;
167
- log.debug(`Experience version updated successfully: ${versionId}`, this.exportConfig?.context );
292
+ log.debug(`Experience version updated successfully: ${versionId}`, this.exportConfig?.context);
168
293
  return result;
169
294
  }
170
295
 
171
296
  async getVariantGroup(input: GetVariantGroupInput): Promise<VariantGroupStruct | void> {
172
- log.debug(`Fetching variant group for experience: ${input.experienceUid}`, this.exportConfig?.context );
297
+ log.debug(`Fetching variant group for experience: ${input.experienceUid}`, this.exportConfig?.context);
173
298
  if (this.cmaAPIClient) {
174
299
  const getVariantGroupEndPoint = `/variant_groups`;
175
300
  const data = await this.cmaAPIClient
176
301
  .queryParams({ experience_uid: input.experienceUid })
177
302
  .get(getVariantGroupEndPoint);
178
303
  const result = (await this.handleVariantAPIRes(data)) as VariantGroupStruct;
179
- log.debug(`Variant group fetched successfully for experience: ${input.experienceUid}`, this.exportConfig?.context );
304
+ log.debug(`Variant group fetched successfully for experience: ${input?.experienceUid}`, this.exportConfig?.context );
180
305
  return result;
181
306
  } else {
182
- log.debug('CMA API client not available for variant group fetch', this.exportConfig?.context );
307
+ log.debug('CMA API client not available for variant group fetch', this.exportConfig?.context);
183
308
  }
184
309
  }
185
310
 
186
311
  async updateVariantGroup(input: VariantGroup): Promise<VariantGroup | void> {
187
- log.debug(`Updating variant group: ${input.uid}`, this.exportConfig?.context );
312
+ log.debug(`Updating variant group: ${input.uid}`, this.exportConfig?.context);
188
313
  if (this.cmaAPIClient) {
189
314
  const updateVariantGroupEndPoint = `/variant_groups/${input.uid}`;
190
315
  const data = await this.cmaAPIClient.put(updateVariantGroupEndPoint, input);
191
316
  const result = (await this.handleVariantAPIRes(data)) as VariantGroup;
192
- log.debug(`Variant group updated successfully: ${input.uid}`, this.exportConfig?.context );
317
+ log.debug(`Variant group updated successfully: ${input?.uid}`, this.exportConfig?.context );
193
318
  return result;
194
319
  } else {
195
- log.debug('CMA API client not available for variant group update', this.exportConfig?.context );
320
+ log.debug('CMA API client not available for variant group update', this.exportConfig?.context);
196
321
  }
197
322
  }
198
323
 
199
324
  async getEvents(): Promise<EventStruct[] | void> {
200
- log.debug('Fetching events from personalization API', this.exportConfig?.context );
201
- const data = await this.apiClient.get<EventStruct>('/events');
202
- const result = (await this.handleVariantAPIRes(data)) as EventStruct[];
203
- log.debug(`Fetched ${result?.length || 0} events`, this.exportConfig?.context );
204
- return result;
325
+ log.debug('Fetching events from personalization API', this.exportConfig?.context);
326
+ try {
327
+ const data = await this.apiClient.get<EventStruct>('/events');
328
+ const result = (await this.handleVariantAPIRes(data)) as EventStruct[];
329
+ log.debug(`Fetched ${result?.length || 0} events`, this.exportConfig?.context);
330
+ return result;
331
+ } catch (error: any) {
332
+ log.debug(`Failed to fetch events: ${error}`, this.exportConfig?.context);
333
+ // Return empty array instead of throwing to prevent spinner from hanging
334
+ throw error;
335
+ }
205
336
  }
206
337
 
207
338
  async createEvents(event: CreateEventInput): Promise<void | EventStruct> {
208
- log.debug(`Creating event: ${event.key}`, this.exportConfig?.context );
209
339
  const data = await this.apiClient.post<EventStruct>('/events', event);
210
340
  const result = (await this.handleVariantAPIRes(data)) as EventStruct;
211
- log.debug(`Event created successfully: ${result.uid}`, this.exportConfig?.context );
341
+ log.info(`Event created successfully: ${result?.uid}`, this.exportConfig?.context );
212
342
  return result;
213
343
  }
214
344
 
215
345
  async getAudiences(): Promise<AudienceStruct[] | void> {
216
- log.debug('Fetching audiences from personalization API', this.exportConfig?.context );
217
- const data = await this.apiClient.get<AudienceStruct>('/audiences');
218
- const result = (await this.handleVariantAPIRes(data)) as AudienceStruct[];
219
- log.debug(`Fetched ${result?.length || 0} audiences`, this.exportConfig?.context );
220
- return result;
346
+ log.debug('Fetching audiences from personalization API', this.exportConfig?.context);
347
+ try {
348
+ const data = await this.apiClient.get<AudienceStruct>('/audiences');
349
+ const result = (await this.handleVariantAPIRes(data)) as AudienceStruct[];
350
+ log.debug(`Fetched ${result?.length || 0} audiences`, this.exportConfig?.context);
351
+ return result;
352
+ } catch (error: any) {
353
+ log.debug(`Failed to fetch audiences: ${error}`, this.exportConfig?.context);
354
+ // Return empty array instead of throwing to prevent spinner from hanging
355
+ throw error;
356
+ }
221
357
  }
222
358
 
223
359
  async getAttributes(): Promise<AttributeStruct[] | void> {
224
360
  log.debug('Fetching attributes from personalization API', this.exportConfig?.context );
225
361
  const data = await this.apiClient.get<AttributeStruct>('/attributes');
226
362
  const result = (await this.handleVariantAPIRes(data)) as AttributeStruct[];
227
- log.debug(`Fetched ${result?.length || 0} attributes`, this.exportConfig?.context );
363
+ log.info(`Fetched ${result?.length || 0} attributes`, this.exportConfig?.context );
228
364
  return result;
229
365
  }
230
366
 
@@ -237,10 +373,10 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
237
373
  * `AudienceStruct`.
238
374
  */
239
375
  async createAudience(audience: CreateAudienceInput): Promise<void | AudienceStruct> {
240
- log.debug(`Creating audience: ${audience.name}`, this.exportConfig?.context );
376
+ log.debug(`Creating audience: ${audience.name}`, this.exportConfig?.context);
241
377
  const data = await this.apiClient.post<AudienceStruct>('/audiences', audience);
242
378
  const result = (await this.handleVariantAPIRes(data)) as AudienceStruct;
243
- log.debug(`Audience created successfully: ${result.uid}`, this.exportConfig?.context );
379
+ log.info(`Audience created successfully: ${result?.name || result?.uid}`, this.exportConfig?.context );
244
380
  return result;
245
381
  }
246
382
 
@@ -253,10 +389,10 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
253
389
  * `ExperienceStruct`.
254
390
  */
255
391
  async createExperience(experience: CreateExperienceInput): Promise<void | ExperienceStruct> {
256
- log.debug(`Creating experience: ${experience.name}`, this.exportConfig?.context );
392
+ log.debug(`Creating experience: ${experience.name}`, this.exportConfig?.context);
257
393
  const data = await this.apiClient.post<ExperienceStruct>('/experiences', experience);
258
394
  const result = (await this.handleVariantAPIRes(data)) as ExperienceStruct;
259
- log.debug(`Experience created successfully: ${result.uid}`, this.exportConfig?.context );
395
+ log.info(`Experience created successfully: ${result?.name || result?.uid}`, this.exportConfig?.context );
260
396
  return result;
261
397
  }
262
398
 
@@ -269,11 +405,11 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
269
405
  experience: UpdateExperienceInput,
270
406
  experienceUid: string,
271
407
  ): Promise<void | CMSExperienceStruct> {
272
- log.debug(`Updating content types in experience: ${experienceUid}`, this.exportConfig?.context );
408
+ log.debug(`Updating content types in experience: ${experienceUid}`, this.exportConfig?.context);
273
409
  const updateCTInExpEndPoint = `/experiences/${experienceUid}/cms-integration/variant-group`;
274
410
  const data = await this.apiClient.post<CMSExperienceStruct>(updateCTInExpEndPoint, experience);
275
411
  const result = (await this.handleVariantAPIRes(data)) as CMSExperienceStruct;
276
- log.debug(`Content types updated successfully in experience: ${experienceUid}`, this.exportConfig?.context );
412
+ log.info(`Content types updated successfully in experience: ${experienceUid}`, this.exportConfig?.context );
277
413
  return result;
278
414
  }
279
415
 
@@ -283,11 +419,11 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
283
419
  * needed to fetch CT details related to experience.
284
420
  */
285
421
  async getCTsFromExperience(experienceUid: string): Promise<void | CMSExperienceStruct> {
286
- log.debug(`Fetching content types from experience: ${experienceUid}`, this.exportConfig?.context );
422
+ log.debug(`Fetching content types from experience: ${experienceUid}`, this.exportConfig?.context);
287
423
  const getCTFromExpEndPoint = `/experiences/${experienceUid}/cms-integration/variant-group`;
288
424
  const data = await this.apiClient.get<CMSExperienceStruct>(getCTFromExpEndPoint);
289
425
  const result = (await this.handleVariantAPIRes(data)) as CMSExperienceStruct;
290
- log.debug(`Content types fetched successfully from experience: ${experienceUid}`, this.exportConfig?.context );
426
+ log.info(`Content types fetched successfully from experience: ${experienceUid}`, this.exportConfig?.context );
291
427
  return result;
292
428
  }
293
429
 
@@ -299,21 +435,21 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
299
435
  */
300
436
  async handleVariantAPIRes(res: APIResponse): Promise<VariantAPIRes> {
301
437
  const { status, data } = res;
302
- log.debug(`API response status: ${status}`, this.exportConfig?.context );
438
+ log.debug(`API response status: ${status}`, this.exportConfig?.context);
303
439
 
304
440
  if (status >= 200 && status < 300) {
305
- log.debug('API request successful', this.exportConfig?.context );
441
+ log.debug('API request successful', this.exportConfig?.context);
306
442
  return data;
307
443
  }
308
444
 
309
- log.debug(`API request failed with status: ${status}`, this.exportConfig?.context );
445
+ log.debug(`API request failed with status: ${status}`, this.exportConfig?.context);
310
446
  // Refresh the access token if it has expired
311
447
  await authenticationHandler.refreshAccessToken(res);
312
448
 
313
449
  const errorMsg = data?.errors
314
450
  ? formatErrors(data.errors)
315
451
  : data?.error || data?.error_message || data?.message || data;
316
- log.debug(`API error: ${errorMsg}`, this.exportConfig?.context );
452
+ log.debug(`API error: ${errorMsg}`, this.exportConfig?.context);
317
453
  throw errorMsg;
318
454
  }
319
455
  }