@contentstack/cli-variants 0.0.1-alpha → 1.1.0
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 +5 -4
- package/lib/export/audiences.d.ts +2 -2
- package/lib/export/audiences.js +5 -4
- package/lib/export/events.d.ts +2 -2
- package/lib/export/events.js +5 -4
- package/lib/export/experiences.d.ts +2 -2
- package/lib/export/experiences.js +20 -5
- package/lib/export/projects.d.ts +2 -2
- package/lib/export/projects.js +9 -6
- package/lib/export/variant-entries.js +1 -1
- package/lib/import/attribute.d.ts +1 -1
- package/lib/import/attribute.js +21 -10
- package/lib/import/audiences.d.ts +2 -2
- package/lib/import/audiences.js +21 -14
- package/lib/import/events.d.ts +1 -1
- package/lib/import/events.js +15 -8
- package/lib/import/experiences.d.ts +12 -5
- package/lib/import/experiences.js +86 -21
- package/lib/import/project.js +12 -11
- package/lib/import/variant-entries.d.ts +1 -1
- package/lib/import/variant-entries.js +28 -22
- package/lib/messages/index.d.ts +1 -1
- package/lib/messages/index.js +3 -2
- package/lib/types/export-config.d.ts +3 -3
- package/lib/types/import-config.d.ts +1 -1
- package/lib/types/personalization-api-adapter.d.ts +14 -1
- package/lib/types/variant-api-adapter.d.ts +3 -2
- package/lib/types/variant-entry.d.ts +2 -3
- package/lib/utils/attributes-helper.js +2 -2
- package/lib/utils/audiences-helper.js +14 -3
- package/lib/utils/error-helper.js +6 -6
- package/lib/utils/logger.js +5 -4
- package/lib/utils/personalization-api-adapter.d.ts +6 -2
- package/lib/utils/personalization-api-adapter.js +90 -23
- package/lib/utils/variant-api-adapter.d.ts +5 -4
- package/lib/utils/variant-api-adapter.js +29 -10
- package/package.json +2 -2
- package/src/export/attributes.ts +11 -7
- package/src/export/audiences.ts +7 -6
- package/src/export/events.ts +7 -6
- package/src/export/experiences.ts +24 -7
- package/src/export/projects.ts +11 -8
- package/src/export/variant-entries.ts +1 -2
- package/src/import/attribute.ts +31 -13
- package/src/import/audiences.ts +37 -19
- package/src/import/events.ts +25 -11
- package/src/import/experiences.ts +120 -30
- package/src/import/project.ts +13 -13
- package/src/import/variant-entries.ts +70 -37
- package/src/messages/index.ts +3 -2
- package/src/types/export-config.ts +3 -3
- package/src/types/import-config.ts +1 -1
- package/src/types/personalization-api-adapter.ts +14 -1
- package/src/types/variant-api-adapter.ts +3 -1
- package/src/types/variant-entry.ts +2 -3
- package/src/utils/attributes-helper.ts +2 -2
- package/src/utils/audiences-helper.ts +12 -2
- package/src/utils/error-helper.ts +6 -6
- package/src/utils/logger.ts +5 -4
- package/src/utils/personalization-api-adapter.ts +71 -18
- package/src/utils/variant-api-adapter.ts +21 -7
|
@@ -29,7 +29,7 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
29
29
|
public entriesMapperPath: string;
|
|
30
30
|
public variantEntryBasePath!: string;
|
|
31
31
|
public variantIdList!: Record<string, unknown>;
|
|
32
|
-
public
|
|
32
|
+
public personalizeConfig: ImportConfig['modules']['personalize'];
|
|
33
33
|
|
|
34
34
|
public taxonomies!: Record<string, unknown>;
|
|
35
35
|
public assetUrlMapper!: Record<string, any>;
|
|
@@ -49,15 +49,23 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
49
49
|
headers: {
|
|
50
50
|
api_key: config.apiKey,
|
|
51
51
|
branch: config.branchName,
|
|
52
|
-
authtoken: config.auth_token,
|
|
53
52
|
organization_uid: config.org_uid,
|
|
54
|
-
'X-Project-Uid': config.modules.
|
|
53
|
+
'X-Project-Uid': config.modules.personalize.project_id,
|
|
55
54
|
},
|
|
56
|
-
};
|
|
55
|
+
};
|
|
57
56
|
super(Object.assign(omit(config, ['helpers']), conf));
|
|
58
|
-
this.entriesMapperPath = resolve(
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
this.entriesMapperPath = resolve(
|
|
58
|
+
sanitizePath(config.backupDir),
|
|
59
|
+
sanitizePath(config.branchName || ''),
|
|
60
|
+
'mapper',
|
|
61
|
+
'entries',
|
|
62
|
+
);
|
|
63
|
+
this.personalizeConfig = this.config.modules.personalize;
|
|
64
|
+
this.entriesDirPath = resolve(
|
|
65
|
+
sanitizePath(config.backupDir),
|
|
66
|
+
sanitizePath(config.branchName || ''),
|
|
67
|
+
sanitizePath(config.modules.entries.dirName),
|
|
68
|
+
);
|
|
61
69
|
this.failedVariantPath = resolve(sanitizePath(this.entriesMapperPath), 'failed-entry-variants.json');
|
|
62
70
|
this.failedVariantEntries = new Map();
|
|
63
71
|
}
|
|
@@ -75,8 +83,8 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
75
83
|
const variantIdPath = resolve(
|
|
76
84
|
sanitizePath(this.config.backupDir),
|
|
77
85
|
'mapper',
|
|
78
|
-
sanitizePath(this.
|
|
79
|
-
sanitizePath(this.
|
|
86
|
+
sanitizePath(this.personalizeConfig.dirName),
|
|
87
|
+
sanitizePath(this.personalizeConfig.experiences.dirName),
|
|
80
88
|
'variants-uid-mapping.json',
|
|
81
89
|
);
|
|
82
90
|
|
|
@@ -107,7 +115,12 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
107
115
|
'terms',
|
|
108
116
|
'success.json',
|
|
109
117
|
);
|
|
110
|
-
const marketplaceAppMapperPath = resolve(
|
|
118
|
+
const marketplaceAppMapperPath = resolve(
|
|
119
|
+
sanitizePath(this.config.backupDir),
|
|
120
|
+
'mapper',
|
|
121
|
+
'marketplace_apps',
|
|
122
|
+
'uid-mapping.json',
|
|
123
|
+
);
|
|
111
124
|
const envPath = resolve(sanitizePath(this.config.backupDir), 'environments', 'environments.json');
|
|
112
125
|
// NOTE Read and store list of variant IDs
|
|
113
126
|
this.variantIdList = (fsUtil.readFile(variantIdPath, true) || {}) as Record<string, unknown>;
|
|
@@ -124,7 +137,8 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
124
137
|
this.assetUidMapper = (fsUtil.readFile(assetUidMapperPath, true) || {}) as Record<string, any>;
|
|
125
138
|
this.assetUrlMapper = (fsUtil.readFile(assetUrlMapperPath, true) || {}) as Record<string, any>;
|
|
126
139
|
this.environments = (fsUtil.readFile(envPath, true) || {}) as Record<string, any>;
|
|
127
|
-
|
|
140
|
+
// set the token
|
|
141
|
+
await this.variantInstance.init();
|
|
128
142
|
for (const entriesForVariant of entriesForVariants) {
|
|
129
143
|
await this.importVariantEntries(entriesForVariant);
|
|
130
144
|
}
|
|
@@ -141,9 +155,22 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
141
155
|
const { content_type, locale, entry_uid } = entriesForVariant;
|
|
142
156
|
const ctConfig = this.config.modules['content-types'];
|
|
143
157
|
const contentType: ContentTypeStruct = JSON.parse(
|
|
144
|
-
readFileSync(
|
|
158
|
+
readFileSync(
|
|
159
|
+
resolve(
|
|
160
|
+
sanitizePath(this.config.backupDir),
|
|
161
|
+
sanitizePath(ctConfig.dirName),
|
|
162
|
+
`${sanitizePath(content_type)}.json`,
|
|
163
|
+
),
|
|
164
|
+
'utf8',
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
const variantEntryBasePath = join(
|
|
168
|
+
sanitizePath(this.entriesDirPath),
|
|
169
|
+
sanitizePath(content_type),
|
|
170
|
+
sanitizePath(locale),
|
|
171
|
+
sanitizePath(variantEntry.dirName),
|
|
172
|
+
sanitizePath(entry_uid),
|
|
145
173
|
);
|
|
146
|
-
const variantEntryBasePath = join(sanitizePath(this.entriesDirPath), sanitizePath(content_type), sanitizePath(locale), sanitizePath(variantEntry.dirName), sanitizePath(entry_uid));
|
|
147
174
|
const fs = new FsUtility({ basePath: variantEntryBasePath });
|
|
148
175
|
|
|
149
176
|
for (const _ in fs.indexFileContent) {
|
|
@@ -202,7 +229,7 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
202
229
|
log(this.config, error, 'error');
|
|
203
230
|
};
|
|
204
231
|
// NOTE Find new variant Id by old Id
|
|
205
|
-
const
|
|
232
|
+
const variantId = this.variantIdList[variantEntry._variant._uid] as string;
|
|
206
233
|
// NOTE Replace all the relation data UID's
|
|
207
234
|
variantEntry = this.handleVariantEntryRelationalData(contentType, variantEntry);
|
|
208
235
|
const changeSet = this.serializeChangeSet(variantEntry);
|
|
@@ -211,19 +238,19 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
211
238
|
...changeSet,
|
|
212
239
|
};
|
|
213
240
|
|
|
214
|
-
if (
|
|
241
|
+
if (variantId) {
|
|
215
242
|
const promise = this.variantInstance.createVariantEntry(
|
|
216
243
|
createVariantReq,
|
|
217
244
|
{
|
|
218
245
|
locale,
|
|
219
246
|
entry_uid: entryUid,
|
|
220
|
-
variant_id,
|
|
247
|
+
variant_id: variantId,
|
|
221
248
|
content_type_uid: content_type,
|
|
222
249
|
},
|
|
223
250
|
{
|
|
224
251
|
reject: onReject.bind(this),
|
|
225
252
|
resolve: onSuccess.bind(this),
|
|
226
|
-
variantUid:
|
|
253
|
+
variantUid: variantId,
|
|
227
254
|
log: log,
|
|
228
255
|
},
|
|
229
256
|
);
|
|
@@ -341,7 +368,7 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
341
368
|
* @param variantEntry - The entry variant to update.
|
|
342
369
|
*/
|
|
343
370
|
updateFileFields(variantEntry: VariantEntryStruct) {
|
|
344
|
-
const setValue = (currentObj: VariantEntryStruct, keys:
|
|
371
|
+
const setValue = (currentObj: VariantEntryStruct, keys: string[]) => {
|
|
345
372
|
if (!currentObj || keys.length === 0) return;
|
|
346
373
|
|
|
347
374
|
const [firstKey, ...restKeys] = keys;
|
|
@@ -353,7 +380,14 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
353
380
|
} else if (currentObj && typeof currentObj === 'object') {
|
|
354
381
|
if (firstKey in currentObj) {
|
|
355
382
|
if (keys.length === 1) {
|
|
356
|
-
|
|
383
|
+
// Check if the current property is already an object with uid and filename
|
|
384
|
+
const existingValue = currentObj[firstKey];
|
|
385
|
+
|
|
386
|
+
if (existingValue && typeof existingValue === 'object' && existingValue.uid) {
|
|
387
|
+
currentObj[firstKey] = { uid: existingValue.uid, filename: 'dummy.jpeg' };
|
|
388
|
+
} else {
|
|
389
|
+
currentObj[firstKey] = { uid: currentObj[firstKey], filename: 'dummy.jpeg' };
|
|
390
|
+
}
|
|
357
391
|
} else {
|
|
358
392
|
setValue(currentObj[firstKey], restKeys);
|
|
359
393
|
}
|
|
@@ -361,13 +395,12 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
361
395
|
}
|
|
362
396
|
};
|
|
363
397
|
|
|
364
|
-
const pathsToUpdate =
|
|
365
|
-
|
|
366
|
-
|
|
398
|
+
const pathsToUpdate =
|
|
399
|
+
variantEntry?._metadata?.references
|
|
400
|
+
?.filter((ref: any) => ref._content_type_uid === 'sys_assets')
|
|
401
|
+
.map((ref: any) => ref.path) || [];
|
|
367
402
|
|
|
368
|
-
|
|
369
|
-
pathsToUpdate.forEach((path: string) => setValue(variantEntry, path.split('.')));
|
|
370
|
-
}
|
|
403
|
+
pathsToUpdate.forEach((path: string) => setValue(variantEntry, path.split('.')));
|
|
371
404
|
}
|
|
372
405
|
|
|
373
406
|
/**
|
|
@@ -379,24 +412,25 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
379
412
|
*/
|
|
380
413
|
async publishVariantEntries(batch: VariantEntryStruct[], entryUid: string, content_type: string) {
|
|
381
414
|
const allPromise = [];
|
|
415
|
+
log(
|
|
416
|
+
this.config,
|
|
417
|
+
`Publishing variant entries for entry uid '${entryUid}' of Content Type '${content_type}'`,
|
|
418
|
+
'info',
|
|
419
|
+
);
|
|
382
420
|
for (let [, variantEntry] of entries(batch)) {
|
|
383
|
-
const
|
|
384
|
-
const oldVariantUid = variantEntry.
|
|
421
|
+
const variantEntryUID = variantEntry.uid;
|
|
422
|
+
const oldVariantUid = variantEntry._variant._uid || '';
|
|
385
423
|
const newVariantUid = this.variantIdList[oldVariantUid] as string;
|
|
386
424
|
|
|
387
425
|
if (!newVariantUid) {
|
|
388
|
-
log(
|
|
389
|
-
this.config,
|
|
390
|
-
`${this.messages.VARIANT_ID_NOT_FOUND}. Skipping entry variant publish for ${variantUid}`,
|
|
391
|
-
'info',
|
|
392
|
-
);
|
|
426
|
+
log(this.config, `${this.messages.VARIANT_ID_NOT_FOUND}. Skipping entry variant publish`, 'info');
|
|
393
427
|
continue;
|
|
394
428
|
}
|
|
395
429
|
|
|
396
|
-
if (this.failedVariantEntries.has(
|
|
430
|
+
if (this.failedVariantEntries.has(variantEntryUID)) {
|
|
397
431
|
log(
|
|
398
432
|
this.config,
|
|
399
|
-
`${this.messages.VARIANT_UID_NOT_FOUND}. Skipping entry variant publish for ${
|
|
433
|
+
`${this.messages.VARIANT_UID_NOT_FOUND}. Skipping entry variant publish for ${variantEntryUID}`,
|
|
400
434
|
'info',
|
|
401
435
|
);
|
|
402
436
|
continue;
|
|
@@ -423,11 +457,9 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
423
457
|
entry: {
|
|
424
458
|
environments,
|
|
425
459
|
locales,
|
|
426
|
-
publish_with_base_entry: false,
|
|
427
460
|
variants: [{ uid: newVariantUid, version: 1 }],
|
|
428
461
|
},
|
|
429
462
|
locale: variantEntry.locale,
|
|
430
|
-
version: 1,
|
|
431
463
|
};
|
|
432
464
|
|
|
433
465
|
const promise = this.variantInstance.publishVariantEntry(
|
|
@@ -440,13 +472,14 @@ export default class VariantEntries extends VariantAdapter<VariantHttpClient<Imp
|
|
|
440
472
|
reject: onReject.bind(this),
|
|
441
473
|
resolve: onSuccess.bind(this),
|
|
442
474
|
log: log,
|
|
443
|
-
variantUid,
|
|
475
|
+
variantUid: newVariantUid,
|
|
444
476
|
},
|
|
445
477
|
);
|
|
446
478
|
|
|
447
479
|
allPromise.push(promise);
|
|
448
480
|
}
|
|
449
481
|
await Promise.allSettled(allPromise);
|
|
482
|
+
log(this.config, `Published variant entries for entry uid '${entryUid}' of Content Type '${content_type}'`, 'info');
|
|
450
483
|
}
|
|
451
484
|
|
|
452
485
|
/**
|
package/src/messages/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ const expImportMsg = {
|
|
|
23
23
|
UPDATING_CT_IN_EXP: 'Updating content types in experiences...',
|
|
24
24
|
UPDATED_CT_IN_EXP: 'Successfully updated content types in experiences!',
|
|
25
25
|
VALIDATE_VARIANT_AND_VARIANT_GRP: 'Validating variant group and variants creation...',
|
|
26
|
-
|
|
26
|
+
PERSONALIZE_JOB_FAILURE: 'Something went wrong! Failed to fetch some variant and variant groups.',
|
|
27
27
|
};
|
|
28
28
|
|
|
29
29
|
const messages: typeof errors & typeof commonMsg & typeof migrationMsg & typeof variantEntry & typeof expImportMsg = {
|
|
@@ -50,7 +50,8 @@ function $t(msg: string, args: Record<string, string>): string {
|
|
|
50
50
|
|
|
51
51
|
for (const key of Object.keys(args)) {
|
|
52
52
|
const escapedKey = key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
53
|
-
|
|
53
|
+
const placeholder = `{${escapedKey}}`;
|
|
54
|
+
msg = msg.split(placeholder).join(args[key]);
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
return msg;
|
|
@@ -20,7 +20,7 @@ export type Modules =
|
|
|
20
20
|
| 'labels'
|
|
21
21
|
| 'marketplace-apps'
|
|
22
22
|
| 'taxonomies'
|
|
23
|
-
| '
|
|
23
|
+
| 'personalize';
|
|
24
24
|
|
|
25
25
|
export type branch = {
|
|
26
26
|
uid: string;
|
|
@@ -155,7 +155,7 @@ export interface DefaultConfig {
|
|
|
155
155
|
include_publish_details: boolean;
|
|
156
156
|
} & AnyProperty;
|
|
157
157
|
} & AnyProperty;
|
|
158
|
-
|
|
158
|
+
personalize: {
|
|
159
159
|
dirName: string;
|
|
160
160
|
baseURL: Record<string, string>;
|
|
161
161
|
} & AnyProperty;
|
|
@@ -269,7 +269,7 @@ export interface ExportConfig extends DefaultConfig {
|
|
|
269
269
|
region: any;
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
export interface
|
|
272
|
+
export interface PersonalizeConfig {
|
|
273
273
|
dirName: string;
|
|
274
274
|
baseURL: Record<string, string>;
|
|
275
275
|
}
|
|
@@ -130,6 +130,18 @@ export type ExperienceStruct = {
|
|
|
130
130
|
content_types?: string[];
|
|
131
131
|
} & AnyProperty;
|
|
132
132
|
|
|
133
|
+
export interface CreateExperienceVersionInput {
|
|
134
|
+
name: string;
|
|
135
|
+
__type: string;
|
|
136
|
+
description: string;
|
|
137
|
+
targeting?: ExpTargeting;
|
|
138
|
+
variations: ExpVariations[];
|
|
139
|
+
variationSplit?: string;
|
|
140
|
+
metrics?: ExpMetric[];
|
|
141
|
+
status: string;
|
|
142
|
+
metadata?: object;
|
|
143
|
+
variants: Array<ExpVariations>;
|
|
144
|
+
}
|
|
133
145
|
export interface CreateExperienceInput {
|
|
134
146
|
name: string;
|
|
135
147
|
__type: string;
|
|
@@ -140,6 +152,7 @@ export interface CreateExperienceInput {
|
|
|
140
152
|
metrics?: ExpMetric[];
|
|
141
153
|
status: string;
|
|
142
154
|
metadata?: object;
|
|
155
|
+
variants?: Array<ExpVariations>;
|
|
143
156
|
}
|
|
144
157
|
|
|
145
158
|
export interface UpdateExperienceInput {
|
|
@@ -193,5 +206,5 @@ export interface Personalization<T> extends AdapterHelperInterface<T, HttpClient
|
|
|
193
206
|
|
|
194
207
|
updateCTsInExperience(experience: UpdateExperienceInput, experienceUid: string): Promise<CMSExperienceStruct | void>;
|
|
195
208
|
|
|
196
|
-
handleVariantAPIRes(res: any): VariantAPIRes
|
|
209
|
+
handleVariantAPIRes(res: any): Promise<VariantAPIRes>;
|
|
197
210
|
}
|
|
@@ -42,6 +42,8 @@ export type VariantOptions = VariantsOption & {
|
|
|
42
42
|
};
|
|
43
43
|
|
|
44
44
|
export interface VariantInterface<T, ApiClient> extends AdapterHelperInterface<T, ApiClient> {
|
|
45
|
+
init(): Promise<void>;
|
|
46
|
+
|
|
45
47
|
variantEntry(options: VariantOptions): Promise<{ entry: Record<string, any> }>;
|
|
46
48
|
|
|
47
49
|
variantEntries(options: VariantsOption): Promise<{ entries?: Record<string, any>[] | unknown[] } | void>;
|
|
@@ -52,5 +54,5 @@ export interface VariantInterface<T, ApiClient> extends AdapterHelperInterface<T
|
|
|
52
54
|
apiParams: Record<string, any>,
|
|
53
55
|
): Promise<VariantEntryStruct | string | void>;
|
|
54
56
|
|
|
55
|
-
handleVariantAPIRes(res: APIResponse): VariantEntryStruct | { entries: VariantEntryStruct[]; count: number } | string
|
|
57
|
+
handleVariantAPIRes(res: APIResponse): Promise<VariantEntryStruct | { entries: VariantEntryStruct[]; count: number } | string>;
|
|
56
58
|
}
|
|
@@ -3,11 +3,11 @@ import { AnyProperty } from './utils';
|
|
|
3
3
|
export type VariantEntryStruct = {
|
|
4
4
|
uid: string;
|
|
5
5
|
title: string;
|
|
6
|
-
variant_id: string;
|
|
7
6
|
locale: string;
|
|
8
7
|
_version: number;
|
|
9
8
|
_variant: {
|
|
10
|
-
|
|
9
|
+
_uid: string;
|
|
10
|
+
_instance_uid: string;
|
|
11
11
|
_change_set: string[];
|
|
12
12
|
_base_entry_version: number;
|
|
13
13
|
};
|
|
@@ -50,7 +50,6 @@ export type PublishVariantEntryDto = {
|
|
|
50
50
|
entry: {
|
|
51
51
|
environments: string[];
|
|
52
52
|
locales: string[];
|
|
53
|
-
publish_with_base_entry: boolean;
|
|
54
53
|
variants: {
|
|
55
54
|
uid: string;
|
|
56
55
|
version?: number;
|
|
@@ -12,8 +12,8 @@ export const lookUpAttributes = (attributeRules: Record<string, any>[], attribut
|
|
|
12
12
|
// Check if attribute reference exists in attributesUid
|
|
13
13
|
const attributeRef = rule.attribute?.ref;
|
|
14
14
|
const attributeType = rule.attribute['__type'];
|
|
15
|
-
// check if type is
|
|
16
|
-
if (attributeType === '
|
|
15
|
+
// check if type is CustomAttributeReference
|
|
16
|
+
if (attributeType === 'CustomAttributeReference') {
|
|
17
17
|
if (attributeRef && attributesUid.hasOwnProperty(attributeRef) && attributesUid[attributeRef]) {
|
|
18
18
|
rule.attribute.ref = attributesUid[attributeRef];
|
|
19
19
|
} else {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CreateExperienceInput } from '../types';
|
|
1
|
+
import { CreateExperienceInput, CreateExperienceVersionInput } from '../types';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* function for substituting an old audience UID with a new one or deleting the audience information if it does not exist
|
|
@@ -37,10 +37,20 @@ export const lookUpAudiences = (
|
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
|
+
} else if (experience.variants) {
|
|
41
|
+
for (let index = experience.variants.length - 1; index >= 0; index--) {
|
|
42
|
+
const expVariations = experience.variants[index];
|
|
43
|
+
if (expVariations['__type'] === 'SegmentedVariant' && expVariations?.audiences?.length) {
|
|
44
|
+
updateAudiences(expVariations.audiences, audiencesUid);
|
|
45
|
+
if (!expVariations.audiences.length) {
|
|
46
|
+
experience.variants.splice(index, 1);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
40
50
|
}
|
|
41
51
|
|
|
42
|
-
// Update targeting audiences
|
|
43
52
|
if (experience?.targeting?.hasOwnProperty('audience') && experience?.targeting?.audience?.audiences?.length) {
|
|
53
|
+
// Update targeting audiences
|
|
44
54
|
updateAudiences(experience.targeting.audience.audiences, audiencesUid);
|
|
45
55
|
if (!experience.targeting.audience.audiences.length) {
|
|
46
56
|
experience.targeting = {};
|
|
@@ -9,18 +9,18 @@ export function formatErrors(errors: any): string {
|
|
|
9
9
|
for (const errorKey in errors) {
|
|
10
10
|
const errorValue = errors[errorKey];
|
|
11
11
|
if (Array.isArray(errorValue)) {
|
|
12
|
-
errorMessages.push(...errorValue.map((error: any) => formatError(error)));
|
|
12
|
+
errorMessages.push(...errorValue.map((error: any) => formatError(errorKey, error)));
|
|
13
13
|
} else {
|
|
14
|
-
errorMessages.push(formatError(errorValue));
|
|
14
|
+
errorMessages.push(formatError(errorKey, errorValue));
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
return errorMessages.join(' ');
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
function formatError(error: any): string {
|
|
22
|
-
if (typeof error === 'object') {
|
|
23
|
-
return Object.values(error).join(' ')
|
|
21
|
+
function formatError(errorKey: string, error: any): string {
|
|
22
|
+
if (typeof error === 'object' && error !== null) {
|
|
23
|
+
return `${errorKey}: ${Object.values(error).join(' ')}`;
|
|
24
24
|
}
|
|
25
|
-
return
|
|
25
|
+
return `${errorKey}: ${error}`;
|
|
26
26
|
}
|
package/src/utils/logger.ts
CHANGED
|
@@ -51,9 +51,9 @@ let errorLogger: winston.Logger;
|
|
|
51
51
|
let successTransport;
|
|
52
52
|
let errorTransport;
|
|
53
53
|
|
|
54
|
-
function init(_logPath: string) {
|
|
54
|
+
function init(_logPath: string, module: string) {
|
|
55
55
|
if (!logger || !errorLogger) {
|
|
56
|
-
const logsDir = path.resolve(sanitizePath(_logPath), 'logs',
|
|
56
|
+
const logsDir = path.resolve(sanitizePath(_logPath), 'logs', sanitizePath(module));
|
|
57
57
|
// Create dir if doesn't already exist
|
|
58
58
|
mkdirp.sync(logsDir);
|
|
59
59
|
|
|
@@ -131,11 +131,12 @@ function init(_logPath: string) {
|
|
|
131
131
|
export const log = (config: ExportConfig | ImportConfig, message: any, type: 'info' | 'error' | 'success') => {
|
|
132
132
|
const logsPath = config.data;
|
|
133
133
|
// ignoring the type argument, as we are not using it to create a logfile anymore
|
|
134
|
+
const module = (config as ImportConfig)['backupDir'] ? 'import' : 'export';
|
|
134
135
|
if (type !== 'error') {
|
|
135
136
|
// removed type argument from init method
|
|
136
|
-
init(logsPath).log(message);
|
|
137
|
+
init(logsPath, module).log(message);
|
|
137
138
|
} else {
|
|
138
|
-
init(logsPath).error(message);
|
|
139
|
+
init(logsPath, module).error(message);
|
|
139
140
|
}
|
|
140
141
|
};
|
|
141
142
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AdapterHelper } from './adapter-helper';
|
|
2
|
-
import { HttpClient } from '@contentstack/cli-utilities';
|
|
2
|
+
import { HttpClient, authenticationHandler } from '@contentstack/cli-utilities';
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
5
|
ProjectStruct,
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
APIResponse,
|
|
23
23
|
VariantGroupStruct,
|
|
24
24
|
VariantGroup,
|
|
25
|
+
CreateExperienceVersionInput,
|
|
25
26
|
} from '../types';
|
|
26
27
|
import { formatErrors } from './error-helper';
|
|
27
28
|
|
|
@@ -30,10 +31,27 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
30
31
|
super(options);
|
|
31
32
|
}
|
|
32
33
|
|
|
34
|
+
async init(): Promise<void> {
|
|
35
|
+
await authenticationHandler.getAuthDetails();
|
|
36
|
+
const token = authenticationHandler.accessToken;
|
|
37
|
+
if (authenticationHandler.isOauthEnabled) {
|
|
38
|
+
this.apiClient.headers({ authorization: token });
|
|
39
|
+
if(this.adapterConfig.cmaConfig) {
|
|
40
|
+
this.cmaAPIClient?.headers({ authorization: token });
|
|
41
|
+
}
|
|
42
|
+
} else {
|
|
43
|
+
this.apiClient.headers({ authtoken: token });
|
|
44
|
+
if(this.adapterConfig.cmaConfig) {
|
|
45
|
+
this.cmaAPIClient?.headers({ authtoken: token });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
33
50
|
async projects(options: GetProjectsParams): Promise<ProjectStruct[]> {
|
|
51
|
+
await this.init();
|
|
34
52
|
const getProjectEndPoint = `/projects?connectedStackApiKey=${options.connectedStackApiKey}`;
|
|
35
53
|
const data = await this.apiClient.get(getProjectEndPoint);
|
|
36
|
-
return this.handleVariantAPIRes(data) as ProjectStruct[];
|
|
54
|
+
return (await this.handleVariantAPIRes(data)) as ProjectStruct[];
|
|
37
55
|
}
|
|
38
56
|
|
|
39
57
|
/**
|
|
@@ -48,7 +66,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
48
66
|
*/
|
|
49
67
|
async createProject(project: CreateProjectInput): Promise<ProjectStruct> {
|
|
50
68
|
const data = await this.apiClient.post<ProjectStruct>('/projects', project);
|
|
51
|
-
return this.handleVariantAPIRes(data) as ProjectStruct;
|
|
69
|
+
return (await this.handleVariantAPIRes(data)) as ProjectStruct;
|
|
52
70
|
}
|
|
53
71
|
|
|
54
72
|
/**
|
|
@@ -62,19 +80,48 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
62
80
|
*/
|
|
63
81
|
async createAttribute(attribute: CreateAttributeInput): Promise<AttributeStruct> {
|
|
64
82
|
const data = await this.apiClient.post<AttributeStruct>('/attributes', attribute);
|
|
65
|
-
return this.handleVariantAPIRes(data) as AttributeStruct;
|
|
83
|
+
return (await this.handleVariantAPIRes(data)) as AttributeStruct;
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
async getExperiences(): Promise<ExperienceStruct[]> {
|
|
69
87
|
const getExperiencesEndPoint = `/experiences`;
|
|
70
88
|
const data = await this.apiClient.get(getExperiencesEndPoint);
|
|
71
|
-
return this.handleVariantAPIRes(data) as ExperienceStruct[];
|
|
89
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct[];
|
|
72
90
|
}
|
|
73
91
|
|
|
74
92
|
async getExperience(experienceUid: string): Promise<ExperienceStruct | void> {
|
|
75
93
|
const getExperiencesEndPoint = `/experiences/${experienceUid}`;
|
|
76
94
|
const data = await this.apiClient.get(getExperiencesEndPoint);
|
|
77
|
-
return this.handleVariantAPIRes(data) as ExperienceStruct;
|
|
95
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async getExperienceVersions(experienceUid: string): Promise<ExperienceStruct | void> {
|
|
99
|
+
const getExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions`;
|
|
100
|
+
const data = await this.apiClient.get(getExperiencesVersionsEndPoint);
|
|
101
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async createExperienceVersion(
|
|
105
|
+
experienceUid: string,
|
|
106
|
+
input: CreateExperienceVersionInput,
|
|
107
|
+
): Promise<ExperienceStruct | void> {
|
|
108
|
+
const createExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions`;
|
|
109
|
+
const data = await this.apiClient.post(createExperiencesVersionsEndPoint, input);
|
|
110
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async updateExperienceVersion(
|
|
114
|
+
experienceUid: string,
|
|
115
|
+
versionId: string,
|
|
116
|
+
input: CreateExperienceVersionInput,
|
|
117
|
+
): Promise<ExperienceStruct | void> {
|
|
118
|
+
// loop through input and remove shortId from variant
|
|
119
|
+
if (input?.variants) {
|
|
120
|
+
input.variants = input.variants.map(({ shortUid, ...rest }) => rest);
|
|
121
|
+
}
|
|
122
|
+
const updateExperiencesVersionsEndPoint = `/experiences/${experienceUid}/versions/${versionId}`;
|
|
123
|
+
const data = await this.apiClient.put(updateExperiencesVersionsEndPoint, input);
|
|
124
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct;
|
|
78
125
|
}
|
|
79
126
|
|
|
80
127
|
async getVariantGroup(input: GetVariantGroupInput): Promise<VariantGroupStruct | void> {
|
|
@@ -83,7 +130,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
83
130
|
const data = await this.cmaAPIClient
|
|
84
131
|
.queryParams({ experience_uid: input.experienceUid })
|
|
85
132
|
.get(getVariantGroupEndPoint);
|
|
86
|
-
return this.handleVariantAPIRes(data) as VariantGroupStruct;
|
|
133
|
+
return (await this.handleVariantAPIRes(data)) as VariantGroupStruct;
|
|
87
134
|
}
|
|
88
135
|
}
|
|
89
136
|
|
|
@@ -91,28 +138,28 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
91
138
|
if (this.cmaAPIClient) {
|
|
92
139
|
const updateVariantGroupEndPoint = `/variant_groups/${input.uid}`;
|
|
93
140
|
const data = await this.cmaAPIClient.put(updateVariantGroupEndPoint, input);
|
|
94
|
-
return this.handleVariantAPIRes(data) as VariantGroup;
|
|
141
|
+
return (await this.handleVariantAPIRes(data)) as VariantGroup;
|
|
95
142
|
}
|
|
96
143
|
}
|
|
97
144
|
|
|
98
145
|
async getEvents(): Promise<EventStruct[] | void> {
|
|
99
146
|
const data = await this.apiClient.get<EventStruct>('/events');
|
|
100
|
-
return this.handleVariantAPIRes(data) as EventStruct[];
|
|
147
|
+
return (await this.handleVariantAPIRes(data)) as EventStruct[];
|
|
101
148
|
}
|
|
102
149
|
|
|
103
150
|
async createEvents(event: CreateEventInput): Promise<void | EventStruct> {
|
|
104
151
|
const data = await this.apiClient.post<EventStruct>('/events', event);
|
|
105
|
-
return this.handleVariantAPIRes(data) as EventStruct;
|
|
152
|
+
return (await this.handleVariantAPIRes(data)) as EventStruct;
|
|
106
153
|
}
|
|
107
154
|
|
|
108
155
|
async getAudiences(): Promise<AudienceStruct[] | void> {
|
|
109
156
|
const data = await this.apiClient.get<AudienceStruct>('/audiences');
|
|
110
|
-
return this.handleVariantAPIRes(data) as AudienceStruct[];
|
|
157
|
+
return (await this.handleVariantAPIRes(data)) as AudienceStruct[];
|
|
111
158
|
}
|
|
112
159
|
|
|
113
160
|
async getAttributes(): Promise<AttributeStruct[] | void> {
|
|
114
161
|
const data = await this.apiClient.get<AttributeStruct>('/attributes');
|
|
115
|
-
return this.handleVariantAPIRes(data) as AttributeStruct[];
|
|
162
|
+
return (await this.handleVariantAPIRes(data)) as AttributeStruct[];
|
|
116
163
|
}
|
|
117
164
|
|
|
118
165
|
/**
|
|
@@ -125,7 +172,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
125
172
|
*/
|
|
126
173
|
async createAudience(audience: CreateAudienceInput): Promise<void | AudienceStruct> {
|
|
127
174
|
const data = await this.apiClient.post<AudienceStruct>('/audiences', audience);
|
|
128
|
-
return this.handleVariantAPIRes(data) as AudienceStruct;
|
|
175
|
+
return (await this.handleVariantAPIRes(data)) as AudienceStruct;
|
|
129
176
|
}
|
|
130
177
|
|
|
131
178
|
/**
|
|
@@ -138,7 +185,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
138
185
|
*/
|
|
139
186
|
async createExperience(experience: CreateExperienceInput): Promise<void | ExperienceStruct> {
|
|
140
187
|
const data = await this.apiClient.post<ExperienceStruct>('/experiences', experience);
|
|
141
|
-
return this.handleVariantAPIRes(data) as ExperienceStruct;
|
|
188
|
+
return (await this.handleVariantAPIRes(data)) as ExperienceStruct;
|
|
142
189
|
}
|
|
143
190
|
|
|
144
191
|
/**
|
|
@@ -152,7 +199,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
152
199
|
): Promise<void | CMSExperienceStruct> {
|
|
153
200
|
const updateCTInExpEndPoint = `/experiences/${experienceUid}/cms-integration/variant-group`;
|
|
154
201
|
const data = await this.apiClient.post<CMSExperienceStruct>(updateCTInExpEndPoint, experience);
|
|
155
|
-
return this.handleVariantAPIRes(data) as CMSExperienceStruct;
|
|
202
|
+
return (await this.handleVariantAPIRes(data)) as CMSExperienceStruct;
|
|
156
203
|
}
|
|
157
204
|
|
|
158
205
|
/**
|
|
@@ -163,7 +210,7 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
163
210
|
async getCTsFromExperience(experienceUid: string): Promise<void | CMSExperienceStruct> {
|
|
164
211
|
const getCTFromExpEndPoint = `/experiences/${experienceUid}/cms-integration/variant-group`;
|
|
165
212
|
const data = await this.apiClient.get<CMSExperienceStruct>(getCTFromExpEndPoint);
|
|
166
|
-
return this.handleVariantAPIRes(data) as CMSExperienceStruct;
|
|
213
|
+
return (await this.handleVariantAPIRes(data)) as CMSExperienceStruct;
|
|
167
214
|
}
|
|
168
215
|
|
|
169
216
|
/**
|
|
@@ -172,16 +219,22 @@ export class PersonalizationAdapter<T> extends AdapterHelper<T, HttpClient> impl
|
|
|
172
219
|
* @returns The variant API response data.
|
|
173
220
|
* @throws If the API response status is not within the success range, an error message is thrown.
|
|
174
221
|
*/
|
|
175
|
-
handleVariantAPIRes(res: APIResponse): VariantAPIRes {
|
|
222
|
+
async handleVariantAPIRes(res: APIResponse): Promise<VariantAPIRes> {
|
|
176
223
|
const { status, data } = res;
|
|
177
224
|
|
|
178
225
|
if (status >= 200 && status < 300) {
|
|
179
226
|
return data;
|
|
180
227
|
}
|
|
181
228
|
|
|
229
|
+
// Refresh the access token if it has expired
|
|
230
|
+
await authenticationHandler.refreshAccessToken(res);
|
|
231
|
+
|
|
182
232
|
const errorMsg = data?.errors
|
|
183
233
|
? formatErrors(data.errors)
|
|
184
|
-
: data?.
|
|
234
|
+
: data?.error ||
|
|
235
|
+
data?.error_message ||
|
|
236
|
+
data?.message ||
|
|
237
|
+
'Something went wrong while processing variant entries request!';
|
|
185
238
|
|
|
186
239
|
throw errorMsg;
|
|
187
240
|
}
|