@kameleoon/javascript-sdk-core 5.15.0 → 5.16.1

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,24 @@
1
1
  # Change Log
2
2
 
3
+ ## 5.16.1 (2025-10-23)
4
+
5
+ ### Patch Changes
6
+
7
+ - Fixed an issue where [`Conversion`](Conversion) metadata initialized with a name was not tracked.
8
+
9
+ ## 5.16.0 (2025-10-22)
10
+
11
+ ### Minor Changes
12
+
13
+ - 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.
14
+
15
+ ### Patch Changes
16
+
17
+ - Addressed an issue where tracking data was sent for visitors who had not provided [consent](setLegalConsent).
18
+
19
+ [setLegalConsent]: https://developers.kameleoon.com/feature-management-and-experimentation/web-sdks/js-sdk#setLegalConsent
20
+ [getDataFile]: https://developers.kameleoon.com/feature-management-and-experimentation/web-sdks/js-sdk#getdatafile
21
+
3
22
  ## 5.15.0 (2025-09-01)
4
23
 
5
24
  > [!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
  };
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';
@@ -2302,11 +2302,11 @@ let CustomData$1 = class CustomData {
2302
2302
  const isNumber = typeof first === 'number';
2303
2303
  const isBoolean = typeof second === 'boolean';
2304
2304
  if (isNumber) {
2305
- this.index = first;
2305
+ this._index = first;
2306
2306
  }
2307
2307
  else {
2308
- this.name = first;
2309
- this.index = -1;
2308
+ this._name = first;
2309
+ this._index = CustomData.UNDEFINED_INDEX;
2310
2310
  }
2311
2311
  this.overwrite = isBoolean ? second : true;
2312
2312
  this.value = isBoolean
@@ -2317,7 +2317,7 @@ let CustomData$1 = class CustomData {
2317
2317
  // --- Note ---
2318
2318
  // If SDK is used in vanilla JS codebase, then you're also able to create an instance
2319
2319
  // with no required data, we don't want send anything to tracking in that case
2320
- if (typeof this.index !== 'number') {
2320
+ if (typeof this._index !== 'number') {
2321
2321
  return '';
2322
2322
  }
2323
2323
  const uniqueValues = [...new Set(this.value)];
@@ -2334,7 +2334,7 @@ let CustomData$1 = class CustomData {
2334
2334
  }
2335
2335
  return (UrlEventType.CustomData +
2336
2336
  UrlParameter.Index +
2337
- this.index +
2337
+ this._index +
2338
2338
  UrlParameter.ValuesCountMap +
2339
2339
  encodeURIComponent(JSON.stringify(resultValue)) +
2340
2340
  UrlParameter.Overwrite +
@@ -2342,7 +2342,7 @@ let CustomData$1 = class CustomData {
2342
2342
  identifierParameter);
2343
2343
  }
2344
2344
  get data() {
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 });
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 });
2346
2346
  }
