@splitsoftware/splitio-commons 3.0.1-rc.1 → 3.0.1-rc.3

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.
Files changed (33) hide show
  1. package/CHANGES.txt +3 -0
  2. package/cjs/evaluator/condition/index.js +1 -1
  3. package/cjs/services/serviceApi.js +2 -2
  4. package/cjs/services/splitApi.js +2 -2
  5. package/cjs/sync/polling/pollingManagerCS.js +1 -1
  6. package/cjs/sync/polling/pollingManagerSS.js +1 -1
  7. package/cjs/sync/polling/syncTasks/definitionsSyncTask.js +3 -2
  8. package/cjs/sync/polling/updaters/definitionChangesUpdater.js +4 -13
  9. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  10. package/cjs/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +1 -4
  11. package/cjs/sync/streaming/pushManager.js +1 -1
  12. package/esm/evaluator/condition/index.js +1 -1
  13. package/esm/services/serviceApi.js +2 -2
  14. package/esm/services/splitApi.js +2 -2
  15. package/esm/sync/polling/pollingManagerCS.js +1 -1
  16. package/esm/sync/polling/pollingManagerSS.js +1 -1
  17. package/esm/sync/polling/syncTasks/definitionsSyncTask.js +3 -2
  18. package/esm/sync/polling/updaters/definitionChangesUpdater.js +4 -13
  19. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  20. package/esm/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +1 -4
  21. package/esm/sync/streaming/pushManager.js +1 -1
  22. package/package.json +1 -1
  23. package/src/dtos/types.ts +1 -1
  24. package/src/evaluator/condition/index.ts +3 -3
  25. package/src/services/serviceApi.ts +2 -2
  26. package/src/services/splitApi.ts +2 -2
  27. package/src/sync/polling/pollingManagerCS.ts +1 -1
  28. package/src/sync/polling/pollingManagerSS.ts +1 -1
  29. package/src/sync/polling/syncTasks/definitionsSyncTask.ts +3 -3
  30. package/src/sync/polling/updaters/definitionChangesUpdater.ts +5 -15
  31. package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -2
  32. package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +2 -4
  33. package/src/sync/streaming/pushManager.ts +1 -1
package/CHANGES.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 3.1.0 (July XX, 2026)
2
+ - Added support for rule-based segments in /api/v1/configs endpoint.
3
+
1
4
  3.0.0 (June 26, 2026)
2
5
  - Extracted SDK lifecycle methods (`init`, `flush`, and `destroy`) into a reusable `sdkLifecycle` module.
3
6
  - Extracted the `track` method into a standalone `trackMethod` factory for reuse across SDKs.
@@ -10,7 +10,7 @@ function match(log, matchingResult, bucketingKey, seed, treatments, label) {
10
10
  return treatments ? // Feature flag
11
11
  {
12
12
  treatment: (0, engineUtils_1.getTreatment)(log, bucketingKey, seed, treatments),
13
- label: label
13
+ label: label !== null && label !== void 0 ? label : ''
14
14
  } : // Rule-based segment
15
15
  true;
16
16
  }
@@ -56,8 +56,8 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
56
56
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SEGMENT));
57
57
  },
58
58
  // @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
59
- fetchConfigs: function (since, noCache, till) {
60
- var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(filterQueryString || '').concat(till ? '&till=' + till : '');
59
+ fetchConfigs: function (since, noCache, till, rbSince) {
60
+ var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
61
61
  return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
62
62
  },
63
63
  fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
@@ -128,8 +128,8 @@ function splitApiFactory(settings, platform, telemetryTracker) {
128
128
  return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), true);
129
129
  },
130
130
  // Not used. Just here to satisfy the IServiceApi interface.
