@kameleoon/javascript-sdk-core 5.14.5 → 5.16.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 CHANGED
@@ -1,5 +1,28 @@
1
1
  # Change Log
2
2
 
3
+ ## 5.16.0 (2025-10-22)
4
+
5
+ ### Minor Changes
6
+
7
+ - Introduced a new [`getDataFile`](getDataFile) method. This method returns the current SDK configuration (also known as the **data file**) used for evaluation and targeting. It is **not** intended for production use to fetch variations for every feature flag in the returned list, as it is not optimized for performance. For that purpose, use [`getVariations`](getVariations) instead. `getDataFile` is mainly useful for debugging or QA, for example to let internal users manually select a variant for a specific feature flag in production.
8
+
9
+ ### Patch Changes
10
+
11
+ - Addressed an issue where tracking data was sent for visitors who had not provided [consent](setLegalConsent).
12
+
13
+ [setLegalConsent]: https://developers.kameleoon.com/feature-management-and-experimentation/web-sdks/js-sdk#setLegalConsent
14
+ [getDataFile]: https://developers.kameleoon.com/feature-management-and-experimentation/web-sdks/js-sdk#getdatafile
15
+
16
+ ## 5.15.0 (2025-09-01)
17
+
18
+ > [!WARNING]
19
+ > If you're upgrading from a version earlier than 5.14.0 and run into any unexpected build or SDK-related issues, please reach out to the Kameleoon Support Team. We're here to ensure your transition is smooth and will promptly address any concerns.
20
+
21
+ ### Features
22
+
23
+ - Added an `overwrite` flag to [`CustomData`](CustomData), used as the `overwrite` parameter during tracking.
24
+ - [`CustomData`](CustomData) can now be created using a `name`, in addition to the existing method of using an `index`.
25
+
3
26
  ## 5.14.5 (2025-08-20)
4
27
 
5
28
  > [!WARNING]
package/dist/browser.d.ts CHANGED
@@ -23,3 +23,4 @@ export { MappingIdentifierType } from './storage/types';
23
23
  export { CustomDataConfigurationType, CustomDataScope, } from './clientConfiguration';
24
24
  export { ListUtilities, Utilities } from './utilities';
25
25
  export { BrowserDataType, CustomDataType, DataFilterType, DataManagerParametersType, DeviceDataType, GeolocationDataType, KameleoonVisitorDataType, MutUpdateTargetingDataParametersType, OperatingSystemDataType, PageViewDataType, ProcessCustomDataManagerParametersType, VisitDataType, VisitorsDataType, } from './kameleoonData/types';
26
+ export { FeatureFlag, Rule, DataFile, Variable, Variation } from './types';
@@ -70,6 +70,7 @@ export type ExperimentType = {
70
70
  variationByExposition: VariationByExpositionType[];
71
71
  };
72
72
  export type FeatureVariationType = {
73
+ name?: string;
73
74
  key: string;
74
75
  variables: FeatureVariableType[];
75
76
  };
