@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.
- package/lib/export/attributes.d.ts +2 -2
- package/lib/export/attributes.js +51 -23
- package/lib/export/audiences.d.ts +2 -2
- package/lib/export/audiences.js +50 -24
- package/lib/export/events.d.ts +2 -2
- package/lib/export/events.js +52 -24
- package/lib/export/experiences.js +87 -54
- package/lib/export/projects.d.ts +3 -2
- package/lib/export/projects.js +55 -63
- package/lib/export/variant-entries.d.ts +19 -0
- package/lib/export/variant-entries.js +76 -1
- package/lib/import/attribute.d.ts +2 -0
- package/lib/import/attribute.js +83 -37
- package/lib/import/audiences.d.ts +2 -0
- package/lib/import/audiences.js +85 -41
- package/lib/import/events.d.ts +3 -1
- package/lib/import/events.js +86 -30
- package/lib/import/experiences.d.ts +2 -0
- package/lib/import/experiences.js +93 -39
- package/lib/import/project.d.ts +2 -0
- package/lib/import/project.js +81 -22
- package/lib/import/variant-entries.d.ts +10 -0
- package/lib/import/variant-entries.js +139 -53
- package/lib/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/types/export-config.d.ts +0 -2
- package/lib/types/import-config.d.ts +0 -1
- package/lib/types/utils.d.ts +1 -1
- package/lib/utils/constants.d.ts +91 -0
- package/lib/utils/constants.js +93 -0
- package/lib/utils/personalization-api-adapter.d.ts +34 -1
- package/lib/utils/personalization-api-adapter.js +180 -53
- package/lib/utils/variant-api-adapter.d.ts +28 -1
- package/lib/utils/variant-api-adapter.js +89 -32
- package/package.json +2 -2
- package/src/export/attributes.ts +84 -34
- package/src/export/audiences.ts +87 -41
- package/src/export/events.ts +84 -41
- package/src/export/experiences.ts +155 -83
- package/src/export/projects.ts +71 -39
- package/src/export/variant-entries.ts +136 -12
- package/src/import/attribute.ts +105 -49
- package/src/import/audiences.ts +110 -54
- package/src/import/events.ts +104 -41
- package/src/import/experiences.ts +140 -62
- package/src/import/project.ts +108 -38
- package/src/import/variant-entries.ts +188 -75
- package/src/index.ts +2 -1
- package/src/types/export-config.ts +0 -2
- package/src/types/import-config.ts +0 -1
- package/src/types/utils.ts +1 -1
- package/src/utils/constants.ts +98 -0
- package/src/utils/personalization-api-adapter.ts +212 -76
- package/src/utils/variant-api-adapter.ts +137 -50
- 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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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.
|
|
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.
|
|
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
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
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.
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
}
|