@kameleoon/javascript-sdk-core 5.16.0 → 5.17.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/CHANGELOG.md +16 -1
- package/dist/clientConfiguration/clientConfiguration.d.ts +4 -1
- package/dist/clientConfiguration/constants.d.ts +2 -3
- package/dist/clientConfiguration/types.d.ts +5 -0
- package/dist/javascript-sdk-core-browser.cjs.js +225 -96
- package/dist/javascript-sdk-core-browser.cjs.js.map +1 -1
- package/dist/javascript-sdk-core-browser.es.js +225 -96
- package/dist/javascript-sdk-core-browser.es.js.map +1 -1
- package/dist/javascript-sdk-core.cjs.js +225 -96
- package/dist/javascript-sdk-core.cjs.js.map +1 -1
- package/dist/javascript-sdk-core.es.js +225 -96
- package/dist/javascript-sdk-core.es.js.map +1 -1
- package/dist/kameleoonClient.d.ts +2 -0
- package/dist/kameleoonData/conversion.d.ts +12 -0
- package/dist/kameleoonData/customData.d.ts +20 -4
- package/dist/kameleoonData/dataManager.d.ts +3 -2
- package/dist/kameleoonData/dataProcessor.d.ts +2 -2
- package/dist/kameleoonData/types.d.ts +5 -3
- package/dist/requester/constants.d.ts +1 -1
- package/dist/requester/urlProvider.d.ts +1 -0
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/types.d.ts +13 -5
- package/dist/variationConfiguration/types.d.ts +2 -0
- package/dist/variationConfiguration/variationConfiguration.d.ts +1 -1
- package/package.json +1 -1
|
@@ -218,10 +218,17 @@ class KameleoonError extends Error {
|
|
|
218
218
|
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
219
219
|
break;
|
|
220
220
|
case KameleoonException.FeatureFlagVariationNotFound:
|
|
221
|
-
case KameleoonException.FeatureFlagEnvironmentDisabled:
|
|
222
221
|
case KameleoonException.FeatureFlagVariableNotFound:
|
|
223
222
|
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
224
223
|
break;
|
|
224
|
+
case KameleoonException.FeatureFlagEnvironmentDisabled:
|
|
225
|
+
if (thirdParam !== undefined) {
|
|
226
|
+
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
this.message = secondParam;
|
|
230
|
+
}
|
|
231
|
+
break;
|
|
225
232
|
case KameleoonException.StorageWrite:
|
|
226
233
|
case KameleoonException.JSONParse:
|
|
227
234
|
this.message = ERROR_MESSAGES[type](secondParam);
|
|
@@ -277,7 +284,7 @@ var RequestType;
|
|
|
277
284
|
RequestType["RemoteData"] = "remoteData";
|
|
278
285
|
})(RequestType || (RequestType = {}));
|
|
279
286
|
|
|
280
|
-
const NUMBER_OF_RETRIES =
|
|
287
|
+
const NUMBER_OF_RETRIES = 1;
|
|
281
288
|
var Header;
|
|
282
289
|
(function (Header) {
|
|
283
290
|
Header["UserAgent"] = "User-Agent";
|
|
@@ -856,6 +863,9 @@ class UrlProvider {
|
|
|
856
863
|
const currentDomain = this.domains[UrlType.DataApi];
|
|
857
864
|
this.domains[UrlType.DataApi] = currentDomain.replace(/^[^.]+/, subDomain);
|
|
858
865
|
}
|
|
866
|
+
get dataApiDomain() {
|
|
867
|
+
return this.domains[UrlType.DataApi];
|
|
868
|
+
}
|
|
859
869
|
getClientConfigurationUrl(timeStamp) {
|
|
860
870
|
this.isInitialized();
|
|
861
871
|
const baseUrl = `https://${this.domains[UrlType.ClientConfiguration]}/v3/`;
|
|
@@ -1115,6 +1125,11 @@ var ConsentType;
|
|
|
1115
1125
|
ConsentType["Required"] = "REQUIRED";
|
|
1116
1126
|
ConsentType["NotRequired"] = "NOT_REQUIRED";
|
|
1117
1127
|
})(ConsentType || (ConsentType = {}));
|
|
1128
|
+
var ConsentBlockingBehaviour;
|
|
1129
|
+
(function (ConsentBlockingBehaviour) {
|
|
1130
|
+
ConsentBlockingBehaviour["PartiallyBlocked"] = "PARTIALLY_BLOCK";
|
|
1131
|
+
ConsentBlockingBehaviour["CompletelyBlocked"] = "FULLY_BLOCK";
|
|
1132
|
+
})(ConsentBlockingBehaviour || (ConsentBlockingBehaviour = {}));
|
|
1118
1133
|
|
|
1119
1134
|
class EventManager {
|
|
1120
1135
|
addEventHandler(eventType, callback) {
|
|
@@ -1142,17 +1157,14 @@ var EventType;
|
|
|
1142
1157
|
EventType["ConfigurationUpdate"] = "configurationUpdate";
|
|
1143
1158
|
})(EventType || (EventType = {}));
|
|
1144
1159
|
|
|
1145
|
-
|
|
1146
|
-
configuration: {
|
|
1147
|
-
consentType: ConsentType.NotRequired},
|
|
1148
|
-
});
|
|
1149
|
-
const DEFAULT_CLIENT_CONFIGURATION$1 = {
|
|
1160
|
+
const DEFAULT_DATA_FILE_CONFIGURATION = {
|
|
1150
1161
|
customData: [],
|
|
1151
1162
|
featureFlags: [],
|
|
1152
1163
|
configuration: {
|
|
1153
1164
|
realTimeUpdate: false,
|
|
1154
1165
|
consentType: ConsentType.NotRequired,
|
|
1155
1166
|
dataApiDomain: 'data.kameleoon.io',
|
|
1167
|
+
consentOptOutBehavior: ConsentBlockingBehaviour.PartiallyBlocked,
|
|
1156
1168
|
},
|
|
1157
1169
|
};
|
|
1158
1170
|
|
|
@@ -1176,7 +1188,7 @@ class ClientConfiguration {
|
|
|
1176
1188
|
constructor({ updateInterval, urlProvider, storage, requester, dataManager, eventSource, externalVisitorCodeManager, eventManager, externalPackageInfo, defaultDataFile, }) {
|
|
1177
1189
|
this.updateConfigurationIntervalId = null;
|
|
1178
1190
|
this.updateType = UpdateType.Polling;
|
|
1179
|
-
this.configurationData =
|
|
1191
|
+
this.configurationData = DEFAULT_DATA_FILE_CONFIGURATION;
|
|
1180
1192
|
this.featureFlagsData = new Map();
|
|
1181
1193
|
this.isTargetedDeliveryRule = null;
|
|
1182
1194
|
this.segmentsData = null;
|
|
@@ -1185,6 +1197,7 @@ class ClientConfiguration {
|
|
|
1185
1197
|
this.mappedRules = null;
|
|
1186
1198
|
this.mappedExperiments = null;
|
|
1187
1199
|
this.usedDefaultDataFile = false;
|
|
1200
|
+
this.blockingBehaviourMode = ConsentBlockingBehaviour.PartiallyBlocked;
|
|
1188
1201
|
this.CACHE_REVALIDATE_PERIOD = 90 * Milliseconds.Minute;
|
|
1189
1202
|
this.urlProvider = urlProvider;
|
|
1190
1203
|
this.requester = requester;
|
|
@@ -1359,6 +1372,9 @@ class ClientConfiguration {
|
|
|
1359
1372
|
get isConsentRequired() {
|
|
1360
1373
|
return this.configuration.consentType === ConsentType.Required;
|
|
1361
1374
|
}
|
|
1375
|
+
get consentBlockingBehaviour() {
|
|
1376
|
+
return this.blockingBehaviourMode;
|
|
1377
|
+
}
|
|
1362
1378
|
get hasAnyTargetedDeliveryRule() {
|
|
1363
1379
|
if (this.isTargetedDeliveryRule !== null) {
|
|
1364
1380
|
return this.isTargetedDeliveryRule;
|
|
@@ -1487,6 +1503,7 @@ class ClientConfiguration {
|
|
|
1487
1503
|
KameleoonLogger.info `Configuration update type was toggled to ${UpdateType[updateType]}`;
|
|
1488
1504
|
yield this.initialize();
|
|
1489
1505
|
}
|
|
1506
|
+
this.blockingBehaviourMode = this.consentBlockingBehaviourFromStr(clientConfigurationData.configuration.consentOptOutBehavior);
|
|
1490
1507
|
return buildExports.Ok(toggleUpdateType);
|
|
1491
1508
|
});
|
|
1492
1509
|
}
|
|
@@ -1593,6 +1610,14 @@ class ClientConfiguration {
|
|
|
1593
1610
|
this.visitorCodeManager.consentRequired =
|
|
1594
1611
|
this.isConsentRequired && !this.hasAnyTargetedDeliveryRule;
|
|
1595
1612
|
}
|
|
1613
|
+
consentBlockingBehaviourFromStr(str) {
|
|
1614
|
+
if (str === ConsentBlockingBehaviour.PartiallyBlocked ||
|
|
1615
|
+
str === ConsentBlockingBehaviour.CompletelyBlocked) {
|
|
1616
|
+
return str;
|
|
1617
|
+
}
|
|
1618
|
+
KameleoonLogger.error(`Unexpected consent blocking type '${str}'`);
|
|
1619
|
+
return ConsentBlockingBehaviour.PartiallyBlocked;
|
|
1620
|
+
}
|
|
1596
1621
|
}
|
|
1597
1622
|
|
|
1598
1623
|
function constructTypeMap(indexMap) {
|
|
@@ -2271,11 +2296,11 @@ let CustomData$1 = class CustomData {
|
|
|
2271
2296
|
const isNumber = typeof first === 'number';
|
|
2272
2297
|
const isBoolean = typeof second === 'boolean';
|
|
2273
2298
|
if (isNumber) {
|
|
2274
|
-
this.
|
|
2299
|
+
this._index = first;
|
|
2275
2300
|
}
|
|
2276
2301
|
else {
|
|
2277
|
-
this.
|
|
2278
|
-
this.
|
|
2302
|
+
this._name = first;
|
|
2303
|
+
this._index = CustomData.UNDEFINED_INDEX;
|
|
2279
2304
|
}
|
|
2280
2305
|
this.overwrite = isBoolean ? second : true;
|
|
2281
2306
|
this.value = isBoolean
|
|
@@ -2286,7 +2311,7 @@ let CustomData$1 = class CustomData {
|
|
|
2286
2311
|
// --- Note ---
|
|
2287
2312
|
// If SDK is used in vanilla JS codebase, then you're also able to create an instance
|
|
2288
2313
|
// with no required data, we don't want send anything to tracking in that case
|
|
2289
|
-
if (typeof this.
|
|
2314
|
+
if (typeof this._index !== 'number') {
|
|
2290
2315
|
return '';
|
|
2291
2316
|
}
|
|
2292
2317
|
const uniqueValues = [...new Set(this.value)];
|
|
@@ -2303,7 +2328,7 @@ let CustomData$1 = class CustomData {
|
|
|
2303
2328
|
}
|
|
2304
2329
|
return (UrlEventType.CustomData +
|
|
2305
2330
|
UrlParameter.Index +
|
|
2306
|
-
this.
|
|
2331
|
+
this._index +
|
|
2307
2332
|
UrlParameter.ValuesCountMap +
|
|
2308
2333
|
encodeURIComponent(JSON.stringify(resultValue)) +
|
|
2309
2334
|
UrlParameter.Overwrite +
|
|
@@ -2311,7 +2336,7 @@ let CustomData$1 = class CustomData {
|
|
|
2311
2336
|
identifierParameter);
|
|
2312
2337
|
}
|
|
2313
2338
|
get data() {
|
|
2314
|
-
return Object.assign(Object.assign({ index: this.
|
|
2339
|
+
return Object.assign(Object.assign({ index: this._index }, (this._name !== undefined ? { name: this._name } : {})), { value: this.value, type: KameleoonData.CustomData, isIdentifier: this.isIdentifier, status: this.status, overwrite: this.overwrite });
|
|
2315
2340
|
}
|
|
2316
2341
|
get status() {
|
|
2317
2342
|
if (this._isMappingIdentifier) {
|
|
@@ -2330,7 +2355,7 @@ let CustomData$1 = class CustomData {
|
|
|
2330
2355
|
let customData;
|
|
2331
2356
|
if (name) {
|
|
2332
2357
|
customData = new CustomData(name, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
|
|
2333
|
-
customData.
|
|
2358
|
+
customData.index = index;
|
|
2334
2359
|
}
|
|
2335
2360
|
else {
|
|
2336
2361
|
customData = new CustomData(index, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
|
|
@@ -2367,13 +2392,35 @@ let CustomData$1 = class CustomData {
|
|
|
2367
2392
|
}
|
|
2368
2393
|
/**
|
|
2369
2394
|
* @private
|
|
2370
|
-
* @method
|
|
2395
|
+
* @method index - an internal setter for setting index of custom data
|
|
2371
2396
|
* @param {number} value - an index value
|
|
2372
2397
|
* */
|
|
2373
|
-
set
|
|
2374
|
-
this.
|
|
2398
|
+
set index(value) {
|
|
2399
|
+
this._index = value;
|
|
2400
|
+
}
|
|
2401
|
+
/**
|
|
2402
|
+
* @private
|
|
2403
|
+
* @method index - an internal getter for index of custom data
|
|
2404
|
+
* */
|
|
2405
|
+
get index() {
|
|
2406
|
+
return this._index;
|
|
2407
|
+
}
|
|
2408
|
+
/**
|
|
2409
|
+
* @private
|
|
2410
|
+
* @method name - an internal getter for a name of custom data
|
|
2411
|
+
* */
|
|
2412
|
+
get name() {
|
|
2413
|
+
return this._name;
|
|
2414
|
+
}
|
|
2415
|
+
/**
|
|
2416
|
+
* @private
|
|
2417
|
+
* @method name - an internal getter for a name of custom data
|
|
2418
|
+
* */
|
|
2419
|
+
get values() {
|
|
2420
|
+
return this.value;
|
|
2375
2421
|
}
|
|
2376
2422
|
};
|
|
2423
|
+
CustomData$1.UNDEFINED_INDEX = -1;
|
|
2377
2424
|
|
|
2378
2425
|
/**
|
|
2379
2426
|
* @class
|
|
@@ -2389,7 +2436,7 @@ let Conversion$1 = class Conversion {
|
|
|
2389
2436
|
this.negative = negative;
|
|
2390
2437
|
this.status = TrackingStatus.Unsent;
|
|
2391
2438
|
this.id = Math.floor(Math.random() * 1000000);
|
|
2392
|
-
this.
|
|
2439
|
+
this._metadata = metadata;
|
|
2393
2440
|
}
|
|
2394
2441
|
set _id(id) {
|
|
2395
2442
|
this.id = id;
|
|
@@ -2410,6 +2457,21 @@ let Conversion$1 = class Conversion {
|
|
|
2410
2457
|
? UrlParameter.Metadata + this._encodeMetadata()
|
|
2411
2458
|
: ''));
|
|
2412
2459
|
}
|
|
2460
|
+
/**
|
|
2461
|
+
* @private
|
|
2462
|
+
* @method metadata - an internal getter for a metadata of conversion
|
|
2463
|
+
* */
|
|
2464
|
+
get _metadata() {
|
|
2465
|
+
return this.metadata;
|
|
2466
|
+
}
|
|
2467
|
+
/**
|
|
2468
|
+
* @private
|
|
2469
|
+
* @method metadata - an internal setter for setting metadata of conversion
|
|
2470
|
+
* @param {number} value - an index value
|
|
2471
|
+
* */
|
|
2472
|
+
set _metadata(value) {
|
|
2473
|
+
this.metadata = value;
|
|
2474
|
+
}
|
|
2413
2475
|
get data() {
|
|
2414
2476
|
var _a;
|
|
2415
2477
|
return {
|
|
@@ -3502,7 +3564,7 @@ class DataProcessor {
|
|
|
3502
3564
|
this.cleanupInterval = cleanupInterval;
|
|
3503
3565
|
this.packageInfo = packageInfo;
|
|
3504
3566
|
}
|
|
3505
|
-
mutUpdateData({ infoData, visitorCode, mutData, dataItem, }) {
|
|
3567
|
+
mutUpdateData({ infoData, visitorCode, mutData, dataItem, extendTtl, }) {
|
|
3506
3568
|
let { visitorReference, data, isReference } = this.dereferenceData(mutData, visitorCode);
|
|
3507
3569
|
if (this.packageInfo.isServer &&
|
|
3508
3570
|
isReference &&
|
|
@@ -3513,9 +3575,12 @@ class DataProcessor {
|
|
|
3513
3575
|
delete mutData[visitorCode];
|
|
3514
3576
|
visitorReference = visitorCode;
|
|
3515
3577
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3578
|
+
let expirationTime;
|
|
3579
|
+
if (extendTtl) {
|
|
3580
|
+
expirationTime = this.cleanupInterval
|
|
3581
|
+
? Date.now() + this.cleanupInterval
|
|
3582
|
+
: 0;
|
|
3583
|
+
}
|
|
3519
3584
|
switch (dataItem.data.type) {
|
|
3520
3585
|
case KameleoonData.CustomData: {
|
|
3521
3586
|
this.updateCustomData({
|
|
@@ -3870,13 +3935,17 @@ class DataProcessor {
|
|
|
3870
3935
|
return closestCleanupTime;
|
|
3871
3936
|
}
|
|
3872
3937
|
updateField({ key, value, data, visitorCode, expirationTime, }) {
|
|
3873
|
-
|
|
3938
|
+
var _a;
|
|
3939
|
+
const existing = data[visitorCode][key];
|
|
3940
|
+
data[visitorCode][key] = Object.assign(Object.assign({}, value), { expirationTime: (_a = expirationTime !== null && expirationTime !== void 0 ? expirationTime : (existing.expirationTime && existing.expirationTime)) !== null && _a !== void 0 ? _a : Date.now() });
|
|
3874
3941
|
}
|
|
3875
3942
|
createField({ key, value, data, visitorCode, expirationTime, }) {
|
|
3876
3943
|
data[visitorCode] = Object.assign(Object.assign({}, data[visitorCode]), { [key]: Object.assign(Object.assign({}, value), { expirationTime }) });
|
|
3877
3944
|
}
|
|
3878
3945
|
updateNestedField({ key, nestedKey, value, data, visitorCode, expirationTime, }) {
|
|
3879
|
-
|
|
3946
|
+
var _a;
|
|
3947
|
+
const existing = data[visitorCode][key][nestedKey];
|
|
3948
|
+
data[visitorCode][key][nestedKey] = Object.assign(Object.assign({}, value), { expirationTime: (_a = expirationTime !== null && expirationTime !== void 0 ? expirationTime : existing === null || existing === void 0 ? void 0 : existing.expirationTime) !== null && _a !== void 0 ? _a : Date.now() });
|
|
3880
3949
|
}
|
|
3881
3950
|
createNestedField({ key, nestedKey, value, data, visitorCode, expirationTime, }) {
|
|
3882
3951
|
var _a;
|
|
@@ -5142,15 +5211,7 @@ var KameleoonStorageKey;
|
|
|
5142
5211
|
KameleoonStorageKey["ForcedExperimentVariation"] = "kameleoonForcedExperimentVariation";
|
|
5143
5212
|
})(KameleoonStorageKey || (KameleoonStorageKey = {}));
|
|
5144
5213
|
const DEFAULT_CLIENT_CONFIGURATION = {
|
|
5145
|
-
data:
|
|
5146
|
-
customData: [],
|
|
5147
|
-
featureFlags: [],
|
|
5148
|
-
configuration: {
|
|
5149
|
-
realTimeUpdate: false,
|
|
5150
|
-
consentType: ConsentType.NotRequired,
|
|
5151
|
-
dataApiDomain: 'data.kameleoon.io',
|
|
5152
|
-
},
|
|
5153
|
-
},
|
|
5214
|
+
data: DEFAULT_DATA_FILE_CONFIGURATION,
|
|
5154
5215
|
lastUpdate: '',
|
|
5155
5216
|
};
|
|
5156
5217
|
// --- Note ---
|
|
@@ -5662,7 +5723,7 @@ class DataManager {
|
|
|
5662
5723
|
return resultData;
|
|
5663
5724
|
}
|
|
5664
5725
|
storeTrackedData(data) {
|
|
5665
|
-
this.storeData(data);
|
|
5726
|
+
this.storeData(data, false);
|
|
5666
5727
|
const infoResult = this.infoStorage.read();
|
|
5667
5728
|
if (!infoResult.ok) {
|
|
5668
5729
|
return;
|
|
@@ -5714,15 +5775,18 @@ class DataManager {
|
|
|
5714
5775
|
targetingData,
|
|
5715
5776
|
visitorCode: firstParameter,
|
|
5716
5777
|
kameleoonData: secondParameter,
|
|
5778
|
+
extendTtl: true,
|
|
5717
5779
|
});
|
|
5718
5780
|
}
|
|
5719
5781
|
else {
|
|
5720
5782
|
for (const [visitorCode, kameleoonData] of Object.entries(firstParameter)) {
|
|
5783
|
+
const extendTtl = typeof secondParameter[0] === 'boolean' ? secondParameter[0] : true;
|
|
5721
5784
|
this.mutUpdateTargetingData({
|
|
5722
5785
|
infoData,
|
|
5723
5786
|
targetingData,
|
|
5724
5787
|
visitorCode,
|
|
5725
5788
|
kameleoonData,
|
|
5789
|
+
extendTtl,
|
|
5726
5790
|
});
|
|
5727
5791
|
}
|
|
5728
5792
|
}
|
|
@@ -5839,8 +5903,10 @@ class DataManager {
|
|
|
5839
5903
|
}
|
|
5840
5904
|
return null;
|
|
5841
5905
|
}
|
|
5842
|
-
mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, }) {
|
|
5906
|
+
mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, extendTtl, }) {
|
|
5907
|
+
var _a, _b, _c;
|
|
5843
5908
|
for (const dataItem of kameleoonData) {
|
|
5909
|
+
// process custom data
|
|
5844
5910
|
if (dataItem.data.type === KameleoonData.CustomData) {
|
|
5845
5911
|
const customDataIsValid = this.processCustomData({
|
|
5846
5912
|
infoData,
|
|
@@ -5852,14 +5918,23 @@ class DataManager {
|
|
|
5852
5918
|
continue;
|
|
5853
5919
|
}
|
|
5854
5920
|
}
|
|
5921
|
+
// process metadata of conversions
|
|
5922
|
+
if (dataItem.data.type === KameleoonData.Conversion) {
|
|
5923
|
+
const conversion = dataItem;
|
|
5924
|
+
if (((_b = (_a = conversion._metadata) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) {
|
|
5925
|
+
conversion._metadata = (_c = conversion._metadata) === null || _c === void 0 ? void 0 : _c.filter((item) => this.trySetCustomDataIndexByName(item));
|
|
5926
|
+
}
|
|
5927
|
+
}
|
|
5855
5928
|
const expirationTime = this.dataProcessor.mutUpdateData({
|
|
5856
5929
|
infoData,
|
|
5857
5930
|
visitorCode,
|
|
5858
5931
|
mutData: targetingData,
|
|
5859
5932
|
dataItem,
|
|
5933
|
+
extendTtl,
|
|
5860
5934
|
});
|
|
5861
5935
|
const nextCleanup = infoData.nextDataCleanup;
|
|
5862
|
-
if (!nextCleanup ||
|
|
5936
|
+
if (!nextCleanup ||
|
|
5937
|
+
(nextCleanup && expirationTime && expirationTime < nextCleanup)) {
|
|
5863
5938
|
infoData.nextDataCleanup = expirationTime;
|
|
5864
5939
|
}
|
|
5865
5940
|
if (dataItem.data.status === TrackingStatus.Unsent) {
|
|
@@ -5891,13 +5966,11 @@ class DataManager {
|
|
|
5891
5966
|
var _a;
|
|
5892
5967
|
const { data } = customData;
|
|
5893
5968
|
const isDataValid = Boolean(data.value.length && data.value[0].length);
|
|
5894
|
-
if (
|
|
5895
|
-
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
data.index = cdIndex;
|
|
5900
|
-
customData._index = cdIndex;
|
|
5969
|
+
if (!this.trySetCustomDataIndexByName(customData)) {
|
|
5970
|
+
return false;
|
|
5971
|
+
}
|
|
5972
|
+
if (data.index == CustomData$1.UNDEFINED_INDEX) {
|
|
5973
|
+
data.index = customData.index;
|
|
5901
5974
|
}
|
|
5902
5975
|
if (this.mappingIdentifierCustomDataIndex === data.index && isDataValid) {
|
|
5903
5976
|
customData._isMappingIdentifier = true;
|
|
@@ -5924,6 +5997,17 @@ class DataManager {
|
|
|
5924
5997
|
}
|
|
5925
5998
|
return true;
|
|
5926
5999
|
}
|
|
6000
|
+
trySetCustomDataIndexByName(customData) {
|
|
6001
|
+
if (customData.index !== CustomData$1.UNDEFINED_INDEX)
|
|
6002
|
+
return true;
|
|
6003
|
+
if (!customData.name)
|
|
6004
|
+
return false;
|
|
6005
|
+
const cdIndex = this.customDataIndexByName.get(customData.name);
|
|
6006
|
+
if (cdIndex == null)
|
|
6007
|
+
return false;
|
|
6008
|
+
customData.index = cdIndex;
|
|
6009
|
+
return true;
|
|
6010
|
+
}
|
|
5927
6011
|
get unsentDataVisitors() {
|
|
5928
6012
|
const infoResult = this.infoStorage.read();
|
|
5929
6013
|
if (!infoResult.ok) {
|
|
@@ -7026,6 +7110,13 @@ class Hasher {
|
|
|
7026
7110
|
}
|
|
7027
7111
|
}
|
|
7028
7112
|
|
|
7113
|
+
var LegalConsent;
|
|
7114
|
+
(function (LegalConsent) {
|
|
7115
|
+
LegalConsent[LegalConsent["Unknown"] = 0] = "Unknown";
|
|
7116
|
+
LegalConsent[LegalConsent["Given"] = 1] = "Given";
|
|
7117
|
+
LegalConsent[LegalConsent["NotGiven"] = 2] = "NotGiven";
|
|
7118
|
+
})(LegalConsent || (LegalConsent = {}));
|
|
7119
|
+
|
|
7029
7120
|
class VariationConfiguration {
|
|
7030
7121
|
constructor(externalStorage, externalStorageForcedExperimentVariations, externalStorageForcedFeatureVariations, visitorCodeManager, clientConfiguration) {
|
|
7031
7122
|
this.storage = externalStorage;
|
|
@@ -7084,9 +7175,12 @@ class VariationConfiguration {
|
|
|
7084
7175
|
}
|
|
7085
7176
|
return buildExports.Ok(featureFlagVariations);
|
|
7086
7177
|
}
|
|
7087
|
-
getVariation({ visitorCode, visitorIdentifier, featureFlag, targetingData, packageInfo, clientConfiguration, dataManager, track = true, withAssignment = false, }) {
|
|
7178
|
+
getVariation({ visitorCode, visitorIdentifier, featureFlag, targetingData, packageInfo, clientConfiguration, dataManager, legalConsent, track = true, withAssignment = false, }) {
|
|
7088
7179
|
KameleoonLogger.debug `CALL: VariationConfiguration.getVariation(visitorCode: ${visitorCode}, visitorIdentifier: ${visitorIdentifier}, featureFlag: ${featureFlag}, targetingData: ${targetingData}, packageInfo: ${packageInfo}, clientConfiguration, dataManager, withAssignment: ${withAssignment})`;
|
|
7089
7180
|
const { rules, featureKey, id: featureFlagId, defaultVariationKey, } = featureFlag;
|
|
7181
|
+
const consent = clientConfiguration.isConsentRequired
|
|
7182
|
+
? legalConsent
|
|
7183
|
+
: LegalConsent.Given;
|
|
7090
7184
|
for (const rule of rules) {
|
|
7091
7185
|
const { segment, experimentId, id, exposition, respoolTime, variationByExposition, } = rule;
|
|
7092
7186
|
const forcedVariationData = this.getForcedExperimentVariation(visitorCode, rule.experimentId);
|
|
@@ -7133,6 +7227,16 @@ class VariationConfiguration {
|
|
|
7133
7227
|
});
|
|
7134
7228
|
KameleoonLogger.debug `Calculated ruleHash: ${ruleHash} for code: ${visitorIdentifier}`;
|
|
7135
7229
|
if (ruleHash <= exposition) {
|
|
7230
|
+
// Checking if the evaluation is blocked due to the consent policy
|
|
7231
|
+
if (consent == LegalConsent.NotGiven &&
|
|
7232
|
+
rule.type == RuleType.EXPERIMENTATION) {
|
|
7233
|
+
const behaviour = clientConfiguration.consentBlockingBehaviour;
|
|
7234
|
+
if (behaviour == ConsentBlockingBehaviour.PartiallyBlocked) {
|
|
7235
|
+
break;
|
|
7236
|
+
}
|
|
7237
|
+
return buildExports.Err(new KameleoonError(KameleoonException.FeatureFlagEnvironmentDisabled, `Evaluation of ${rule} is blocked because consent is not provided for visitor '${visitorCode}'`));
|
|
7238
|
+
}
|
|
7239
|
+
// evaluate with CB scores if applicable
|
|
7136
7240
|
let variation = this.evaluateCBScores(rule, visitorIdentifier, targetingData);
|
|
7137
7241
|
if (!variation) {
|
|
7138
7242
|
const variationHash = Hasher.getHashDouble({
|
|
@@ -7494,7 +7598,6 @@ class KameleoonEventSource {
|
|
|
7494
7598
|
const VISITOR_CODE_LENGTH = 16;
|
|
7495
7599
|
const VISITOR_CODE_MAX_LENGTH = 255;
|
|
7496
7600
|
const DEFAULT_MAX_AGE = 60 * 60 * 24 * 365;
|
|
7497
|
-
const ZERO_MAX_AGE = 0;
|
|
7498
7601
|
const PATH = '/';
|
|
7499
7602
|
|
|
7500
7603
|
/**
|
|
@@ -7962,7 +8065,7 @@ class Tracker {
|
|
|
7962
8065
|
this.dataManager.storeTrackedData(updatedData);
|
|
7963
8066
|
}
|
|
7964
8067
|
else {
|
|
7965
|
-
this.dataManager.storeData(updatedData);
|
|
8068
|
+
this.dataManager.storeData(updatedData, false);
|
|
7966
8069
|
}
|
|
7967
8070
|
}
|
|
7968
8071
|
getUnsentVisitorData(visitorCode, isConsentProvided) {
|
|
@@ -8314,16 +8417,23 @@ class KameleoonClient {
|
|
|
8314
8417
|
const variations = new Map();
|
|
8315
8418
|
const featureFlags = this.clientConfiguration.featureFlags;
|
|
8316
8419
|
for (const featureFlag of featureFlags.values()) {
|
|
8317
|
-
|
|
8318
|
-
|
|
8319
|
-
|
|
8320
|
-
|
|
8321
|
-
|
|
8322
|
-
|
|
8323
|
-
if (
|
|
8420
|
+
try {
|
|
8421
|
+
const variation = this._getFeatureVariation({
|
|
8422
|
+
visitorCode,
|
|
8423
|
+
featureKey: featureFlag.featureKey,
|
|
8424
|
+
track,
|
|
8425
|
+
});
|
|
8426
|
+
if (variation.ok &&
|
|
8427
|
+
(!onlyActive || variation.data.key !== OFF_VARIATION_KEY)) {
|
|
8324
8428
|
variations.set(featureFlag.featureKey, variation.data);
|
|
8325
8429
|
}
|
|
8326
8430
|
}
|
|
8431
|
+
catch (err) {
|
|
8432
|
+
if (err instanceof KameleoonError &&
|
|
8433
|
+
err.type !== KameleoonException.FeatureFlagEnvironmentDisabled) {
|
|
8434
|
+
throw err;
|
|
8435
|
+
}
|
|
8436
|
+
}
|
|
8327
8437
|
}
|
|
8328
8438
|
KameleoonLogger.info `RETURN: KameleoonClient.getVariations(visitorCode: ${visitorCode}, onlyActive: ${onlyActive}, track: ${track}) -> (variations: ${variations})`;
|
|
8329
8439
|
return variations;
|
|
@@ -8643,25 +8753,16 @@ class KameleoonClient {
|
|
|
8643
8753
|
path: PATH,
|
|
8644
8754
|
});
|
|
8645
8755
|
}
|
|
8646
|
-
else {
|
|
8647
|
-
if (this.visitorCodeManager.consentRequired) {
|
|
8648
|
-
setData({
|
|
8649
|
-
visitorCode: '',
|
|
8650
|
-
key: KameleoonStorageKey.VisitorCode,
|
|
8651
|
-
maxAge: ZERO_MAX_AGE,
|
|
8652
|
-
path: PATH,
|
|
8653
|
-
});
|
|
8654
|
-
}
|
|
8655
|
-
}
|
|
8656
8756
|
KameleoonLogger.info `RETURN: KameleoonClient.setUserConsent(visitorCode: ${visitorCode}, consent: ${consent}, setData: ${setData})`;
|
|
8657
8757
|
}
|
|
8658
8758
|
updateConsentData(visitorCode, consent) {
|
|
8659
8759
|
const readResult = this.consentDataStorage.read();
|
|
8760
|
+
const legalConsent = consent ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8660
8761
|
if (!readResult.ok) {
|
|
8661
8762
|
if (readResult.error.type === KameleoonException.StorageEmpty) {
|
|
8662
8763
|
this.consentDataStorage.write({
|
|
8663
8764
|
[visitorCode]: {
|
|
8664
|
-
consent,
|
|
8765
|
+
consent: legalConsent,
|
|
8665
8766
|
},
|
|
8666
8767
|
});
|
|
8667
8768
|
}
|
|
@@ -8669,28 +8770,36 @@ class KameleoonClient {
|
|
|
8669
8770
|
}
|
|
8670
8771
|
const data = readResult.data;
|
|
8671
8772
|
data[visitorCode] = {
|
|
8672
|
-
consent,
|
|
8773
|
+
consent: legalConsent,
|
|
8673
8774
|
};
|
|
8674
8775
|
this.consentDataStorage.write(data);
|
|
8675
8776
|
}
|
|
8777
|
+
getLegalConsent(visitorCode) {
|
|
8778
|
+
KameleoonLogger.debug `CALL: KameleoonClient.getLegalConsent(visitorCode: ${visitorCode})`;
|
|
8779
|
+
let legalConsent;
|
|
8780
|
+
const consentDataResult = this.consentDataStorage.read();
|
|
8781
|
+
legalConsent = consentDataResult.ok
|
|
8782
|
+
? this.extractLegalConsent(consentDataResult.data[visitorCode])
|
|
8783
|
+
: LegalConsent.Unknown;
|
|
8784
|
+
KameleoonLogger.debug `RETURN: KameleoonClient.getLegalConsent(visitorCode: ${visitorCode}) -> (legalConsent: ${legalConsent})`;
|
|
8785
|
+
return legalConsent;
|
|
8786
|
+
}
|
|
8787
|
+
extractLegalConsent(consentData) {
|
|
8788
|
+
if (consentData === undefined)
|
|
8789
|
+
return LegalConsent.Unknown;
|
|
8790
|
+
if (typeof consentData === 'boolean') {
|
|
8791
|
+
return consentData ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8792
|
+
}
|
|
8793
|
+
const value = consentData.consent;
|
|
8794
|
+
if (typeof value === 'boolean')
|
|
8795
|
+
return value ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8796
|
+
return value;
|
|
8797
|
+
}
|
|
8676
8798
|
_isConsentProvided(visitorCode) {
|
|
8677
8799
|
KameleoonLogger.debug `CALL: KameleoonClient._isConsentProvided(visitorCode: ${visitorCode})`;
|
|
8678
8800
|
const { isConsentRequired } = this.clientConfiguration;
|
|
8679
|
-
const
|
|
8680
|
-
|
|
8681
|
-
if (!isConsentRequired) {
|
|
8682
|
-
isConsentProvided = true;
|
|
8683
|
-
}
|
|
8684
|
-
else if (consentDataResult.ok) {
|
|
8685
|
-
const consentData = consentDataResult.data[visitorCode];
|
|
8686
|
-
// for consistency with the old data in the storage
|
|
8687
|
-
if (typeof consentData === 'boolean') {
|
|
8688
|
-
isConsentProvided = consentData;
|
|
8689
|
-
}
|
|
8690
|
-
else {
|
|
8691
|
-
isConsentProvided = consentData && consentData.consent;
|
|
8692
|
-
}
|
|
8693
|
-
}
|
|
8801
|
+
const isConsentProvided = !isConsentRequired ||
|
|
8802
|
+
this.getLegalConsent(visitorCode) == LegalConsent.Given;
|
|
8694
8803
|
KameleoonLogger.debug `RETURN: KameleoonClient._isConsentProvided(visitorCode: ${visitorCode}) -> (isConsentProvided: ${isConsentProvided})`;
|
|
8695
8804
|
return isConsentProvided;
|
|
8696
8805
|
}
|
|
@@ -8718,22 +8827,32 @@ class KameleoonClient {
|
|
|
8718
8827
|
if (!featureFlag.environmentEnabled) {
|
|
8719
8828
|
continue;
|
|
8720
8829
|
}
|
|
8721
|
-
|
|
8722
|
-
|
|
8723
|
-
|
|
8724
|
-
|
|
8725
|
-
|
|
8726
|
-
|
|
8727
|
-
if (evalExp.variationKey !== OFF_VARIATION_KEY) {
|
|
8728
|
-
activeVariations.push({
|
|
8729
|
-
variationKey: evalExp.variationKey,
|
|
8730
|
-
variationId: evalExp.variationId,
|
|
8731
|
-
experimentId: evalExp.experimentId,
|
|
8732
|
-
featureFlagId: featureFlag.id,
|
|
8733
|
-
featureKey: featureFlag.featureKey,
|
|
8734
|
-
rule: null,
|
|
8735
|
-
isTargetedRule: evalExp.ruleType === RuleType.TARGETED_DELIVERY,
|
|
8830
|
+
try {
|
|
8831
|
+
const evalExp = this._evaluate({
|
|
8832
|
+
visitorCode,
|
|
8833
|
+
featureFlag,
|
|
8834
|
+
track: false,
|
|
8835
|
+
save: false,
|
|
8736
8836
|
});
|
|
8837
|
+
if (evalExp.variationKey !== OFF_VARIATION_KEY) {
|
|
8838
|
+
activeVariations.push({
|
|
8839
|
+
variationKey: evalExp.variationKey,
|
|
8840
|
+
variationId: evalExp.variationId,
|
|
8841
|
+
experimentId: evalExp.experimentId,
|
|
8842
|
+
featureFlagId: featureFlag.id,
|
|
8843
|
+
featureKey: featureFlag.featureKey,
|
|
8844
|
+
rule: null,
|
|
8845
|
+
isTargetedRule: evalExp.ruleType === RuleType.TARGETED_DELIVERY,
|
|
8846
|
+
});
|
|
8847
|
+
}
|
|
8848
|
+
}
|
|
8849
|
+
catch (err) {
|
|
8850
|
+
if (err instanceof KameleoonError) {
|
|
8851
|
+
if (err.type != KameleoonException.FeatureFlagEnvironmentDisabled) {
|
|
8852
|
+
KameleoonLogger.error `Unexpected error: ${err}`;
|
|
8853
|
+
}
|
|
8854
|
+
continue;
|
|
8855
|
+
}
|
|
8737
8856
|
}
|
|
8738
8857
|
}
|
|
8739
8858
|
KameleoonLogger.debug `RETURN: KameleoonClient._getActiveFeatureVariations(visitorCode: ${visitorCode}) -> (activeVariations: ${activeVariations})`;
|
|
@@ -8754,6 +8873,7 @@ class KameleoonClient {
|
|
|
8754
8873
|
else if (this._isVisitorNotInHoldout(visitorCode, track, save, featureFlag, visitorData) &&
|
|
8755
8874
|
this._isFFUnrestrictedByMEGroup(visitorCode, featureFlag, visitorData)) {
|
|
8756
8875
|
const visitorIdentifier = this._getCodeForHash(visitorCode, featureFlag.bucketingCustomDataIndex, visitorData);
|
|
8876
|
+
const legalConsent = this.getLegalConsent(visitorCode);
|
|
8757
8877
|
const variationData = this.variationConfiguration
|
|
8758
8878
|
.getVariation({
|
|
8759
8879
|
visitorCode,
|
|
@@ -8765,6 +8885,7 @@ class KameleoonClient {
|
|
|
8765
8885
|
clientConfiguration: this.clientConfiguration,
|
|
8766
8886
|
dataManager: this.dataManager,
|
|
8767
8887
|
packageInfo: this.externalPackageInfo,
|
|
8888
|
+
legalConsent,
|
|
8768
8889
|
})
|
|
8769
8890
|
.throw();
|
|
8770
8891
|
evalExp =
|
|
@@ -8883,6 +9004,14 @@ class KameleoonClient {
|
|
|
8883
9004
|
}
|
|
8884
9005
|
KameleoonLogger.debug `CALL: KameleoonClient._isVisitorNotInHoldout(visitorCode: ${visitorCode}, track: ${track}, save: ${save}, featureFlag: ${featureFlag}, visitorData: ${visitorData})`;
|
|
8885
9006
|
let isNotInHoldout = true;
|
|
9007
|
+
// Checking if the evaluation is blocked due to the consent policy
|
|
9008
|
+
const legalConsent = this.getLegalConsent(visitorCode);
|
|
9009
|
+
if (legalConsent == LegalConsent.NotGiven) {
|
|
9010
|
+
const behaviour = this.clientConfiguration.consentBlockingBehaviour;
|
|
9011
|
+
if (behaviour == ConsentBlockingBehaviour.CompletelyBlocked) {
|
|
9012
|
+
throw new KameleoonError(KameleoonException.FeatureFlagEnvironmentDisabled, `Evaluation of holdout is blocked because consent is not provided for visitor '${visitorCode}'`);
|
|
9013
|
+
}
|
|
9014
|
+
}
|
|
8886
9015
|
const codeForHash = this._getCodeForHash(visitorCode, featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.bucketingCustomDataIndex, visitorData);
|
|
8887
9016
|
const holdoutHash = Hasher.getHashDouble({
|
|
8888
9017
|
visitorIdentifier: codeForHash,
|