131
- fetchConfigs: function (since, noCache, till) {
132
- var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(filterQueryString || '').concat(till ? '&till=' + till : '');
131
+ fetchConfigs: function (since, noCache, till, rbSince) {
132
+ var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
133
133
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
134
134
  },
135
135
  fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
@@ -15,7 +15,7 @@ var AbstractDefinitionsCacheSync_1 = require("../../storages/AbstractDefinitions
15
15
  function pollingManagerCSFactory(params, definitionChangesFetcher) {
16
16
  var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
17
17
  var log = settings.log;
18
- var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings, true);
18
+ var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
19
19
  // Map of matching keys to their corresponding MySegmentsSyncTask.
20
20
  var mySegmentsSyncTasks = {};
21
21
  var matchingKey = (0, key_1.getMatching)(settings.core.key);
@@ -10,8 +10,8 @@ var constants_1 = require("../../logger/constants");
10
10
  function pollingManagerSSFactory(params, definitionChangesFetcher, segmentChangesFetcher) {
11
11
  var storage = params.storage, readiness = params.readiness, settings = params.settings;
12
12
  var log = settings.log;
13
- var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
14
13
  var segmentsSyncTask = (0, segmentsSyncTask_1.segmentsSyncTaskFactory)(segmentChangesFetcher, storage, readiness, settings);
14
+ var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
15
15
  return {
16
16
  definitionsSyncTask: definitionsSyncTask,
17
17
  segmentsSyncTask: segmentsSyncTask,
@@ -6,7 +6,8 @@ var definitionChangesUpdater_1 = require("../updaters/definitionChangesUpdater")
6
6
  /**
7
7
  * Creates a sync task that periodically executes a `definitionChangesUpdater` task
8
8
  */
9
- function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, isClientSide) {
10
- return (0, syncTask_1.syncTaskFactory)(settings.log, (0, definitionChangesUpdater_1.definitionChangesUpdaterFactory)(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
9
+ function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask // undefined for client-side
10
+ ) {
11
+ return (0, syncTask_1.syncTaskFactory)(settings.log, (0, definitionChangesUpdater_1.definitionChangesUpdaterFactory)(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, segmentsSyncTask), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
11
12
  }
12
13
  exports.definitionsSyncTaskFactory = definitionsSyncTaskFactory;
@@ -8,16 +8,6 @@ var lang_1 = require("../../../utils/lang");
8
8
  var constants_3 = require("../../../utils/constants");
9
9
  var sets_1 = require("../../../utils/lang/sets");
10
10
  var constants_4 = require("../../streaming/constants");
11
- // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
12
- // Returns a promise that could be rejected.
13
- // @TODO review together with Segments and MySegments storage APIs
14
- function checkAllSegmentsExist(segments) {
15
- var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
16
- return registeredSegments.then(function (segmentNames) {
17
- return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
18
- .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
19
- });
20
- }
21
11
  /**
22
12
  * Collect segments from a raw FF or RBS definition.
23
13
  * Exported for testing purposes.
@@ -106,7 +96,8 @@ function convertInstantUpdateToDefinitionChanges(instantUpdate) {
106
96
  * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
107
97
  * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
108
98
  */
109
- function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
99
+ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, segmentsSyncTask // undefined for client-side
100
+ ) {
110
101
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
111
102
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
112
103
  var definitions = storage.definitions, rbSegments = storage.rbSegments, segments = storage.segments;
@@ -168,8 +159,8 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
168
159
  storage.save();
169
160
  startingUp = false;
170
161
  if (definitionsEventEmitter) {
171
- // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
172
- return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
162
+ // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
163
+ return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
173
164
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
174
165
  .then(function (emitSplitsArrivedEvent) {
175
166
  // emit SDK events
@@ -66,7 +66,7 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
66
66
  // if at least one segment fetch succeeded, mark segments ready
67
67
  if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
68
68
  readyOnAlreadyExistentState = false;
69
- if (readiness) {
69
+ if (readiness && !fetchOnlyNew) {
70
70
  var metadata = {
71
71
  type: constants_1.SEGMENTS_UPDATE,
72
72
  names: []
@@ -11,7 +11,7 @@ var constants_5 = require("./constants");
11
11
  /**
12
12
  * DefinitionsUpdateWorker factory
13
13
  */
14
- function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker, segmentsSyncTask) {
14
+ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
15
15
  var ff = DefinitionsUpdateWorker(storage.definitions);
16
16
  var rbs = DefinitionsUpdateWorker(storage.rbSegments);
17
17
  function DefinitionsUpdateWorker(cache) {
@@ -35,9 +35,6 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
35
35
  else {
36
36
  if (instantUpdate)
37
37
  telemetryTracker.trackUpdatesFromSSE(constants_3.SPLITS);
38
- // fetch new registered segments for server-side API. Not retrying on error
39
- if (segmentsSyncTask)
40
- segmentsSyncTask.execute(true);
41
38
  var attempts = backoff.attempts + 1;
42
39
  if (ff.isSync() && rbs.isSync()) {
43
40
  log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts."));
@@ -46,7 +46,7 @@ function pushManagerFactory(params, pollingManager) {
46
46
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
47
47
  var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
48
48
  // For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
49
- var definitionsUpdateWorker = (0, DefinitionsUpdateWorker_1.DefinitionsUpdateWorker)(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
49
+ var definitionsUpdateWorker = (0, DefinitionsUpdateWorker_1.DefinitionsUpdateWorker)(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
50
50
  // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
51
51
  var userKeyHashes = {};
52
52
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
@@ -7,7 +7,7 @@ function match(log, matchingResult, bucketingKey, seed, treatments, label) {
7
7
  return treatments ? // Feature flag
8
8
  {
9
9
  treatment: getTreatment(log, bucketingKey, seed, treatments),
10
- label: label
10
+ label: label !== null && label !== void 0 ? label : ''
11
11
  } : // Rule-based segment
12
12
  true;
13
13
  }
@@ -53,8 +53,8 @@ export function serviceApiFactory(settings, platform, telemetryTracker, secureSp
53
53
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SEGMENT));
54
54
  },
55
55
  // @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
56
- fetchConfigs: function (since, noCache, till) {
57
- var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(filterQueryString || '').concat(till ? '&till=' + till : '');
56
+ fetchConfigs: function (since, noCache, till, rbSince) {
57
+ var url = "".concat(urls.configs, "/api/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
58
58
  return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
59
59
  },
60
60
  fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
@@ -125,8 +125,8 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
125
125
  return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(TELEMETRY), true);
126
126
  },
127
127
  // Not used. Just here to satisfy the IServiceApi interface.
128
- fetchConfigs: function (since, noCache, till) {
129
- var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(filterQueryString || '').concat(till ? '&till=' + till : '');
128
+ fetchConfigs: function (since, noCache, till, rbSince) {
129
+ var url = "".concat(urls.configs, "/v1/configs?since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
130
130
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
131
131
  },
132
132
  fetchConfigsSegmentChanges: function (since, segmentName, noCache, till) {
@@ -12,7 +12,7 @@ import { usesSegmentsSync } from '../../storages/AbstractDefinitionsCacheSync';
12
12
  export function pollingManagerCSFactory(params, definitionChangesFetcher) {
13
13
  var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
14
14
  var log = settings.log;
15
- var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, true);
15
+ var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
16
16
  // Map of matching keys to their corresponding MySegmentsSyncTask.
17
17
  var mySegmentsSyncTasks = {};
18
18
  var matchingKey = getMatching(settings.core.key);
@@ -7,8 +7,8 @@ import { POLLING_START, POLLING_STOP, LOG_PREFIX_SYNC_POLLING } from '../../logg
7
7
  export function pollingManagerSSFactory(params, definitionChangesFetcher, segmentChangesFetcher) {
8
8
  var storage = params.storage, readiness = params.readiness, settings = params.settings;
9
9
  var log = settings.log;
10
- var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
11
10
  var segmentsSyncTask = segmentsSyncTaskFactory(segmentChangesFetcher, storage, readiness, settings);
11
+ var definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
12
12
  return {
13
13
  definitionsSyncTask: definitionsSyncTask,
14
14
  segmentsSyncTask: segmentsSyncTask,
@@ -3,6 +3,7 @@ import { definitionChangesUpdaterFactory } from '../updaters/definitionChangesUp
3
3
  /**
4
4
  * Creates a sync task that periodically executes a `definitionChangesUpdater` task
5
5
  */
6
- export function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, isClientSide) {
7
- return syncTaskFactory(settings.log, definitionChangesUpdaterFactory(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, isClientSide), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
6
+ export function definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask // undefined for client-side
7
+ ) {
8
+ return syncTaskFactory(settings.log, definitionChangesUpdaterFactory(settings.log, definitionChangesFetcher, storage, settings.sync.__splitFiltersValidation, readiness.definitions, settings.startup.requestTimeoutBeforeReady, settings.startup.retriesOnFailureBeforeReady, segmentsSyncTask), settings.scheduler.featuresRefreshRate, 'definitionChangesUpdater');
8
9
  }
@@ -5,16 +5,6 @@ import { startsWith } from '../../../utils/lang';
5
5
  import { IN_RULE_BASED_SEGMENT, IN_SEGMENT, RULE_BASED_SEGMENT, STANDARD_SEGMENT } from '../../../utils/constants';
6
6
  import { setToArray } from '../../../utils/lang/sets';
7
7
  import { SPLIT_UPDATE } from '../../streaming/constants';
8
- // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
9
- // Returns a promise that could be rejected.
10
- // @TODO review together with Segments and MySegments storage APIs
11
- function checkAllSegmentsExist(segments) {
12
- var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
13
- return registeredSegments.then(function (segmentNames) {
14
- return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
15
- .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
16
- });
17
- }
18
8
  /**
19
9
  * Collect segments from a raw FF or RBS definition.
20
10
  * Exported for testing purposes.
@@ -101,7 +91,8 @@ function convertInstantUpdateToDefinitionChanges(instantUpdate) {
101
91
  * @param requestTimeoutBeforeReady - How long the updater will wait for the request to timeout. Default 0, i.e., never timeout.
102
92
  * @param retriesOnFailureBeforeReady - How many retries on `/splitChanges` or `/configs` we the updater do in case of failure or timeout. Default 0, i.e., no retries.
103
93
  */
104
- export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, isClientSide) {
94
+ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage, splitFiltersValidation, definitionsEventEmitter, requestTimeoutBeforeReady, retriesOnFailureBeforeReady, segmentsSyncTask // undefined for client-side
95
+ ) {
105
96
  if (requestTimeoutBeforeReady === void 0) { requestTimeoutBeforeReady = 0; }
106
97
  if (retriesOnFailureBeforeReady === void 0) { retriesOnFailureBeforeReady = 0; }
107
98
  var definitions = storage.definitions, rbSegments = storage.rbSegments, segments = storage.segments;
@@ -163,8 +154,8 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
163
154
  storage.save();
164
155
  startingUp = false;
165
156
  if (definitionsEventEmitter) {
166
- // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
167
- return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
157
+ // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
158
+ return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
168
159
  .catch(function () { return false; } /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
169
160
  .then(function (emitSplitsArrivedEvent) {
170
161
  // emit SDK events
@@ -63,7 +63,7 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
63
63
  // if at least one segment fetch succeeded, mark segments ready
64
64
  if (shouldUpdateFlags.some(function (update) { return update; }) || readyOnAlreadyExistentState) {
65
65
  readyOnAlreadyExistentState = false;
66
- if (readiness) {
66
+ if (readiness && !fetchOnlyNew) {
67
67
  var metadata = {
68
68
  type: SEGMENTS_UPDATE,
69
69
  names: []
@@ -8,7 +8,7 @@ import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES }
8
8
  /**
9
9
  * DefinitionsUpdateWorker factory
10
10
  */
11
- export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker, segmentsSyncTask) {
11
+ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
12
12
  var ff = DefinitionsUpdateWorker(storage.definitions);
13
13
  var rbs = DefinitionsUpdateWorker(storage.rbSegments);
14
14
  function DefinitionsUpdateWorker(cache) {
@@ -32,9 +32,6 @@ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, defin
32
32
  else {
33
33
  if (instantUpdate)
34
34
  telemetryTracker.trackUpdatesFromSSE(SPLITS);
35
- // fetch new registered segments for server-side API. Not retrying on error
36
- if (segmentsSyncTask)
37
- segmentsSyncTask.execute(true);
38
35
  var attempts = backoff.attempts + 1;
39
36
  if (ff.isSync() && rbs.isSync()) {
40
37
  log.debug("Refresh completed".concat(cdnBypass ? ' bypassing the CDN' : '', " in ").concat(attempts, " attempts."));
@@ -43,7 +43,7 @@ export function pushManagerFactory(params, pollingManager) {
43
43
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
44
44
  var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
45
45
  // For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
46
- var definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
46
+ var definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
47
47
  // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
48
48
  var userKeyHashes = {};
49
49
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "3.0.1-rc.1",
3
+ "version": "3.0.1-rc.3",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
package/src/dtos/types.ts CHANGED
@@ -192,7 +192,7 @@ export interface IDefinitionCondition {
192
192
  matchers: IDefinitionMatcher[]
193
193
  }
194
194
  partitions?: IDefinitionPartition[]
195
- label?: string
195
+ label?: string | null
196
196
  conditionType?: 'ROLLOUT' | 'WHITELIST'
197
197
  }
198
198
 
@@ -7,12 +7,12 @@ import SplitIO from '../../../types/splitio';
7
7
  import { ILogger } from '../../logger/types';
8
8
 
9
9
  // Build Evaluation object if and only if matchingResult is true
10
- function match(log: ILogger, matchingResult: boolean, bucketingKey: string | undefined, seed?: number, treatments?: { getTreatmentFor: (x: number) => string }, label?: string): IEvaluation | boolean | undefined {
10
+ function match(log: ILogger, matchingResult: boolean, bucketingKey: string | undefined, seed?: number, treatments?: { getTreatmentFor: (x: number) => string }, label?: string | null): IEvaluation | boolean | undefined {
11
11
  if (matchingResult) {
12
12
  return treatments ? // Feature flag
13
13
  {
14
14
  treatment: getTreatment(log, bucketingKey as string, seed, treatments),
15
- label: label!
15
+ label: label ?? ''
16
16
  } : // Rule-based segment
17
17
  true;
18
18
  }
@@ -22,7 +22,7 @@ function match(log: ILogger, matchingResult: boolean, bucketingKey: string | und
22
22
  }
23
23
 
24
24
  // Condition factory
25
- export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {
25
+ export function conditionContext(log: ILogger, matcherEvaluator: (key: SplitIO.SplitKeyObject, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) => MaybeThenable<boolean>, treatments?: { getTreatmentFor: (x: number) => string }, label?: string | null, conditionType?: 'ROLLOUT' | 'WHITELIST'): IEvaluator {
26
26
 
27
27
  return function conditionEvaluator(key: SplitIO.SplitKeyObject, seed?: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: IDefinitionEvaluator) {
28
28
 
@@ -70,8 +70,8 @@ export function serviceApiFactory(
70
70
  },
71
71
 
72
72
  // @TODO support filterQueryString and handle ERROR_TOO_MANY_SETS error
73
- fetchConfigs(since: number, noCache?: boolean, till?: number) {
74
- const url = `${urls.configs}/api/v1/configs?since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
73
+ fetchConfigs(since: number, noCache?: boolean, till?: number, rbSince?: number) {
74
+ const url = `${urls.configs}/api/v1/configs?since=${since}${rbSince ? '&rbSince=' + rbSince : ''}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
75
75
  return secureSplitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
76
76
  },
77
77
 
@@ -149,8 +149,8 @@ export function splitApiFactory(
149
149
 
150
150
  // Not used. Just here to satisfy the IServiceApi interface.
151
151
 
152
- fetchConfigs(since: number, noCache?: boolean, till?: number) {
153
- const url = `${urls.configs}/v1/configs?since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
152
+ fetchConfigs(since: number, noCache?: boolean, till?: number, rbSince?: number) {
153
+ const url = `${urls.configs}/v1/configs?since=${since}${rbSince ? '&rbSince=' + rbSince : ''}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
154
154
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined);
155
155
  },
156
156
 
@@ -24,7 +24,7 @@ export function pollingManagerCSFactory(
24
24
  const { serviceApi, storage, readiness, settings } = params;
25
25
  const log = settings.log;
26
26
 
27
- const definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, true);
27
+ const definitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
28
28
 
29
29
  // Map of matching keys to their corresponding MySegmentsSyncTask.
30
30
  const mySegmentsSyncTasks: Record<string, IMySegmentsSyncTask> = {};
@@ -17,8 +17,8 @@ export function pollingManagerSSFactory(
17
17
  const { storage, readiness, settings } = params;
18
18
  const log = settings.log;
19
19
 
20
- const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings);
21
20
  const segmentsSyncTask: ISegmentsSyncTask = segmentsSyncTaskFactory(segmentChangesFetcher, storage, readiness, settings);
21
+ const definitionsSyncTask: IDefinitionsSyncTask = definitionsSyncTaskFactory(definitionChangesFetcher, storage, readiness, settings, segmentsSyncTask);
22
22
 
23
23
  return {
24
24
  definitionsSyncTask,
@@ -1,7 +1,7 @@
1
1
  import { IStorageSync } from '../../../storages/types';
2
2
  import { IReadinessManager } from '../../../readiness/types';
3
3
  import { syncTaskFactory } from '../../syncTask';
4
- import { IDefinitionsSyncTask } from '../types';
4
+ import { IDefinitionsSyncTask, ISegmentsSyncTask } from '../types';
5
5
  import { ISettings } from '../../../types';
6
6
  import { definitionChangesUpdaterFactory } from '../updaters/definitionChangesUpdater';
7
7
  import { IDefinitionChangesFetcher } from '../fetchers/types';
@@ -14,7 +14,7 @@ export function definitionsSyncTaskFactory(
14
14
  storage: IStorageSync,
15
15
  readiness: IReadinessManager,
16
16
  settings: ISettings,
17
- isClientSide?: boolean
17
+ segmentsSyncTask?: ISegmentsSyncTask // undefined for client-side
18
18
  ): IDefinitionsSyncTask {
19
19
  return syncTaskFactory(
20
20
  settings.log,
@@ -26,7 +26,7 @@ export function definitionsSyncTaskFactory(
26
26
  readiness.definitions,
27
27
  settings.startup.requestTimeoutBeforeReady,
28
28
  settings.startup.retriesOnFailureBeforeReady,
29
- isClientSide
29
+ segmentsSyncTask
30
30
  ),
31
31
  settings.scheduler.featuresRefreshRate,
32
32
  'definitionChangesUpdater',
@@ -1,4 +1,4 @@
1
- import { ISegmentsCacheBase, IStorageBase } from '../../../storages/types';
1
+ import { IStorageBase } from '../../../storages/types';
2
2
  import { IDefinitionChangesFetcher } from '../fetchers/types';
3
3
  import { IRBSegment, IDefinition, IDefinitionChangesResponse, ISplitFiltersValidation, MaybeThenable } from '../../../dtos/types';
4
4
  import { IDefinitionsEventEmitter } from '../../../readiness/types';
@@ -12,21 +12,11 @@ import { setToArray } from '../../../utils/lang/sets';
12
12
  import { SPLIT_UPDATE } from '../../streaming/constants';
13
13
  import { SdkUpdateMetadata } from '../../../../types/splitio';
14
14
  import { ISplit } from '../fetchers/splitChangesFetcher';
15
+ import { ISegmentsSyncTask } from '../types';
15
16
 
16
17
  export type InstantUpdate = { payload: ISplit | IRBSegment, changeNumber: number, type: string };
17
18
  type DefinitionChangesUpdater = (noCache?: boolean, till?: number, instantUpdate?: InstantUpdate) => Promise<boolean>
18
19
 
19
- // Checks that all registered segments have been fetched (changeNumber !== -1 for every segment).
20
- // Returns a promise that could be rejected.
21
- // @TODO review together with Segments and MySegments storage APIs
22
- function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
23
- let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
24
- return registeredSegments.then(segmentNames => {
25
- return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
26
- .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
27
- });
28
- }
29
-
30
20
  /**
31
21
  * Collect segments from a raw FF or RBS definition.
32
22
  * Exported for testing purposes.
@@ -133,7 +123,7 @@ export function definitionChangesUpdaterFactory(
133
123
  definitionsEventEmitter?: IDefinitionsEventEmitter,
134
124
  requestTimeoutBeforeReady = 0,
135
125
  retriesOnFailureBeforeReady = 0,
136
- isClientSide?: boolean
126
+ segmentsSyncTask?: ISegmentsSyncTask // undefined for client-side
137
127
  ): DefinitionChangesUpdater {
138
128
  const { definitions, rbSegments, segments } = storage;
139
129
 
@@ -202,8 +192,8 @@ export function definitionChangesUpdaterFactory(
202
192
  startingUp = false;
203
193
 
204
194
  if (definitionsEventEmitter) {
205
- // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must check that all registered segments have been fetched
206
- return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (isClientSide || checkAllSegmentsExist(segments))))
195
+ // To emit SDK_DEFINITIONS_ARRIVED for server-side SDK, we must wait for all registered segments to be fetched
196
+ return Promise.resolve(!definitionsEventEmitter.definitionsArrived || ((ffChanged || rbsChanged) && (!segmentsSyncTask || segmentsSyncTask.execute(true))))
207
197
  .catch(() => false /** noop. just to handle a possible `checkAllSegmentsExist` rejection, before emitting SDK event */)
208
198
  .then(emitSplitsArrivedEvent => {
209
199
  // emit SDK events
@@ -76,7 +76,7 @@ export function segmentChangesUpdaterFactory(
76
76
  log.debug(`${LOG_PREFIX_SYNC}Started segments update`);
77
77
 
78
78
  // If not a segment name provided, read list of available segments names to be updated.
79
- let segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
79
+ const segmentsPromise = Promise.resolve(segmentName ? [segmentName] : segments.getRegisteredSegments());
80
80
 
81
81
  return segmentsPromise.then(segmentNames => {
82
82
  const updaters = segmentNames.map(segmentName => updateSegment(segmentName, noCache, till, fetchOnlyNew, readyOnAlreadyExistentState ? retriesOnFailureBeforeReady : 0));
@@ -85,7 +85,7 @@ export function segmentChangesUpdaterFactory(
85
85
  // if at least one segment fetch succeeded, mark segments ready
86
86
  if (shouldUpdateFlags.some(update => update) || readyOnAlreadyExistentState) {
87
87
  readyOnAlreadyExistentState = false;
88
- if (readiness) {
88
+ if (readiness && !fetchOnlyNew) {
89
89
  const metadata: SdkUpdateMetadata = {
90
90
  type: SEGMENTS_UPDATE,
91
91
  names: []
@@ -7,7 +7,7 @@ import { IRBSegmentsCacheSync, IDefinitionsCacheSync, IStorageSync } from '../..
7
7
  import { ITelemetryTracker } from '../../../trackers/types';
8
8
  import { Backoff } from '../../../utils/Backoff';
9
9
  import { SPLITS } from '../../../utils/constants';
10
- import { ISegmentsSyncTask, IDefinitionsSyncTask } from '../../polling/types';
10
+ import { IDefinitionsSyncTask } from '../../polling/types';
11
11
  import { InstantUpdate } from '../../polling/updaters/definitionChangesUpdater';
12
12
  import { RB_SEGMENT_UPDATE } from '../constants';
13
13
  import { parseFFUpdatePayload } from '../parseUtils';
@@ -18,7 +18,7 @@ import { IUpdateWorker } from './types';
18
18
  /**
19
19
  * DefinitionsUpdateWorker factory
20
20
  */
21
- export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, definitionsSyncTask: IDefinitionsSyncTask, definitionsEventEmitter: IDefinitionsEventEmitter, telemetryTracker: ITelemetryTracker, segmentsSyncTask?: ISegmentsSyncTask): IUpdateWorker<[updateData: ISplitUpdateData]> & { killDefinition(event: ISplitKillData): void } {
21
+ export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, definitionsSyncTask: IDefinitionsSyncTask, definitionsEventEmitter: IDefinitionsEventEmitter, telemetryTracker: ITelemetryTracker): IUpdateWorker<[updateData: ISplitUpdateData]> & { killDefinition(event: ISplitKillData): void } {
22
22
 
23
23
  const ff = DefinitionsUpdateWorker(storage.definitions);
24
24
  const rbs = DefinitionsUpdateWorker(storage.rbSegments);
@@ -42,8 +42,6 @@ export function DefinitionsUpdateWorker(log: ILogger, storage: IStorageSync, def
42
42
  __handleDefinitionUpdateCall();
43
43
  } else {
44
44
  if (instantUpdate) telemetryTracker.trackUpdatesFromSSE(SPLITS);
45
- // fetch new registered segments for server-side API. Not retrying on error
46
- if (segmentsSyncTask) segmentsSyncTask.execute(true);
47
45
 
48
46
  const attempts = backoff.attempts + 1;
49
47
 
@@ -56,7 +56,7 @@ export function pushManagerFactory(
56
56
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
57
57
  const segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask as ISegmentsSyncTask, storage.segments);
58
58
  // For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
59
- const definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask as ISegmentsSyncTask);
59
+ const definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
60
60
 
61
61
  // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
62
62
  const userKeyHashes: Record<string, string> = {};