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