@@ -119,6 +120,7 @@ export type ClientConfigurationDataType = Omit<ConfigurationDataType, 'featureFl
119
120
  export type CustomDataConfigurationType = {
120
121
  id?: number;
121
122
  index: number;
123
+ name?: string;
122
124
  localOnly: boolean;
123
125
  isMappingIdentifier: boolean;
124
126
  scope: CustomDataScope;
package/dist/index.d.ts CHANGED
@@ -23,3 +23,4 @@ export { MappingIdentifierType } from './storage/types';
23
23
  export { CustomDataConfigurationType, CustomDataScope, } from './clientConfiguration';
24
24
  export { ListUtilities, Utilities } from './utilities';
25
25
  export { BrowserDataType, CustomDataType, DataFilterType, DataManagerParametersType, DeviceDataType, GeolocationDataType, KameleoonVisitorDataType, MutUpdateTargetingDataParametersType, OperatingSystemDataType, PageViewDataType, ProcessCustomDataManagerParametersType, VisitDataType, VisitorsDataType, } from './kameleoonData/types';
26
+ export { FeatureFlag, Rule, DataFile, Variable, Variation } from './types';
@@ -2296,25 +2296,22 @@ class PageView {
2296
2296
  * CustomData - a class for creating an instance for user's custom data
2297
2297
  * */
2298
2298
  let CustomData$1 = class CustomData {
2299
- /**
2300
- * @param {number} index - an index of custom data to be stored under in a state, an index of custom data can be specified in `Advanced Tools` section of Kameleoon Application
2301
- * @param {string[]} value - custom value to store under the specified id, value can be anything but has to be stringified to match the `string` type. *Note* value is variadic parameter and can be used as follows
2302
- * @example
2303
- * ```ts
2304
- * // - Single value
2305
- * const customData = new CustomData(0, 'value_1');
2306
- * // - Variadic number of values
2307
- * const customData = new CustomData(0, 'value_1', 'value_2', 'value_3');
2308
- * // - Array of values
2309
- * const values = ['value_1', 'value_2', 'value_3'];
2310
- * const customData = new CustomData(0, ...values);
2311
- * ```
2312
- * */
2313
- constructor(index, ...value) {
2314
- this.index = index;
2315
- this.value = value;
2299
+ constructor(first, second, ...rest) {
2316
2300
  this._status = exports.TrackingStatus.Unsent;
2317
2301
  this.isIdentifier = false;
2302
+ const isNumber = typeof first === 'number';
2303
+ const isBoolean = typeof second === 'boolean';
2304
+ if (isNumber) {
2305
+ this.index = first;
2306
+ }
2307
+ else {
2308
+ this.name = first;
2309
+ this.index = -1;
2310
+ }
2311
+ this.overwrite = isBoolean ? second : true;
2312
+ this.value = isBoolean
2313
+ ? rest
2314
+ : [second, ...rest].filter((v) => v != null);
2318
2315
  }
2319
2316
  get url() {
2320
2317
  // --- Note ---
@@ -2341,17 +2338,11 @@ let CustomData$1 = class CustomData {
2341
2338
  UrlParameter.ValuesCountMap +
2342
2339
  encodeURIComponent(JSON.stringify(resultValue)) +
2343
2340
  UrlParameter.Overwrite +
2344
- String(true) +
2341
+ String(this.overwrite) +
2345
2342
  identifierParameter);
2346
2343
  }
2347
2344
  get data() {
2348
- return {
2349
- index: this.index,
2350
- value: this.value,
2351
- type: exports.KameleoonData.CustomData,
2352
- isIdentifier: this.isIdentifier,
2353
- status: this.status,
2354
- };
2345
+ 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 });
2355
2346
  }
2356
2347
  get status() {
2357
2348
  if (this._isMappingIdentifier) {
@@ -2366,8 +2357,15 @@ let CustomData$1 = class CustomData {
2366
2357
  * @return {CustomData} a CustomData instance
2367
2358
  * */
2368
2359
  static _fromRaw(data) {
2369
- const { index, value, status, isIdentifier } = data;
2370
- const customData = new CustomData(index, ...value);
2360
+ const { index, value, status, isIdentifier, name, overwrite } = data;
2361
+ let customData;
2362
+ if (name) {
2363
+ customData = new CustomData(name, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
2364
+ customData._index = index;
2365
+ }
2366
+ else {
2367
+ customData = new CustomData(index, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
2368
+ }
2371
2369
  customData.status = status;
2372
2370
  customData._isMappingIdentifier = isIdentifier;
2373
2371
  return customData;
@@ -2398,6 +2396,14 @@ let CustomData$1 = class CustomData {
2398
2396
  }
2399
2397
  }
2400
2398
  }
2399
+ /**
2400
+ * @private
2401
+ * @method _index - an internal setter for setting index of custom data
2402
+ * @param {number} value - an index value
2403
+ * */
2404
+ set _index(value) {
2405
+ this.index = value;
2406
+ }
2401
2407
  };
2402
2408
 
2403
2409
  /**
@@ -5143,7 +5149,7 @@ class ConditionFactory {
5143
5149
  case TargetingType.HEAT_SLICE:
5144
5150
  return buildExports.Ok(new ConversionLikelihood(data));
5145
5151
  default:
5146
- KameleoonLogger.error `Unsupported targeted condition type found: ${targetingType}`;
5152
+ KameleoonLogger.info `Unsupported targeted condition type found: ${targetingType}`;
5147
5153
  return buildExports.Err(new KameleoonError(exports.KameleoonException.TargetingCondition, targetingType));
5148
5154
  }
5149
5155
  }
@@ -5532,6 +5538,7 @@ class DataManager {
5532
5538
  this.mappingIdentifierCustomDataIndex = null;
5533
5539
  this.persistentCustomDataIndexes = new Set();
5534
5540
  this.localCustomDataIndexes = new Set();
5541
+ this.customDataIndexByName = new Map();
5535
5542
  this.cleanupIntervalId = null;
5536
5543
  KameleoonLogger.debug `CALL: new DataManager(dataStorage, infoStorage, cleanupInterval: ${cleanupInterval})`;
5537
5544
  this.dataStorage = dataStorage;
@@ -5866,12 +5873,15 @@ class DataManager {
5866
5873
  mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, }) {
5867
5874
  for (const dataItem of kameleoonData) {
5868
5875
  if (dataItem.data.type === exports.KameleoonData.CustomData) {
5869
- this.processCustomData({
5876
+ const customDataIsValid = this.processCustomData({
5870
5877
  infoData,
5871
5878
  customData: dataItem,
5872
5879
  mutData: targetingData,
5873
5880
  visitorCode,
5874
5881
  });
5882
+ if (!customDataIsValid) {
5883
+ continue;
5884
+ }
5875
5885
  }
5876
5886
  const expirationTime = this.dataProcessor.mutUpdateData({
5877
5887
  infoData,
@@ -5912,6 +5922,14 @@ class DataManager {
5912
5922
  var _a;
5913
5923
  const { data } = customData;
5914
5924
  const isDataValid = Boolean(data.value.length && data.value[0].length);
5925
+ if (data.name) {
5926
+ const cdIndex = this.customDataIndexByName.get(data.name);
5927
+ if (cdIndex === undefined) {
5928
+ return false;
5929
+ }
5930
+ data.index = cdIndex;
5931
+ customData._index = cdIndex;
5932
+ }
5915
5933
  if (this.mappingIdentifierCustomDataIndex === data.index && isDataValid) {
5916
5934
  customData._isMappingIdentifier = true;
5917
5935
  const userId = data.value[0];
@@ -5935,6 +5953,7 @@ class DataManager {
5935
5953
  if (this.localCustomDataIndexes.has(data.index)) {
5936
5954
  customData.status = exports.TrackingStatus.Sent;
5937
5955
  }
5956
+ return true;
5938
5957
  }
5939
5958
  get unsentDataVisitors() {
5940
5959
  const infoResult = this.infoStorage.read();
@@ -5967,6 +5986,7 @@ class DataManager {
5967
5986
  set customDataIndexes(customData) {
5968
5987
  var _a;
5969
5988
  const [customDataLocalOnlyIndexes, persistentCustomDataIndexes] = [[], []];
5989
+ const customDataIndexByName = new Map();
5970
5990
  customData.forEach((customData) => {
5971
5991
  if (customData.localOnly) {
5972
5992
  customDataLocalOnlyIndexes.push(customData.index);
@@ -5974,12 +5994,19 @@ class DataManager {
5974
5994
  if (customData.scope === exports.CustomDataScope.Visitor) {
5975
5995
  persistentCustomDataIndexes.push(customData.index);
5976
5996
  }
5997
+ if (customData.name) {
5998
+ customDataIndexByName.set(customData.name, customData.index);
5999
+ }
5977
6000
  });
5978
6001
  this.mappingIdentifierCustomDataIndex =
5979
6002
  ((_a = customData.find((customData) => customData.isMappingIdentifier)) === null || _a === void 0 ? void 0 : _a.index) ||
5980
6003
  null;
5981
6004
  this.localCustomDataIndexes = new Set(customDataLocalOnlyIndexes);
5982
6005
  this.persistentCustomDataIndexes = new Set(persistentCustomDataIndexes);
6006
+ this.customDataIndexByName = customDataIndexByName;
6007
+ }
6008
+ getCustomDataIndexByName(name) {
6009
+ return this.customDataIndexByName.get(name);
5983
6010
  }
5984
6011
  }
5985
6012
 
@@ -7780,7 +7807,7 @@ class BodyProvider {
7780
7807
  const identifier = isMappingIdentifier
7781
7808
  ? UrlParameter.MappingValue
7782
7809
  : UrlParameter.VisitorCode;
7783
- return identifier + visitorCode;
7810
+ return identifier + encodeURIComponent(visitorCode);
7784
7811
  }
7785
7812
  }
7786
7813
 
@@ -8364,6 +8391,7 @@ class KameleoonClient {
8364
8391
  }
8365
8392
  const resultVariables = variables.map((variable) => Parser.parseFeatureVariable(variable).throw());
8366
8393
  resultFeatureList.set(variation.featureKey, {
8394
+ name: '',
8367
8395
  key: variationKey,
8368
8396
  id: variationId,
8369
8397
  experimentId,
@@ -8584,6 +8612,62 @@ class KameleoonClient {
8584
8612
  this.flush(visitorCode);
8585
8613
  KameleoonLogger.info `RETURN: KameleoonClient.evaluateAudiences(visitorCode: ${visitorCode})`;
8586
8614
  }
8615
+ getDataFile() {
8616
+ const dataFile = {
8617
+ featureFlags: new Map(),
8618
+ };
8619
+ if (this.stubMode) {
8620
+ return dataFile;
8621
+ }
8622
+ KameleoonLogger.debug `CALL: KameleoonClient.getDataFile()`;
8623
+ this.clientConfiguration.featureFlags.forEach((featureFlag, key) => {
8624
+ const variationsMap = new Map();
8625
+ featureFlag.variations.forEach((sourceVariation) => {
8626
+ var _a;
8627
+ const variablesMap = new Map();
8628
+ sourceVariation.variables.forEach((variable) => {
8629
+ try {
8630
+ const parsedVariable = Parser.parseFeatureVariable(variable).throw();
8631
+ variablesMap.set(variable.key, parsedVariable);
8632
+ }
8633
+ catch (err) {
8634
+ KameleoonLogger.error `Error parsing variable ${variable.key} of feature flag ${featureFlag.featureKey}: ${err}`;
8635
+ }
8636
+ });
8637
+ variationsMap.set(sourceVariation.key, {
8638
+ name: (_a = sourceVariation.name) !== null && _a !== void 0 ? _a : '',
8639
+ key: sourceVariation.key,
8640
+ id: null,
8641
+ experimentId: null,
8642
+ variables: variablesMap,
8643
+ });
8644
+ });
8645
+ const rules = featureFlag.rules.map((rule) => {
8646
+ const ruleVariations = new Map();
8647
+ rule.variationByExposition.forEach((varByExp) => {
8648
+ const baseVariation = variationsMap.get(varByExp.variationKey);
8649
+ if (!baseVariation)
8650
+ return;
8651
+ ruleVariations.set(baseVariation.key, {
8652
+ name: baseVariation.name,
8653
+ key: baseVariation.key,
8654
+ id: varByExp.variationId,
8655
+ experimentId: rule.experimentId,
8656
+ variables: baseVariation.variables,
8657
+ });
8658
+ });
8659
+ return { variations: ruleVariations };
8660
+ });
8661
+ dataFile.featureFlags.set(key, {
8662
+ variations: variationsMap,
8663
+ environmentEnabled: featureFlag.environmentEnabled,
8664
+ rules,
8665
+ defaultVariationKey: featureFlag.defaultVariationKey,
8666
+ });
8667
+ });
8668
+ KameleoonLogger.debug `RETURN: KameleoonClient.getDataFile() -> (dataFile: ${dataFile})`;
8669
+ return dataFile;
8670
+ }
8587
8671
  setUserConsent({ visitorCode, consent, setData, }) {
8588
8672
  if (this.stubMode) {
8589
8673
  return;
@@ -8770,6 +8854,7 @@ class KameleoonClient {
8770
8854
  return selected;
8771
8855
  }
8772
8856
  _getFeatureVariation({ visitorCode, featureKey, track, }) {
8857
+ var _a, _b;
8773
8858
  KameleoonLogger.debug `CALL: KameleoonClient._getFeatureVariation(visitorCode: ${visitorCode}, featureKey: ${featureKey}, track: ${track})`;
8774
8859
  if (!this.initialized) {
8775
8860
  return buildExports.Err(new KameleoonError(exports.KameleoonException.Initialization));
@@ -8820,7 +8905,9 @@ class KameleoonClient {
8820
8905
  if (track && !isSimulated) {
8821
8906
  this.tracker.scheduleVisitor(visitorCode, this._isConsentProvided(visitorCode));
8822
8907
  }
8908
+ const variationName = (_b = (_a = featureFlag.variations.find((item) => item.key === variationKey)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
8823
8909
  const resultData = {
8910
+ name: variationName,
8824
8911
  key: variationKey,
8825
8912
  id: variationId,
8826
8913
  experimentId,