2347
2347
  get status() {
2348
2348
  if (this._isMappingIdentifier) {
@@ -2361,7 +2361,7 @@ let CustomData$1 = class CustomData {
2361
2361
  let customData;
2362
2362
  if (name) {
2363
2363
  customData = new CustomData(name, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
2364
- customData._index = index;
2364
+ customData.index = index;
2365
2365
  }
2366
2366
  else {
2367
2367
  customData = new CustomData(index, overwrite !== null && overwrite !== void 0 ? overwrite : true, ...value);
@@ -2398,13 +2398,28 @@ let CustomData$1 = class CustomData {
2398
2398
  }
2399
2399
  /**
2400
2400
  * @private
2401
- * @method _index - an internal setter for setting index of custom data
2401
+ * @method index - an internal setter for setting index of custom data
2402
2402
  * @param {number} value - an index value
2403
2403
  * */
2404
- set _index(value) {
2405
- this.index = value;
2404
+ set index(value) {
2405
+ this._index = value;
2406
+ }
2407
+ /**
2408
+ * @private
2409
+ * @method index - an internal getter for index of custom data
2410
+ * */
2411
+ get index() {
2412
+ return this._index;
2413
+ }
2414
+ /**
2415
+ * @private
2416
+ * @method name - an internal getter for a name of custom data
2417
+ * */
2418
+ get name() {
2419
+ return this._name;
2406
2420
  }
2407
2421
  };
2422
+ CustomData$1.UNDEFINED_INDEX = -1;
2408
2423
 
2409
2424
  /**
2410
2425
  * @class
@@ -2441,6 +2456,9 @@ let Conversion$1 = class Conversion {
2441
2456
  ? UrlParameter.Metadata + this._encodeMetadata()
2442
2457
  : ''));
2443
2458
  }
2459
+ get _metadata() {
2460
+ return this.metadata;
2461
+ }
2444
2462
  get data() {
2445
2463
  var _a;
2446
2464
  return {
@@ -5149,7 +5167,7 @@ class ConditionFactory {
5149
5167
  case TargetingType.HEAT_SLICE:
5150
5168
  return buildExports.Ok(new ConversionLikelihood(data));
5151
5169
  default:
5152
- KameleoonLogger.error `Unsupported targeted condition type found: ${targetingType}`;
5170
+ KameleoonLogger.info `Unsupported targeted condition type found: ${targetingType}`;
5153
5171
  return buildExports.Err(new KameleoonError(exports.KameleoonException.TargetingCondition, targetingType));
5154
5172
  }
5155
5173
  }
@@ -5871,7 +5889,9 @@ class DataManager {
5871
5889
  return null;
5872
5890
  }
5873
5891
  mutUpdateTargetingData({ infoData, visitorCode, kameleoonData, targetingData, }) {
5892
+ var _a;
5874
5893
  for (const dataItem of kameleoonData) {
5894
+ // process custom data
5875
5895
  if (dataItem.data.type === exports.KameleoonData.CustomData) {
5876
5896
  const customDataIsValid = this.processCustomData({
5877
5897
  infoData,
@@ -5883,6 +5903,10 @@ class DataManager {
5883
5903
  continue;
5884
5904
  }
5885
5905
  }
5906
+ // process metadata of conversions
5907
+ if (dataItem.data.type === exports.KameleoonData.Conversion) {
5908
+ (_a = dataItem._metadata) === null || _a === void 0 ? void 0 : _a.forEach((item) => this.trySetCustomDataIndexByName(item));
5909
+ }
5886
5910
  const expirationTime = this.dataProcessor.mutUpdateData({
5887
5911
  infoData,
5888
5912
  visitorCode,
@@ -5922,13 +5946,9 @@ class DataManager {
5922
5946
  var _a;
5923
5947
  const { data } = customData;
5924
5948
  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;
5949
+ this.trySetCustomDataIndexByName(customData);
5950
+ if (data.index == CustomData$1.UNDEFINED_INDEX) {
5951
+ data.index = customData.index;
5932
5952
  }
5933
5953
  if (this.mappingIdentifierCustomDataIndex === data.index && isDataValid) {
5934
5954
  customData._isMappingIdentifier = true;
@@ -5955,6 +5975,15 @@ class DataManager {
5955
5975
  }
5956
5976
  return true;
5957
5977
  }
5978
+ trySetCustomDataIndexByName(customData) {
5979
+ if (customData.index == CustomData$1.UNDEFINED_INDEX && customData.name) {
5980
+ const cdIndex = this.customDataIndexByName.get(customData.name);
5981
+ if (cdIndex === undefined) {
5982
+ return;
5983
+ }
5984
+ customData.index = cdIndex;
5985
+ }
5986
+ }
5958
5987
  get unsentDataVisitors() {
5959
5988
  const infoResult = this.infoStorage.read();
5960
5989
  if (!infoResult.ok) {
@@ -7807,7 +7836,7 @@ class BodyProvider {
7807
7836
  const identifier = isMappingIdentifier
7808
7837
  ? UrlParameter.MappingValue
7809
7838
  : UrlParameter.VisitorCode;
7810
- return identifier + visitorCode;
7839
+ return identifier + encodeURIComponent(visitorCode);
7811
7840
  }
7812
7841
  }
7813
7842
 
@@ -8391,6 +8420,7 @@ class KameleoonClient {
8391
8420
  }
8392
8421
  const resultVariables = variables.map((variable) => Parser.parseFeatureVariable(variable).throw());
8393
8422
  resultFeatureList.set(variation.featureKey, {
8423
+ name: '',
8394
8424
  key: variationKey,
8395
8425
  id: variationId,
8396
8426
  experimentId,
@@ -8611,6 +8641,62 @@ class KameleoonClient {
8611
8641
  this.flush(visitorCode);
8612
8642
  KameleoonLogger.info `RETURN: KameleoonClient.evaluateAudiences(visitorCode: ${visitorCode})`;
8613
8643
  }
8644
+ getDataFile() {
8645
+ const dataFile = {
8646
+ featureFlags: new Map(),
8647
+ };
8648
+ if (this.stubMode) {
8649
+ return dataFile;
8650
+ }
8651
+ KameleoonLogger.debug `CALL: KameleoonClient.getDataFile()`;
8652
+ this.clientConfiguration.featureFlags.forEach((featureFlag, key) => {
8653
+ const variationsMap = new Map();
8654
+ featureFlag.variations.forEach((sourceVariation) => {
8655
+ var _a;
8656
+ const variablesMap = new Map();
8657
+ sourceVariation.variables.forEach((variable) => {
8658
+ try {
8659
+ const parsedVariable = Parser.parseFeatureVariable(variable).throw();
8660
+ variablesMap.set(variable.key, parsedVariable);
8661
+ }
8662
+ catch (err) {
8663
+ KameleoonLogger.error `Error parsing variable ${variable.key} of feature flag ${featureFlag.featureKey}: ${err}`;
8664
+ }
8665
+ });
8666
+ variationsMap.set(sourceVariation.key, {
8667
+ name: (_a = sourceVariation.name) !== null && _a !== void 0 ? _a : '',
8668
+ key: sourceVariation.key,
8669
+ id: null,
8670
+ experimentId: null,
8671
+ variables: variablesMap,
8672
+ });
8673
+ });
8674
+ const rules = featureFlag.rules.map((rule) => {
8675
+ const ruleVariations = new Map();
8676
+ rule.variationByExposition.forEach((varByExp) => {
8677
+ const baseVariation = variationsMap.get(varByExp.variationKey);
8678
+ if (!baseVariation)
8679
+ return;
8680
+ ruleVariations.set(baseVariation.key, {
8681
+ name: baseVariation.name,
8682
+ key: baseVariation.key,
8683
+ id: varByExp.variationId,
8684
+ experimentId: rule.experimentId,
8685
+ variables: baseVariation.variables,
8686
+ });
8687
+ });
8688
+ return { variations: ruleVariations };
8689
+ });
8690
+ dataFile.featureFlags.set(key, {
8691
+ variations: variationsMap,
8692
+ environmentEnabled: featureFlag.environmentEnabled,
8693
+ rules,
8694
+ defaultVariationKey: featureFlag.defaultVariationKey,
8695
+ });
8696
+ });
8697
+ KameleoonLogger.debug `RETURN: KameleoonClient.getDataFile() -> (dataFile: ${dataFile})`;
8698
+ return dataFile;
8699
+ }
8614
8700
  setUserConsent({ visitorCode, consent, setData, }) {
8615
8701
  if (this.stubMode) {
8616
8702
  return;
@@ -8797,6 +8883,7 @@ class KameleoonClient {
8797
8883
  return selected;
8798
8884
  }
8799
8885
  _getFeatureVariation({ visitorCode, featureKey, track, }) {
8886
+ var _a, _b;
8800
8887
  KameleoonLogger.debug `CALL: KameleoonClient._getFeatureVariation(visitorCode: ${visitorCode}, featureKey: ${featureKey}, track: ${track})`;
8801
8888
  if (!this.initialized) {
8802
8889
  return buildExports.Err(new KameleoonError(exports.KameleoonException.Initialization));
@@ -8847,7 +8934,9 @@ class KameleoonClient {
8847
8934
  if (track && !isSimulated) {
8848
8935
  this.tracker.scheduleVisitor(visitorCode, this._isConsentProvided(visitorCode));
8849
8936
  }
8937
+ const variationName = (_b = (_a = featureFlag.variations.find((item) => item.key === variationKey)) === null || _a === void 0 ? void 0 : _a.name) !== null && _b !== void 0 ? _b : '';
8850
8938
  const resultData = {
8939
+ name: variationName,
8851
8940
  key: variationKey,
8852
8941
  id: variationId,
8853
8942
  experimentId,