@splitsoftware/splitio-commons 2.1.0-rc.0 → 2.1.0-rc.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/CHANGES.txt CHANGED
@@ -1,3 +1,10 @@
1
+ 2.1.0 (January XX, 2025)
2
+ - Added two new configuration options for the SDK storage in browsers when using storage type `LOCALSTORAGE`:
3
+ - `storage.expirationDays` to specify the validity period of the rollout cache.
4
+ - `storage.clearOnInit` to clear the rollout cache on SDK initialization.
5
+ - Updated SDK_READY_FROM_CACHE event when using `LOCALSTORAGE` storage type to be emitted alongside SDK_READY event in case it has not been emitted.
6
+ - Bugfixing - Properly handle rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages).
7
+
1
8
  2.0.2 (December 3, 2024)
2
9
  - Updated the factory `init` and `destroy` methods to support re-initialization after destruction. This update ensures compatibility of the React SDK with React Strict Mode, where the factory's `init` and `destroy` effects are executed an extra time to validate proper resource cleanup.
3
10
  - Bugfixing - Sanitize the `SplitSDKMachineName` header value to avoid exceptions on HTTP/S requests when it contains non ISO-8859-1 characters (Related to issue https://github.com/splitio/javascript-client/issues/847).
@@ -1,15 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.largeSegmentMatcherContext = void 0;
4
- var thenable_1 = require("../../utils/promise/thenable");
5
4
  function largeSegmentMatcherContext(largeSegmentName, storage) {
6
5
  return function largeSegmentMatcher(key) {
7
6
  var isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
8
- if ((0, thenable_1.thenable)(isInLargeSegment)) {
9
- isInLargeSegment.then(function (result) {
10
- return result;
11
- });
12
- }
13
7
  return isInLargeSegment;
14
8
  };
15
9
  }
@@ -1,15 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.segmentMatcherContext = void 0;
4
- var thenable_1 = require("../../utils/promise/thenable");
5
4
  function segmentMatcherContext(segmentName, storage) {
6
5
  return function segmentMatcher(key) {
7
6
  var isInSegment = storage.segments.isInSegment(segmentName, key);
8
- if ((0, thenable_1.thenable)(isInSegment)) {
9
- isInSegment.then(function (result) {
10
- return result;
11
- });
12
- }
13
7
  return isInSegment;
14
8
  };
15
9
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.readinessManagerFactory = void 0;
4
4
  var objectAssign_1 = require("../utils/lang/objectAssign");
5
5
  var constants_1 = require("./constants");
6
+ var constants_2 = require("../utils/constants");
6
7
  function splitsEventEmitterFactory(EventEmitter) {
7
8
  var splitsEventEmitter = (0, objectAssign_1.objectAssign)(new EventEmitter(), {
8
9
  splitsArrived: false,
@@ -83,6 +84,7 @@ function readinessManagerFactory(EventEmitter, settings, splits, isShared) {
83
84
  }
84
85
  }
85
86
  function checkIsReadyOrUpdate(diff) {
87
+ var _a;
86
88
  if (isDestroyed)
87
89
  return;
88
90
  if (isReady) {
@@ -101,6 +103,10 @@ function readinessManagerFactory(EventEmitter, settings, splits, isShared) {
101
103
  isReady = true;
102
104
  try {
103
105
  syncLastUpdate();
106
+ if (!isReadyFromCache && ((_a = settings.storage) === null || _a === void 0 ? void 0 : _a.type) === constants_2.STORAGE_LOCALSTORAGE) {
107
+ isReadyFromCache = true;
108
+ gate.emit(constants_1.SDK_READY_FROM_CACHE);
109
+ }
104
110
  gate.emit(constants_1.SDK_READY);
105
111
  }
106
112
  catch (e) {
@@ -4,7 +4,6 @@ exports.validateCache = void 0;
4
4
  var lang_1 = require("../../utils/lang");
5
5
  var KeyBuilder_1 = require("../KeyBuilder");
6
6
  var constants_1 = require("./constants");
7
- // milliseconds in a day
8
7
  var DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
9
8
  var MILLIS_IN_A_DAY = 86400000;
10
9
  /**
@@ -36,7 +35,7 @@ function validateExpiration(options, settings, keys, currentTimestamp, isThereCa
36
35
  log.error(constants_1.LOG_PREFIX + e);
37
36
  }
38
37
  if (isThereCache) {
39
- log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
38
+ log.info(constants_1.LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
40
39
  return true;
41
40
  }
42
41
  return false; // No cache to clear
@@ -241,9 +241,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
241
241
  this.log.error(constants_1.LOG_PREFIX + this.redisError);
242
242
  return Promise.reject(this.redisError);
243
243
  }
244
- var splits = {};
245
244
  var keys = names.map(function (name) { return _this.keys.buildSplitKey(name); });
246
245
  return (_a = this.redis).mget.apply(_a, keys).then(function (splitDefinitions) {
246
+ var splits = {};
247
247
  names.forEach(function (name, idx) {
248
248
  var split = splitDefinitions[idx];
249
249
  splits[name] = split && JSON.parse(split);
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function largeSegmentMatcherContext(largeSegmentName, storage) {
3
2
  return function largeSegmentMatcher(key) {
4
3
  var isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
5
- if (thenable(isInLargeSegment)) {
6
- isInLargeSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInLargeSegment;
11
5
  };
12
6
  }
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function segmentMatcherContext(segmentName, storage) {
3
2
  return function segmentMatcher(key) {
4
3
  var isInSegment = storage.segments.isInSegment(segmentName, key);
5
- if (thenable(isInSegment)) {
6
- isInSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInSegment;
11
5
  };
12
6
  }
@@ -1,5 +1,6 @@
1
1
  import { objectAssign } from '../utils/lang/objectAssign';
2
2
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
3
+ import { STORAGE_LOCALSTORAGE } from '../utils/constants';
3
4
  function splitsEventEmitterFactory(EventEmitter) {
4
5
  var splitsEventEmitter = objectAssign(new EventEmitter(), {
5
6
  splitsArrived: false,
@@ -80,6 +81,7 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
80
81
  }
81
82
  }
82
83
  function checkIsReadyOrUpdate(diff) {
84
+ var _a;
83
85
  if (isDestroyed)
84
86
  return;
85
87
  if (isReady) {
@@ -98,6 +100,10 @@ export function readinessManagerFactory(EventEmitter, settings, splits, isShared
98
100
  isReady = true;
99
101
  try {
100
102
  syncLastUpdate();
103
+ if (!isReadyFromCache && ((_a = settings.storage) === null || _a === void 0 ? void 0 : _a.type) === STORAGE_LOCALSTORAGE) {
104
+ isReadyFromCache = true;
105
+ gate.emit(SDK_READY_FROM_CACHE);
106
+ }
101
107
  gate.emit(SDK_READY);
102
108
  }
103
109
  catch (e) {
@@ -1,7 +1,6 @@
1
1
  import { isFiniteNumber, isNaNNumber } from '../../utils/lang';
2
2
  import { getStorageHash } from '../KeyBuilder';
3
3
  import { LOG_PREFIX } from './constants';
4
- // milliseconds in a day
5
4
  var DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
6
5
  var MILLIS_IN_A_DAY = 86400000;
7
6
  /**
@@ -33,7 +32,7 @@ function validateExpiration(options, settings, keys, currentTimestamp, isThereCa
33
32
  log.error(LOG_PREFIX + e);
34
33
  }
35
34
  if (isThereCache) {
36
- log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
35
+ log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
37
36
  return true;
38
37
  }
39
38
  return false; // No cache to clear
@@ -238,9 +238,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
238
238
  this.log.error(LOG_PREFIX + this.redisError);
239
239
  return Promise.reject(this.redisError);
240
240
  }
241
- var splits = {};
242
241
  var keys = names.map(function (name) { return _this.keys.buildSplitKey(name); });
243
242
  return (_a = this.redis).mget.apply(_a, keys).then(function (splitDefinitions) {
243
+ var splits = {};
244
244
  names.forEach(function (name, idx) {
245
245
  var split = splitDefinitions[idx];
246
246
  splits[name] = split && JSON.parse(split);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.1.0-rc.0",
3
+ "version": "2.1.0-rc.1",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -1,18 +1,11 @@
1
1
  import { MaybeThenable } from '../../dtos/types';
2
2
  import { ISegmentsCacheBase } from '../../storages/types';
3
- import { thenable } from '../../utils/promise/thenable';
4
3
 
5
4
  export function largeSegmentMatcherContext(largeSegmentName: string, storage: { largeSegments?: ISegmentsCacheBase }) {
6
5
 
7
6
  return function largeSegmentMatcher(key: string): MaybeThenable<boolean> {
8
7
  const isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
9
8
 
10
- if (thenable(isInLargeSegment)) {
11
- isInLargeSegment.then(result => {
12
- return result;
13
- });
14
- }
15
-
16
9
  return isInLargeSegment;
17
10
  };
18
11
  }
@@ -1,18 +1,11 @@
1
1
  import { MaybeThenable } from '../../dtos/types';
2
2
  import { ISegmentsCacheBase } from '../../storages/types';
3
- import { thenable } from '../../utils/promise/thenable';
4
3
 
5
4
  export function segmentMatcherContext(segmentName: string, storage: { segments: ISegmentsCacheBase }) {
6
5
 
7
6
  return function segmentMatcher(key: string): MaybeThenable<boolean> {
8
7
  const isInSegment = storage.segments.isInSegment(segmentName, key);
9
8
 
10
- if (thenable(isInSegment)) {
11
- isInSegment.then(result => {
12
- return result;
13
- });
14
- }
15
-
16
9
  return isInSegment;
17
10
  };
18
11
  }
@@ -3,6 +3,7 @@ import { ISettings } from '../types';
3
3
  import SplitIO from '../../types/splitio';
4
4
  import { SDK_SPLITS_ARRIVED, SDK_SPLITS_CACHE_LOADED, SDK_SEGMENTS_ARRIVED, SDK_READY_TIMED_OUT, SDK_READY_FROM_CACHE, SDK_UPDATE, SDK_READY } from './constants';
5
5
  import { IReadinessEventEmitter, IReadinessManager, ISegmentsEventEmitter, ISplitsEventEmitter } from './types';
6
+ import { STORAGE_LOCALSTORAGE } from '../utils/constants';
6
7
 
7
8
  function splitsEventEmitterFactory(EventEmitter: new () => SplitIO.IEventEmitter): ISplitsEventEmitter {
8
9
  const splitsEventEmitter = objectAssign(new EventEmitter(), {
@@ -114,6 +115,10 @@ export function readinessManagerFactory(
114
115
  isReady = true;
115
116
  try {
116
117
  syncLastUpdate();
118
+ if (!isReadyFromCache && settings.storage?.type === STORAGE_LOCALSTORAGE) {
119
+ isReadyFromCache = true;
120
+ gate.emit(SDK_READY_FROM_CACHE);
121
+ }
117
122
  gate.emit(SDK_READY);
118
123
  } catch (e) {
119
124
  // throws user callback exceptions in next tick
@@ -7,7 +7,6 @@ import type { MySegmentsCacheInLocal } from './MySegmentsCacheInLocal';
7
7
  import { KeyBuilderCS } from '../KeyBuilderCS';
8
8
  import SplitIO from '../../../types/splitio';
9
9
 
10
- // milliseconds in a day
11
10
  const DEFAULT_CACHE_EXPIRATION_IN_DAYS = 10;
12
11
  const MILLIS_IN_A_DAY = 86400000;
13
12
 
@@ -42,7 +41,7 @@ function validateExpiration(options: SplitIO.InLocalStorageOptions, settings: IS
42
41
  log.error(LOG_PREFIX + e);
43
42
  }
44
43
  if (isThereCache) {
45
- log.info(LOG_PREFIX + 'SDK key, flags filter criteria or flags spec version has changed. Cleaning up cache');
44
+ log.info(LOG_PREFIX + 'SDK key, flags filter criteria, or flags spec version has changed. Cleaning up cache');
46
45
  return true;
47
46
  }
48
47
  return false; // No cache to clear
@@ -266,10 +266,10 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
266
266
  return Promise.reject(this.redisError);
267
267
  }
268
268
 
269
- const splits: Record<string, ISplit | null> = {};
270
269
  const keys = names.map(name => this.keys.buildSplitKey(name));
271
270
  return this.redis.mget(...keys)
272
271
  .then(splitDefinitions => {
272
+ const splits: Record<string, ISplit | null> = {};
273
273
  names.forEach((name, idx) => {
274
274
  const split = splitDefinitions[idx];
275
275
  splits[name] = split && JSON.parse(split);