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