@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
|
@@ -249,10 +249,17 @@ class KameleoonError extends Error {
|
|
|
249
249
|
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
250
250
|
break;
|
|
251
251
|
case exports.KameleoonException.FeatureFlagVariationNotFound:
|
|
252
|
-
case exports.KameleoonException.FeatureFlagEnvironmentDisabled:
|
|
253
252
|
case exports.KameleoonException.FeatureFlagVariableNotFound:
|
|
254
253
|
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
255
254
|
break;
|
|
255
|
+
case exports.KameleoonException.FeatureFlagEnvironmentDisabled:
|
|
256
|
+
if (thirdParam !== undefined) {
|
|
257
|
+
this.message = ERROR_MESSAGES[type](secondParam, thirdParam);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
this.message = secondParam;
|
|
261
|
+
}
|
|
262
|
+
break;
|
|
256
263
|
case exports.KameleoonException.StorageWrite:
|
|
257
264
|
case exports.KameleoonException.JSONParse:
|
|
258
265
|
this.message = ERROR_MESSAGES[type](secondParam);
|
|
@@ -308,7 +315,7 @@ exports.RequestType = void 0;
|
|
|
308
315
|
RequestType["RemoteData"] = "remoteData";
|
|
309
316
|
})(exports.RequestType || (exports.RequestType = {}));
|
|
310
317
|
|
|
311
|
-
const NUMBER_OF_RETRIES =
|
|
318
|
+
const NUMBER_OF_RETRIES = 1;
|
|
312
319
|
exports.Header = void 0;
|
|
313
320
|
(function (Header) {
|
|
314
321
|
Header["UserAgent"] = "User-Agent";
|
|
@@ -887,6 +894,9 @@ class UrlProvider {
|
|
|
887
894
|
const currentDomain = this.domains[UrlType.DataApi];
|
|
888
895
|
this.domains[UrlType.DataApi] = currentDomain.replace(/^[^.]+/, subDomain);
|
|
889
896
|
}
|
|
897
|
+
get dataApiDomain() {
|
|
898
|
+
return this.domains[UrlType.DataApi];
|
|
899
|
+
}
|
|
890
900
|
getClientConfigurationUrl(timeStamp) {
|
|
891
901
|
this.isInitialized();
|
|
892
902
|
const baseUrl = `https://${this.domains[UrlType.ClientConfiguration]}/v3/`;
|
|
@@ -1146,6 +1156,11 @@ var ConsentType;
|
|
|
1146
1156
|
ConsentType["Required"] = "REQUIRED";
|
|
1147
1157
|
ConsentType["NotRequired"] = "NOT_REQUIRED";
|
|
1148
1158
|
})(ConsentType || (ConsentType = {}));
|
|
1159
|
+
var ConsentBlockingBehaviour;
|
|
1160
|
+
(function (ConsentBlockingBehaviour) {
|
|
1161
|
+
ConsentBlockingBehaviour["PartiallyBlocked"] = "PARTIALLY_BLOCK";
|
|
1162
|
+
ConsentBlockingBehaviour["CompletelyBlocked"] = "FULLY_BLOCK";
|
|
1163
|
+
})(ConsentBlockingBehaviour || (ConsentBlockingBehaviour = {}));
|
|
1149
1164
|
|
|
1150
1165
|
class EventManager {
|
|
1151
1166
|
addEventHandler(eventType, callback) {
|
|
@@ -1173,17 +1188,14 @@ exports.EventType = void 0;
|
|
|
1173
1188
|
EventType["ConfigurationUpdate"] = "configurationUpdate";
|
|
1174
1189
|
})(exports.EventType || (exports.EventType = {}));
|
|
1175
1190
|
|
|
1176
|
-
|
|
1177
|
-
configuration: {
|
|
1178
|
-
consentType: ConsentType.NotRequired},
|
|
1179
|
-
});
|
|
1180
|
-
const DEFAULT_CLIENT_CONFIGURATION$1 = {
|
|
1191
|
+
const DEFAULT_DATA_FILE_CONFIGURATION = {
|
|
1181
1192
|
customData: [],
|
|
1182
1193
|
featureFlags: [],
|
|
1183
1194
|
configuration: {
|
|
1184
1195
|
realTimeUpdate: false,
|
|
1185
1196
|
consentType: ConsentType.NotRequired,
|
|
1186
1197
|
dataApiDomain: 'data.kameleoon.io',
|
|
1198
|
+
consentOptOutBehavior: ConsentBlockingBehaviour.PartiallyBlocked,
|
|
1187
1199
|
},
|
|
1188
1200
|
};
|
|
1189
1201
|
|
|
@@ -1207,7 +1219,7 @@ class ClientConfiguration {
|
|
|
1207
1219
|
constructor({ updateInterval, urlProvider, storage, requester, dataManager, eventSource, externalVisitorCodeManager, eventManager, externalPackageInfo, defaultDataFile, }) {
|
|
1208
1220
|
this.updateConfigurationIntervalId = null;
|
|
1209
1221
|
this.updateType = UpdateType.Polling;
|
|
1210
|
-
this.configurationData =
|
|
1222
|
+
this.configurationData = DEFAULT_DATA_FILE_CONFIGURATION;
|
|
1211
1223
|
this.featureFlagsData = new Map();
|
|
1212
1224
|
this.isTargetedDeliveryRule = null;
|
|
1213
1225
|
this.segmentsData = null;
|
|
@@ -1216,6 +1228,7 @@ class ClientConfiguration {
|
|
|
1216
1228
|
this.mappedRules = null;
|
|
1217
1229
|
this.mappedExperiments = null;
|
|
1218
1230
|
this.usedDefaultDataFile = false;
|
|
1231
|
+
this.blockingBehaviourMode = ConsentBlockingBehaviour.PartiallyBlocked;
|
|
1219
1232
|
this.CACHE_REVALIDATE_PERIOD = 90 * exports.Milliseconds.Minute;
|
|
1220
1233
|
this.urlProvider = urlProvider;
|
|
1221
1234
|
this.requester = requester;
|
|
@@ -1390,6 +1403,9 @@ class ClientConfiguration {
|
|
|
1390
1403
|
get isConsentRequired() {
|
|
1391
1404
|
return this.configuration.consentType === ConsentType.Required;
|
|
1392
1405
|
}
|
|
1406
|
+
get consentBlockingBehaviour() {
|
|
1407
|
+
return this.blockingBehaviourMode;
|
|
1408
|
+
}
|
|
1393
1409
|
get hasAnyTargetedDeliveryRule() {
|
|
1394
1410
|
if (this.isTargetedDeliveryRule !== null) {
|
|
1395
1411
|
return this.isTargetedDeliveryRule;
|
|
@@ -1518,6 +1534,7 @@ class ClientConfiguration {
|
|
|
1518
1534
|
KameleoonLogger.info `Configuration update type was toggled to ${UpdateType[updateType]}`;
|
|
1519
1535
|
yield this.initialize();
|
|
1520
1536
|
}
|
|
1537
|
+
this.blockingBehaviourMode = this.consentBlockingBehaviourFromStr(clientConfigurationData.configuration.consentOptOutBehavior);
|
|
1521
1538
|
return buildExports.Ok(toggleUpdateType);
|
|
1522
1539
|
});
|
|
1523
1540
|
}
|
|
@@ -1624,6 +1641,14 @@ class ClientConfiguration {
|
|
|
1624
1641
|
this.visitorCodeManager.consentRequired =
|
|
1625
1642
|
this.isConsentRequired && !this.hasAnyTargetedDeliveryRule;
|
|
1626
1643
|
}
|
|
1644
|
+
consentBlockingBehaviourFromStr(str) {
|
|
1645
|
+
if (str === ConsentBlockingBehaviour.PartiallyBlocked ||
|
|
1646
|
+
str === ConsentBlockingBehaviour.CompletelyBlocked) {
|
|
1647
|
+
return str;
|
|
1648
|
+
}
|
|
1649
|
+
KameleoonLogger.error(`Unexpected consent blocking type '${str}'`);
|
|
1650
|
+
return ConsentBlockingBehaviour.PartiallyBlocked;
|
|
1651
|
+
}
|
|
1627
1652
|
}
|
|
1628
1653
|
|
|
1629
1654
|
function constructTypeMap(indexMap) {
|
|
@@ -2302,11 +2327,11 @@ let CustomData$1 = class CustomData {
|
|
|
2302
2327
|
const isNumber = typeof first === 'number';
|
|
2303
2328
|
const isBoolean = typeof second === 'boolean';
|
|
2304
2329
|
if (isNumber) {
|
|
2305
|
-
this.
|
|
2330
|
+
this._index = first;
|
|
2306
2331
|
}
|
|
2307
2332
|
else {
|
|
2308
|
-
this.
|
|
2309
|
-
this.
|
|
2333
|
+
this._name = first;
|
|
2334
|
+
this._index = CustomData.UNDEFINED_INDEX;
|
|
2310
2335
|
}
|
|
2311
2336
|
this.overwrite = isBoolean ? second : true;
|
|
2312
2337
|
this.value = isBoolean
|
|
@@ -2317,7 +2342,7 @@ let CustomData$1 = class CustomData {
|
|
|
2317
2342
|
// --- Note ---
|
|
2318
2343
|
// If SDK is used in vanilla JS codebase, then you're also able to create an instance
|
|
2319
2344
|
// with no required data, we don't want send anything to tracking in that case
|
|
2320
|
-
if (typeof this.
|
|
2345
|
+
if (typeof this._index !== 'number') {
|
|
2321
2346
|
return '';
|
|
2322
2347
|
}
|
|
2323
2348
|
const uniqueValues = [...new Set(this.value)];
|
|
@@ -2334,7 +2359,7 @@ let CustomData$1 = class CustomData {
|
|
|
2334
2359
|
}
|
|
2335
2360
|
return (UrlEventType.CustomData +
|
|
2336
2361
|
UrlParameter.Index +
|
|
2337
|
-
this.
|
|
2362
|
+
this._index +
|
|
2338
2363
|
UrlParameter.ValuesCountMap +
|
|
2339
2364
|
encodeURIComponent(JSON.stringify(resultValue)) +
|
|
2340
2365
|
UrlParameter.Overwrite +
|
|
@@ -2342,7 +2367,7 @@ let CustomData$1 = class CustomData {
|
|
|
2342
2367
|
identifierParameter);
|
|
2343
2368
|
}
|
|
2344
2369
|
get data() {
|
|
2345
|
-
return Object.assign(Object.assign({ index: this.
|
|
2370
|
+
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 });
|
|
2346
2371
|
}
|
|
2347
2372
|
get status() {
|
|
2348
2373
|
if (this._isMappingIdentifier) {
|
|
@@ -2361,7 +2386,7 @@ let CustomData$1 = class CustomData {
|
|
|
2361
2386
|
let customData;
|
|
2362
2387
|
if (name) {
|
|
2363
2388
|
customData = new CustomData(name, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
|
|
2364
|
-
customData.
|
|
2389
|
+
customData.index = index;
|
|
2365
2390
|
}
|
|
2366
2391
|
else {
|
|
2367
2392
|
customData = new CustomData(index, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
|
|
@@ -2398,13 +2423,35 @@ let CustomData$1 = class CustomData {
|
|
|
2398
2423
|
}
|
|
2399
2424
|
/**
|
|
2400
2425
|
* @private
|
|
2401
|
-
* @method
|
|
2426
|
+
* @method index - an internal setter for setting index of custom data
|
|
2402
2427
|
* @param {number} value - an index value
|
|
2403
2428
|
* */
|
|
2404
|
-
set
|
|
2405
|
-
this.
|
|
2429
|
+
set index(value) {
|
|
2430
|
+
this._index = value;
|
|
2431
|
+
}
|
|
2432
|
+
/**
|
|
2433
|
+
* @private
|
|
2434
|
+
* @method index - an internal getter for index of custom data
|
|
2435
|
+
* */
|
|
2436
|
+
get index() {
|
|
2437
|
+
return this._index;
|
|
2438
|
+
}
|
|
2439
|
+
/**
|
|
2440
|
+
* @private
|
|
2441
|
+
* @method name - an internal getter for a name of custom data
|
|
2442
|
+
* */
|
|
2443
|
+
get name() {
|
|
2444
|
+
return this._name;
|
|
2445
|
+
}
|
|
2446
|
+
/**
|
|
2447
|
+
* @private
|
|
2448
|
+
* @method name - an internal getter for a name of custom data
|
|
2449
|
+
* */
|
|
2450
|
+
get values() {
|
|
2451
|
+
return this.value;
|
|
2406
2452
|
}
|
|
2407
2453
|
};
|
|
2454
|
+
CustomData$1.UNDEFINED_INDEX = -1;
|
|
2408
2455
|
|
|
2409
2456
|
/**
|
|
2410
2457
|
* @class
|
|
@@ -2420,7 +2467,7 @@ let Conversion$1 = class Conversion {
|
|
|
2420
2467
|
this.negative = negative;
|
|
2421
2468
|
this.status = exports.TrackingStatus.Unsent;
|
|
2422
2469
|
this.id = Math.floor(Math.random() * 1000000);
|
|
2423
|
-
this.
|
|
2470
|
+
this._metadata = metadata;
|
|
2424
2471
|
}
|
|
2425
2472
|
set _id(id) {
|
|
2426
2473
|
this.id = id;
|
|
@@ -2441,6 +2488,21 @@ let Conversion$1 = class Conversion {
|
|
|
2441
2488
|
? UrlParameter.Metadata + this._encodeMetadata()
|
|
2442
2489
|
: ''));
|
|
2443
2490
|
}
|
|
2491
|
+
/**
|
|
2492
|
+
* @private
|
|
2493
|
+
* @method metadata - an internal getter for a metadata of conversion
|
|
2494
|
+
* */
|
|
2495
|
+
get _metadata() {
|
|
2496
|
+
return this.metadata;
|
|
2497
|
+
}
|
|
2498
|
+
/**
|
|
2499
|
+
* @private
|
|
2500
|
+
* @method metadata - an internal setter for setting metadata of conversion
|
|
2501
|
+
* @param {number} value - an index value
|
|
2502
|
+
* */
|
|
2503
|
+
set _metadata(value) {
|
|
2504
|
+
this.metadata = value;
|
|
2505
|
+
}
|
|
2444
2506
|
get data() {
|
|
2445
2507
|
var _a;
|
|
2446
2508
|
return {
|
|
@@ -3533,7 +3595,7 @@ class DataProcessor {
|
|
|
3533
3595
|
this.cleanupInterval = cleanupInterval;
|
|
3534
3596
|
this.packageInfo = packageInfo;
|
|
3535
3597
|
}
|
|
3536
|
-
mutUpdateData({ infoData, visitorCode, mutData, dataItem, }) {
|
|
3598
|
+
mutUpdateData({ infoData, visitorCode, mutData, dataItem, extendTtl, }) {
|
|
3537
3599
|
let { visitorReference, data, isReference } = this.dereferenceData(mutData, visitorCode);
|
|
3538
3600
|
if (this.packageInfo.isServer &&
|
|
3539
3601
|
isReference &&
|
|
@@ -3544,9 +3606,12 @@ class DataProcessor {
|
|
|
3544
3606
|
delete mutData[visitorCode];
|
|
3545
3607
|
visitorReference = visitorCode;
|
|
3546
3608
|
}
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3609
|
+
let expirationTime;
|
|
3610
|
+
if (extendTtl) {
|
|
3611
|
+
expirationTime = this.cleanupInterval
|
|
3612
|
+
? Date.now() + this.cleanupInterval
|
|
3613
|
+
: 0;
|
|
3614
|
+
}
|
|
3550
3615
|
switch (dataItem.data.type) {
|
|
3551
3616
|
case exports.KameleoonData.CustomData: {
|
|
3552
3617
|
this.updateCustomData({
|
|
@@ -3901,13 +3966,17 @@ class DataProcessor {
|
|
|
3901
3966
|
return closestCleanupTime;
|
|
3902
3967
|
}
|
|
3903
3968
|
updateField({ key, value, data, visitorCode, expirationTime, }) {
|
|
3904
|
-
|
|
3969
|
+
var _a;
|
|
3970
|
+
const existing = data[visitorCode][key];
|
|
3971
|
+
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() });
|
|
3905
3972
|
}
|
|
3906
3973
|
createField({ key, value, data, visitorCode, expirationTime, }) {
|
|
3907
3974
|
data[visitorCode] = Object.assign(Object.assign({}, data[visitorCode]), { [key]: Object.assign(Object.assign({}, value), { expirationTime }) });
|
|
3908
3975
|
}
|
|
3909
3976
|
updateNestedField({ key, nestedKey, value, data, visitorCode, expirationTime, }) {
|
|
3910
|
-
|
|
3977
|
+
var _a;
|
|
3978
|
+
const existing = data[visitorCode][key][nestedKey];
|
|
3979
|
+
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() });
|
|
3911
3980
|
}
|
|
3912
3981
|
createNestedField({ key, nestedKey, value, data, visitorCode, expirationTime, }) {
|
|
3913
3982
|
var _a;
|
|
@@ -5173,15 +5242,7 @@ exports.KameleoonStorageKey = void 0;
|
|
|
5173
5242
|
KameleoonStorageKey["ForcedExperimentVariation"] = "kameleoonForcedExperimentVariation";
|
|
5174
5243
|
})(exports.KameleoonStorageKey || (exports.KameleoonStorageKey = {}));
|
|
5175
5244
|
const DEFAULT_CLIENT_CONFIGURATION = {
|
|
5176
|
-
data:
|
|
5177
|
-
customData: [],
|
|
5178
|
-
featureFlags: [],
|
|
5179
|
-
configuration: {
|
|
5180
|
-
realTimeUpdate: false,
|
|
5181
|
-
consentType: ConsentType.NotRequired,
|
|
5182
|
-
dataApiDomain: 'data.kameleoon.io',
|
|
5183
|
-
},
|
|
5184
|
-
},
|
|
5245
|
+
data: DEFAULT_DATA_FILE_CONFIGURATION,
|
|
5185
5246
|
lastUpdate: '',
|
|
5186
5247
|
};
|
|
5187
5248
|
// --- Note ---
|
|
@@ -5693,7 +5754,7 @@ class DataManager {
|
|
|
5693
5754
|
return resultData;
|
|
5694
5755
|
}
|
|
5695
5756
|
storeTrackedData(data) {
|
|
5696
|
-
this.storeData(data);
|
|
5757
|
+
this.storeData(data, false);
|
|
5697
5758
|
const infoResult = this.infoStorage.read();
|
|
5698
5759
|
if (!infoResult.ok) {
|
|
5699
5760
|
return;
|
|
@@ -5745,15 +5806,18 @@ class DataManager {
|
|
|
5745
5806
|
targetingData,
|
|
5746
5807
|
visitorCode: firstParameter,
|
|
5747
5808
|
kameleoonData: secondParameter,
|
|
5809
|
+
extendTtl: true,
|
|
5748
5810
|
});
|
|
5749
5811
|
}
|
|
5750
5812
|
else {
|
|
5751
5813
|
for (const [visitorCode, kameleoonData] of Object.entries(firstParameter)) {
|
|
5814
|
+
const extendTtl = typeof secondParameter[0] === 'boolean' ? secondParameter[0] : true;
|
|
5752
5815
|
this.mutUpdateTargetingData({
|
|
5753
5816
|
infoData,
|
|
5754
5817
|
targetingData,
|
|
5755
5818
|
visitorCode,
|
|
5756
5819
|
kameleoonData,
|
|
5820
|
+
extendTtl,
|
|
5757
5821
|
});
|
|
5758
5822
|
}
|
|
5759
5823
|
}
|
|
@@ -5870,8 +5934,10 @@ class DataManager {
|
|
|
5870
5934
|
}
|
|
5871
5935
|
return null;
|
|
5872
5936
|
}
|
|
5873
|
-
mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, }) {
|
|
5937
|
+
mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, extendTtl, }) {
|
|
5938
|
+
var _a, _b, _c;
|
|
5874
5939
|
for (const dataItem of kameleoonData) {
|
|
5940
|
+
// process custom data
|
|
5875
5941
|
if (dataItem.data.type === exports.KameleoonData.CustomData) {
|
|
5876
5942
|
const customDataIsValid = this.processCustomData({
|
|
5877
5943
|
infoData,
|
|
@@ -5883,14 +5949,23 @@ class DataManager {
|
|
|
5883
5949
|
continue;
|
|
5884
5950
|
}
|
|
5885
5951
|
}
|
|
5952
|
+
// process metadata of conversions
|
|
5953
|
+
if (dataItem.data.type === exports.KameleoonData.Conversion) {
|
|
5954
|
+
const conversion = dataItem;
|
|
5955
|
+
if (((_b = (_a = conversion._metadata) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0) > 0) {
|
|
5956
|
+
conversion._metadata = (_c = conversion._metadata) === null || _c === void 0 ? void 0 : _c.filter((item) => this.trySetCustomDataIndexByName(item));
|
|
5957
|
+
}
|
|
5958
|
+
}
|
|
5886
5959
|
const expirationTime = this.dataProcessor.mutUpdateData({
|
|
5887
5960
|
infoData,
|
|
5888
5961
|
visitorCode,
|
|
5889
5962
|
mutData: targetingData,
|
|
5890
5963
|
dataItem,
|
|
5964
|
+
extendTtl,
|
|
5891
5965
|
});
|
|
5892
5966
|
const nextCleanup = infoData.nextDataCleanup;
|
|
5893
|
-
if (!nextCleanup ||
|
|
5967
|
+
if (!nextCleanup ||
|
|
5968
|
+
(nextCleanup && expirationTime && expirationTime < nextCleanup)) {
|
|
5894
5969
|
infoData.nextDataCleanup = expirationTime;
|
|
5895
5970
|
}
|
|
5896
5971
|
if (dataItem.data.status === exports.TrackingStatus.Unsent) {
|
|
@@ -5922,13 +5997,11 @@ class DataManager {
|
|
|
5922
5997
|
var _a;
|
|
5923
5998
|
const { data } = customData;
|
|
5924
5999
|
const isDataValid = Boolean(data.value.length && data.value[0].length);
|
|
5925
|
-
if (
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
5929
|
-
|
|
5930
|
-
data.index = cdIndex;
|
|
5931
|
-
customData._index = cdIndex;
|
|
6000
|
+
if (!this.trySetCustomDataIndexByName(customData)) {
|
|
6001
|
+
return false;
|
|
6002
|
+
}
|
|
6003
|
+
if (data.index == CustomData$1.UNDEFINED_INDEX) {
|
|
6004
|
+
data.index = customData.index;
|
|
5932
6005
|
}
|
|
5933
6006
|
if (this.mappingIdentifierCustomDataIndex === data.index && isDataValid) {
|
|
5934
6007
|
customData._isMappingIdentifier = true;
|
|
@@ -5955,6 +6028,17 @@ class DataManager {
|
|
|
5955
6028
|
}
|
|
5956
6029
|
return true;
|
|
5957
6030
|
}
|
|
6031
|
+
trySetCustomDataIndexByName(customData) {
|
|
6032
|
+
if (customData.index !== CustomData$1.UNDEFINED_INDEX)
|
|
6033
|
+
return true;
|
|
6034
|
+
if (!customData.name)
|
|
6035
|
+
return false;
|
|
6036
|
+
const cdIndex = this.customDataIndexByName.get(customData.name);
|
|
6037
|
+
if (cdIndex == null)
|
|
6038
|
+
return false;
|
|
6039
|
+
customData.index = cdIndex;
|
|
6040
|
+
return true;
|
|
6041
|
+
}
|
|
5958
6042
|
get unsentDataVisitors() {
|
|
5959
6043
|
const infoResult = this.infoStorage.read();
|
|
5960
6044
|
if (!infoResult.ok) {
|
|
@@ -7066,6 +7150,13 @@ class Hasher {
|
|
|
7066
7150
|
}
|
|
7067
7151
|
}
|
|
7068
7152
|
|
|
7153
|
+
var LegalConsent;
|
|
7154
|
+
(function (LegalConsent) {
|
|
7155
|
+
LegalConsent[LegalConsent["Unknown"] = 0] = "Unknown";
|
|
7156
|
+
LegalConsent[LegalConsent["Given"] = 1] = "Given";
|
|
7157
|
+
LegalConsent[LegalConsent["NotGiven"] = 2] = "NotGiven";
|
|
7158
|
+
})(LegalConsent || (LegalConsent = {}));
|
|
7159
|
+
|
|
7069
7160
|
class VariationConfiguration {
|
|
7070
7161
|
constructor(externalStorage, externalStorageForcedExperimentVariations, externalStorageForcedFeatureVariations, visitorCodeManager, clientConfiguration) {
|
|
7071
7162
|
this.storage = externalStorage;
|
|
@@ -7124,9 +7215,12 @@ class VariationConfiguration {
|
|
|
7124
7215
|
}
|
|
7125
7216
|
return buildExports.Ok(featureFlagVariations);
|
|
7126
7217
|
}
|
|
7127
|
-
getVariation({ visitorCode, visitorIdentifier, featureFlag, targetingData, packageInfo, clientConfiguration, dataManager, track = true, withAssignment = false, }) {
|
|
7218
|
+
getVariation({ visitorCode, visitorIdentifier, featureFlag, targetingData, packageInfo, clientConfiguration, dataManager, legalConsent, track = true, withAssignment = false, }) {
|
|
7128
7219
|
KameleoonLogger.debug `CALL: VariationConfiguration.getVariation(visitorCode: ${visitorCode}, visitorIdentifier: ${visitorIdentifier}, featureFlag: ${featureFlag}, targetingData: ${targetingData}, packageInfo: ${packageInfo}, clientConfiguration, dataManager, withAssignment: ${withAssignment})`;
|
|
7129
7220
|
const { rules, featureKey, id: featureFlagId, defaultVariationKey, } = featureFlag;
|
|
7221
|
+
const consent = clientConfiguration.isConsentRequired
|
|
7222
|
+
? legalConsent
|
|
7223
|
+
: LegalConsent.Given;
|
|
7130
7224
|
for (const rule of rules) {
|
|
7131
7225
|
const { segment, experimentId, id, exposition, respoolTime, variationByExposition, } = rule;
|
|
7132
7226
|
const forcedVariationData = this.getForcedExperimentVariation(visitorCode, rule.experimentId);
|
|
@@ -7173,6 +7267,16 @@ class VariationConfiguration {
|
|
|
7173
7267
|
});
|
|
7174
7268
|
KameleoonLogger.debug `Calculated ruleHash: ${ruleHash} for code: ${visitorIdentifier}`;
|
|
7175
7269
|
if (ruleHash <= exposition) {
|
|
7270
|
+
// Checking if the evaluation is blocked due to the consent policy
|
|
7271
|
+
if (consent == LegalConsent.NotGiven &&
|
|
7272
|
+
rule.type == RuleType.EXPERIMENTATION) {
|
|
7273
|
+
const behaviour = clientConfiguration.consentBlockingBehaviour;
|
|
7274
|
+
if (behaviour == ConsentBlockingBehaviour.PartiallyBlocked) {
|
|
7275
|
+
break;
|
|
7276
|
+
}
|
|
7277
|
+
return buildExports.Err(new KameleoonError(exports.KameleoonException.FeatureFlagEnvironmentDisabled, `Evaluation of ${rule} is blocked because consent is not provided for visitor '${visitorCode}'`));
|
|
7278
|
+
}
|
|
7279
|
+
// evaluate with CB scores if applicable
|
|
7176
7280
|
let variation = this.evaluateCBScores(rule, visitorIdentifier, targetingData);
|
|
7177
7281
|
if (!variation) {
|
|
7178
7282
|
const variationHash = Hasher.getHashDouble({
|
|
@@ -7534,7 +7638,6 @@ class KameleoonEventSource {
|
|
|
7534
7638
|
const VISITOR_CODE_LENGTH = 16;
|
|
7535
7639
|
const VISITOR_CODE_MAX_LENGTH = 255;
|
|
7536
7640
|
const DEFAULT_MAX_AGE = 60 * 60 * 24 * 365;
|
|
7537
|
-
const ZERO_MAX_AGE = 0;
|
|
7538
7641
|
const PATH = '/';
|
|
7539
7642
|
|
|
7540
7643
|
/**
|
|
@@ -8002,7 +8105,7 @@ class Tracker {
|
|
|
8002
8105
|
this.dataManager.storeTrackedData(updatedData);
|
|
8003
8106
|
}
|
|
8004
8107
|
else {
|
|
8005
|
-
this.dataManager.storeData(updatedData);
|
|
8108
|
+
this.dataManager.storeData(updatedData, false);
|
|
8006
8109
|
}
|
|
8007
8110
|
}
|
|
8008
8111
|
getUnsentVisitorData(visitorCode, isConsentProvided) {
|
|
@@ -8354,16 +8457,23 @@ class KameleoonClient {
|
|
|
8354
8457
|
const variations = new Map();
|
|
8355
8458
|
const featureFlags = this.clientConfiguration.featureFlags;
|
|
8356
8459
|
for (const featureFlag of featureFlags.values()) {
|
|
8357
|
-
|
|
8358
|
-
|
|
8359
|
-
|
|
8360
|
-
|
|
8361
|
-
|
|
8362
|
-
|
|
8363
|
-
if (
|
|
8460
|
+
try {
|
|
8461
|
+
const variation = this._getFeatureVariation({
|
|
8462
|
+
visitorCode,
|
|
8463
|
+
featureKey: featureFlag.featureKey,
|
|
8464
|
+
track,
|
|
8465
|
+
});
|
|
8466
|
+
if (variation.ok &&
|
|
8467
|
+
(!onlyActive || variation.data.key !== OFF_VARIATION_KEY)) {
|
|
8364
8468
|
variations.set(featureFlag.featureKey, variation.data);
|
|
8365
8469
|
}
|
|
8366
8470
|
}
|
|
8471
|
+
catch (err) {
|
|
8472
|
+
if (err instanceof KameleoonError &&
|
|
8473
|
+
err.type !== exports.KameleoonException.FeatureFlagEnvironmentDisabled) {
|
|
8474
|
+
throw err;
|
|
8475
|
+
}
|
|
8476
|
+
}
|
|
8367
8477
|
}
|
|
8368
8478
|
KameleoonLogger.info `RETURN: KameleoonClient.getVariations(visitorCode: ${visitorCode}, onlyActive: ${onlyActive}, track: ${track}) -> (variations: ${variations})`;
|
|
8369
8479
|
return variations;
|
|
@@ -8683,25 +8793,16 @@ class KameleoonClient {
|
|
|
8683
8793
|
path: PATH,
|
|
8684
8794
|
});
|
|
8685
8795
|
}
|
|
8686
|
-
else {
|
|
8687
|
-
if (this.visitorCodeManager.consentRequired) {
|
|
8688
|
-
setData({
|
|
8689
|
-
visitorCode: '',
|
|
8690
|
-
key: exports.KameleoonStorageKey.VisitorCode,
|
|
8691
|
-
maxAge: ZERO_MAX_AGE,
|
|
8692
|
-
path: PATH,
|
|
8693
|
-
});
|
|
8694
|
-
}
|
|
8695
|
-
}
|
|
8696
8796
|
KameleoonLogger.info `RETURN: KameleoonClient.setUserConsent(visitorCode: ${visitorCode}, consent: ${consent}, setData: ${setData})`;
|
|
8697
8797
|
}
|
|
8698
8798
|
updateConsentData(visitorCode, consent) {
|
|
8699
8799
|
const readResult = this.consentDataStorage.read();
|
|
8800
|
+
const legalConsent = consent ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8700
8801
|
if (!readResult.ok) {
|
|
8701
8802
|
if (readResult.error.type === exports.KameleoonException.StorageEmpty) {
|
|
8702
8803
|
this.consentDataStorage.write({
|
|
8703
8804
|
[visitorCode]: {
|
|
8704
|
-
consent,
|
|
8805
|
+
consent: legalConsent,
|
|
8705
8806
|
},
|
|
8706
8807
|
});
|
|
8707
8808
|
}
|
|
@@ -8709,28 +8810,36 @@ class KameleoonClient {
|
|
|
8709
8810
|
}
|
|
8710
8811
|
const data = readResult.data;
|
|
8711
8812
|
data[visitorCode] = {
|
|
8712
|
-
consent,
|
|
8813
|
+
consent: legalConsent,
|
|
8713
8814
|
};
|
|
8714
8815
|
this.consentDataStorage.write(data);
|
|
8715
8816
|
}
|
|
8817
|
+
getLegalConsent(visitorCode) {
|
|
8818
|
+
KameleoonLogger.debug `CALL: KameleoonClient.getLegalConsent(visitorCode: ${visitorCode})`;
|
|
8819
|
+
let legalConsent;
|
|
8820
|
+
const consentDataResult = this.consentDataStorage.read();
|
|
8821
|
+
legalConsent = consentDataResult.ok
|
|
8822
|
+
? this.extractLegalConsent(consentDataResult.data[visitorCode])
|
|
8823
|
+
: LegalConsent.Unknown;
|
|
8824
|
+
KameleoonLogger.debug `RETURN: KameleoonClient.getLegalConsent(visitorCode: ${visitorCode}) -> (legalConsent: ${legalConsent})`;
|
|
8825
|
+
return legalConsent;
|
|
8826
|
+
}
|
|
8827
|
+
extractLegalConsent(consentData) {
|
|
8828
|
+
if (consentData === undefined)
|
|
8829
|
+
return LegalConsent.Unknown;
|
|
8830
|
+
if (typeof consentData === 'boolean') {
|
|
8831
|
+
return consentData ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8832
|
+
}
|
|
8833
|
+
const value = consentData.consent;
|
|
8834
|
+
if (typeof value === 'boolean')
|
|
8835
|
+
return value ? LegalConsent.Given : LegalConsent.NotGiven;
|
|
8836
|
+
return value;
|
|
8837
|
+
}
|
|
8716
8838
|
_isConsentProvided(visitorCode) {
|
|
8717
8839
|
KameleoonLogger.debug `CALL: KameleoonClient._isConsentProvided(visitorCode: ${visitorCode})`;
|
|
8718
8840
|
const { isConsentRequired } = this.clientConfiguration;
|
|
8719
|
-
const
|
|
8720
|
-
|
|
8721
|
-
if (!isConsentRequired) {
|
|
8722
|
-
isConsentProvided = true;
|
|
8723
|
-
}
|
|
8724
|
-
else if (consentDataResult.ok) {
|
|
8725
|
-
const consentData = consentDataResult.data[visitorCode];
|
|
8726
|
-
// for consistency with the old data in the storage
|
|
8727
|
-
if (typeof consentData === 'boolean') {
|
|
8728
|
-
isConsentProvided = consentData;
|
|
8729
|
-
}
|
|
8730
|
-
else {
|
|
8731
|
-
isConsentProvided = consentData && consentData.consent;
|
|
8732
|
-
}
|
|
8733
|
-
}
|
|
8841
|
+
const isConsentProvided = !isConsentRequired ||
|
|
8842
|
+
this.getLegalConsent(visitorCode) == LegalConsent.Given;
|
|
8734
8843
|
KameleoonLogger.debug `RETURN: KameleoonClient._isConsentProvided(visitorCode: ${visitorCode}) -> (isConsentProvided: ${isConsentProvided})`;
|
|
8735
8844
|
return isConsentProvided;
|
|
8736
8845
|
}
|
|
@@ -8758,22 +8867,32 @@ class KameleoonClient {
|
|
|
8758
8867
|
if (!featureFlag.environmentEnabled) {
|
|
8759
8868
|
continue;
|
|
8760
8869
|
}
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
8764
|
-
|
|
8765
|
-
|
|
8766
|
-
|
|
8767
|
-
if (evalExp.variationKey !== OFF_VARIATION_KEY) {
|
|
8768
|
-
activeVariations.push({
|
|
8769
|
-
variationKey: evalExp.variationKey,
|
|
8770
|
-
variationId: evalExp.variationId,
|
|
8771
|
-
experimentId: evalExp.experimentId,
|
|
8772
|
-
featureFlagId: featureFlag.id,
|
|
8773
|
-
featureKey: featureFlag.featureKey,
|
|
8774
|
-
rule: null,
|
|
8775
|
-
isTargetedRule: evalExp.ruleType === RuleType.TARGETED_DELIVERY,
|
|
8870
|
+
try {
|
|
8871
|
+
const evalExp = this._evaluate({
|
|
8872
|
+
visitorCode,
|
|
8873
|
+
featureFlag,
|
|
8874
|
+
track: false,
|
|
8875
|
+
save: false,
|
|
8776
8876
|
});
|
|
8877
|
+
if (evalExp.variationKey !== OFF_VARIATION_KEY) {
|
|
8878
|
+
activeVariations.push({
|
|
8879
|
+
variationKey: evalExp.variationKey,
|
|
8880
|
+
variationId: evalExp.variationId,
|
|
8881
|
+
experimentId: evalExp.experimentId,
|
|
8882
|
+
featureFlagId: featureFlag.id,
|
|
8883
|
+
featureKey: featureFlag.featureKey,
|
|
8884
|
+
rule: null,
|
|
8885
|
+
isTargetedRule: evalExp.ruleType === RuleType.TARGETED_DELIVERY,
|
|
8886
|
+
});
|
|
8887
|
+
}
|
|
8888
|
+
}
|
|
8889
|
+
catch (err) {
|
|
8890
|
+
if (err instanceof KameleoonError) {
|
|
8891
|
+
if (err.type != exports.KameleoonException.FeatureFlagEnvironmentDisabled) {
|
|
8892
|
+
KameleoonLogger.error `Unexpected error: ${err}`;
|
|
8893
|
+
}
|
|
8894
|
+
continue;
|
|
8895
|
+
}
|
|
8777
8896
|
}
|
|
8778
8897
|
}
|
|
8779
8898
|
KameleoonLogger.debug `RETURN: KameleoonClient._getActiveFeatureVariations(visitorCode: ${visitorCode}) -> (activeVariations: ${activeVariations})`;
|
|
@@ -8794,6 +8913,7 @@ class KameleoonClient {
|
|
|
8794
8913
|
else if (this._isVisitorNotInHoldout(visitorCode, track, save, featureFlag, visitorData) &&
|
|
8795
8914
|
this._isFFUnrestrictedByMEGroup(visitorCode, featureFlag, visitorData)) {
|
|
8796
8915
|
const visitorIdentifier = this._getCodeForHash(visitorCode, featureFlag.bucketingCustomDataIndex, visitorData);
|
|
8916
|
+
const legalConsent = this.getLegalConsent(visitorCode);
|
|
8797
8917
|
const variationData = this.variationConfiguration
|
|
8798
8918
|
.getVariation({
|
|
8799
8919
|
visitorCode,
|
|
@@ -8805,6 +8925,7 @@ class KameleoonClient {
|
|
|
8805
8925
|
clientConfiguration: this.clientConfiguration,
|
|
8806
8926
|
dataManager: this.dataManager,
|
|
8807
8927
|
packageInfo: this.externalPackageInfo,
|
|
8928
|
+
legalConsent,
|
|
8808
8929
|
})
|
|
8809
8930
|
.throw();
|
|
8810
8931
|
evalExp =
|
|
@@ -8923,6 +9044,14 @@ class KameleoonClient {
|
|
|
8923
9044
|
}
|
|
8924
9045
|
KameleoonLogger.debug `CALL: KameleoonClient._isVisitorNotInHoldout(visitorCode: ${visitorCode}, track: ${track}, save: ${save}, featureFlag: ${featureFlag}, visitorData: ${visitorData})`;
|
|
8925
9046
|
let isNotInHoldout = true;
|
|
9047
|
+
// Checking if the evaluation is blocked due to the consent policy
|
|
9048
|
+
const legalConsent = this.getLegalConsent(visitorCode);
|
|
9049
|
+
if (legalConsent == LegalConsent.NotGiven) {
|
|
9050
|
+
const behaviour = this.clientConfiguration.consentBlockingBehaviour;
|
|
9051
|
+
if (behaviour == ConsentBlockingBehaviour.CompletelyBlocked) {
|
|
9052
|
+
throw new KameleoonError(exports.KameleoonException.FeatureFlagEnvironmentDisabled, `Evaluation of holdout is blocked because consent is not provided for visitor '${visitorCode}'`);
|
|
9053
|
+
}
|
|
9054
|
+
}
|
|
8926
9055
|
const codeForHash = this._getCodeForHash(visitorCode, featureFlag === null || featureFlag === void 0 ? void 0 : featureFlag.bucketingCustomDataIndex, visitorData);
|
|
8927
9056
|
const holdoutHash = Hasher.getHashDouble({
|
|
8928
9057
|
visitorIdentifier: codeForHash,
|