@splitsoftware/splitio-commons 1.16.1-rc.10 → 1.16.1-rc.11

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 (66) hide show
  1. package/cjs/logger/constants.js +2 -2
  2. package/cjs/logger/messages/warn.js +1 -1
  3. package/cjs/services/splitApi.js +1 -1
  4. package/cjs/storages/AbstractSegmentsCacheSync.js +41 -7
  5. package/cjs/storages/dataLoader.js +1 -1
  6. package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +19 -63
  7. package/cjs/storages/inMemory/MySegmentsCacheInMemory.js +5 -40
  8. package/cjs/sync/polling/updaters/mySegmentsUpdater.js +7 -17
  9. package/cjs/sync/streaming/AuthClient/index.js +1 -1
  10. package/cjs/sync/streaming/SSEHandler/index.js +5 -7
  11. package/cjs/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +8 -6
  12. package/cjs/sync/streaming/constants.js +3 -3
  13. package/cjs/sync/streaming/pushManager.js +21 -24
  14. package/cjs/utils/constants/index.js +3 -4
  15. package/esm/logger/constants.js +1 -1
  16. package/esm/logger/messages/warn.js +1 -1
  17. package/esm/services/splitApi.js +2 -2
  18. package/esm/storages/AbstractSegmentsCacheSync.js +41 -7
  19. package/esm/storages/dataLoader.js +1 -1
  20. package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +19 -63
  21. package/esm/storages/inMemory/MySegmentsCacheInMemory.js +5 -40
  22. package/esm/sync/polling/updaters/mySegmentsUpdater.js +7 -17
  23. package/esm/sync/streaming/AuthClient/index.js +1 -1
  24. package/esm/sync/streaming/SSEHandler/index.js +6 -8
  25. package/esm/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.js +8 -6
  26. package/esm/sync/streaming/constants.js +2 -2
  27. package/esm/sync/streaming/pushManager.js +24 -27
  28. package/esm/utils/constants/index.js +1 -2
  29. package/package.json +1 -1
  30. package/src/dtos/types.ts +9 -12
  31. package/src/logger/constants.ts +1 -1
  32. package/src/logger/messages/warn.ts +1 -1
  33. package/src/services/splitApi.ts +2 -2
  34. package/src/storages/AbstractSegmentsCacheSync.ts +52 -7
  35. package/src/storages/AbstractSplitsCacheSync.ts +1 -1
  36. package/src/storages/dataLoader.ts +1 -1
  37. package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +15 -69
  38. package/src/storages/inMemory/MySegmentsCacheInMemory.ts +6 -46
  39. package/src/storages/types.ts +5 -4
  40. package/src/sync/polling/types.ts +8 -9
  41. package/src/sync/polling/updaters/mySegmentsUpdater.ts +9 -14
  42. package/src/sync/streaming/AuthClient/index.ts +1 -1
  43. package/src/sync/streaming/SSEHandler/index.ts +9 -11
  44. package/src/sync/streaming/SSEHandler/types.ts +6 -6
  45. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +8 -7
  46. package/src/sync/streaming/constants.ts +2 -2
  47. package/src/sync/streaming/parseUtils.ts +2 -2
  48. package/src/sync/streaming/pushManager.ts +26 -29
  49. package/src/sync/streaming/types.ts +6 -6
  50. package/src/sync/submitters/types.ts +3 -4
  51. package/src/utils/constants/index.ts +1 -2
  52. package/types/dtos/types.d.ts +8 -12
  53. package/types/logger/constants.d.ts +1 -1
  54. package/types/storages/AbstractSegmentsCacheSync.d.ts +8 -6
  55. package/types/storages/AbstractSplitsCacheSync.d.ts +1 -1
  56. package/types/storages/inLocalStorage/MySegmentsCacheInLocal.d.ts +1 -12
  57. package/types/storages/inMemory/MySegmentsCacheInMemory.d.ts +1 -9
  58. package/types/storages/types.d.ts +5 -4
  59. package/types/sync/polling/types.d.ts +8 -6
  60. package/types/sync/streaming/SSEHandler/types.d.ts +6 -6
  61. package/types/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.d.ts +1 -2
  62. package/types/sync/streaming/constants.d.ts +2 -2
  63. package/types/sync/streaming/parseUtils.d.ts +2 -2
  64. package/types/sync/streaming/types.d.ts +5 -5
  65. package/types/sync/submitters/types.d.ts +3 -4
  66. package/types/utils/constants/index.d.ts +1 -2
@@ -1,6 +1,6 @@
1
1
  import { splitHttpClientFactory } from './splitHttpClient';
2
2
  import { objectAssign } from '../utils/lang/objectAssign';
3
- import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
3
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
4
4
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
5
5
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
6
6
  function userKeyToQueryParam(userKey) {
@@ -59,7 +59,7 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
59
59
  * - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
60
60
  */
61
61
  var url = urls.sdk + "/memberships/" + encodeURIComponent(userMatchingKey);
62
- return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
62
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MEMBERSHIPS));
63
63
  },
64
64
  /**
65
65
  * Post events.
@@ -6,20 +6,54 @@ var AbstractSegmentsCacheSync = /** @class */ (function () {
6
6
  function AbstractSegmentsCacheSync() {
7
7
  }
8
8
  /**
9
- * For server-side synchronizer: add the given list of segments to the cache, with an empty list of keys. The segments that already exist are not modified.
10
- * For client-side synchronizer: the method is not used.
9
+ * clear the cache.
11
10
  */
12
- AbstractSegmentsCacheSync.prototype.registerSegments = function (names) { return false; };
11
+ AbstractSegmentsCacheSync.prototype.clear = function () {
12
+ this.resetSegments({});
13
+ };
13
14
  /**
14
- * For server-side synchronizer: set the change number of `name` segment.
15
+ * For server-side synchronizer: add the given list of segments to the cache, with an empty list of keys. The segments that already exist are not modified.
15
16
  * For client-side synchronizer: the method is not used.
16
17
  */
17
- AbstractSegmentsCacheSync.prototype.setChangeNumber = function (name, changeNumber) { return true; };
18
+ AbstractSegmentsCacheSync.prototype.registerSegments = function (names) { return false; };
18
19
  /**
19
20
  * For server-side synchronizer: the method is not used.
20
- * For client-side synchronizer: reset the cache with the given list of segments.
21
+ * For client-side synchronizer: it resets or updates the cache.
21
22
  */
22
- AbstractSegmentsCacheSync.prototype.resetSegments = function (names, changeNumber) { return true; };
23
+ AbstractSegmentsCacheSync.prototype.resetSegments = function (segmentsData) {
24
+ var _this = this;
25
+ this.setChangeNumber(undefined, segmentsData.cn);
26
+ var _a = segmentsData, added = _a.added, removed = _a.removed;
27
+ if (added && removed) {
28
+ var isDiff_1 = false;
29
+ added.forEach(function (segment) {
30
+ isDiff_1 = _this.addToSegment(segment) || isDiff_1;
31
+ });
32
+ removed.forEach(function (segment) {
33
+ isDiff_1 = _this.removeFromSegment(segment) || isDiff_1;
34
+ });
35
+ return isDiff_1;
36
+ }
37
+ var names = (segmentsData.k || []).map(function (s) { return s.n; }).sort();
38
+ var storedSegmentKeys = this.getRegisteredSegments().sort();
39
+ // Extreme fast => everything is empty
40
+ if (!names.length && !storedSegmentKeys.length)
41
+ return false;
42
+ var index = 0;
43
+ while (index < names.length && index < storedSegmentKeys.length && names[index] === storedSegmentKeys[index])
44
+ index++;
45
+ // Quick path => no changes
46
+ if (index === names.length && index === storedSegmentKeys.length)
47
+ return false;
48
+ // Slowest path => add and/or remove segments
49
+ for (var removeIndex = index; removeIndex < storedSegmentKeys.length; removeIndex++) {
50
+ this.removeFromSegment(storedSegmentKeys[removeIndex]);
51
+ }
52
+ for (var addIndex = index; addIndex < names.length; addIndex++) {
53
+ this.addToSegment(names[addIndex]);
54
+ }
55
+ return true;
56
+ };
23
57
  return AbstractSegmentsCacheSync;
24
58
  }());
25
59
  export { AbstractSegmentsCacheSync };
@@ -42,6 +42,6 @@ export function dataLoaderFactory(preloadedData) {
42
42
  return Array.isArray(userIds) && userIds.indexOf(userId) > -1;
43
43
  });
44
44
  }
45
- storage.segments.resetSegments(mySegmentsData);
45
+ storage.segments.resetSegments({ k: mySegmentsData.map(function (s) { return ({ n: s }); }) });
46
46
  };
47
47
  }
@@ -11,19 +11,11 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
11
11
  return _this;
12
12
  // There is not need to flush segments cache like splits cache, since resetSegments receives the up-to-date list of active segments
13
13
  }
14
- /**
15
- * Removes list of segments from localStorage
16
- * @NOTE this method is not being used at the moment.
17
- */
18
- MySegmentsCacheInLocal.prototype.clear = function () {
19
- this.log.info(LOG_PREFIX + 'Flushing MySegments data from localStorage');
20
- // We cannot simply call `localStorage.clear()` since that implies removing user items from the storage
21
- // We could optimize next sentence, since it implies iterating over all localStorage items
22
- this.resetSegments([]);
23
- };
24
14
  MySegmentsCacheInLocal.prototype.addToSegment = function (name) {
25
15
  var segmentKey = this.keys.buildSegmentNameKey(name);
26
16
  try {
17
+ if (localStorage.getItem(segmentKey) === DEFINED)
18
+ return false;
27
19
  localStorage.setItem(segmentKey, DEFINED);
28
20
  return true;
29
21
  }
@@ -35,6 +27,8 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
35
27
  MySegmentsCacheInLocal.prototype.removeFromSegment = function (name) {
36
28
  var segmentKey = this.keys.buildSegmentNameKey(name);
37
29
  try {
30
+ if (localStorage.getItem(segmentKey) !== DEFINED)
31
+ return false;
38
32
  localStorage.removeItem(segmentKey);
39
33
  return true;
40
34
  }
@@ -46,41 +40,22 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
46
40
  MySegmentsCacheInLocal.prototype.isInSegment = function (name) {
47
41
  return localStorage.getItem(this.keys.buildSegmentNameKey(name)) === DEFINED;
48
42
  };
49
- /**
50
- * Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
51
- *
52
- * @param {string[]} names list of segment names
53
- * @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
54
- */
55
- MySegmentsCacheInLocal.prototype.resetSegments = function (names, changeNumber) {
43
+ MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
56
44
  var _this = this;
57
- try {
58
- if (changeNumber) {
59
- localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
60
- }
61
- else {
62
- localStorage.removeItem(this.keys.buildTillKey());
63
- }
64
- }
65
- catch (e) {
66
- this.log.error(e);
67
- }
68
- var isDiff = false;
69
- var index;
70
45
  // Scan current values from localStorage
71
- var storedSegmentNames = Object.keys(localStorage).reduce(function (accum, key) {
46
+ return Object.keys(localStorage).reduce(function (accum, key) {
72
47
  var segmentName = _this.keys.extractSegmentName(key);
73
48
  if (segmentName) {
74
49
  accum.push(segmentName);
75
50
  }
76
51
  else {
77
- // @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block and reuse `getRegisteredSegments` method.
52
+ // @TODO @BREAKING: This is only to clean up "old" keys. Remove this whole else code block
78
53
  segmentName = _this.keys.extractOldSegmentKey(key);
79
54
  if (segmentName) { // this was an old segment key, let's clean up.
80
55
  var newSegmentKey = _this.keys.buildSegmentNameKey(segmentName);
81
56
  try {
82
57
  // If the new format key is not there, create it.
83
- if (!localStorage.getItem(newSegmentKey) && names.indexOf(segmentName) > -1) {
58
+ if (!localStorage.getItem(newSegmentKey)) {
84
59
  localStorage.setItem(newSegmentKey, DEFINED);
85
60
  // we are migrating a segment, let's track it.
86
61
  accum.push(segmentName);
@@ -94,40 +69,21 @@ var MySegmentsCacheInLocal = /** @class */ (function (_super) {
94
69
  }
95
70
  return accum;
96
71
  }, []);
97
- // Extreme fast => everything is empty
98
- if (names.length === 0 && storedSegmentNames.length === names.length)
99
- return isDiff;
100
- // Quick path
101
- if (storedSegmentNames.length !== names.length) {
102
- isDiff = true;
103
- storedSegmentNames.forEach(function (name) { return _this.removeFromSegment(name); });
104
- names.forEach(function (name) { return _this.addToSegment(name); });
105
- }
106
- else {
107
- // Slowest path => we need to find at least 1 difference because
108
- for (index = 0; index < names.length && storedSegmentNames.indexOf(names[index]) !== -1; index++) {
109
- // TODO: why empty statement?
110
- }
111
- if (index < names.length) {
112
- isDiff = true;
113
- storedSegmentNames.forEach(function (name) { return _this.removeFromSegment(name); });
114
- names.forEach(function (name) { return _this.addToSegment(name); });
115
- }
116
- }
117
- return isDiff;
118
- };
119
- MySegmentsCacheInLocal.prototype.getRegisteredSegments = function () {
120
- var _this = this;
121
- return Object.keys(localStorage).reduce(function (accum, key) {
122
- var segmentName = _this.keys.extractSegmentName(key);
123
- if (segmentName)
124
- accum.push(segmentName);
125
- return accum;
126
- }, []);
127
72
  };
128
73
  MySegmentsCacheInLocal.prototype.getKeysCount = function () {
129
74
  return 1;
130
75
  };
76
+ MySegmentsCacheInLocal.prototype.setChangeNumber = function (name, changeNumber) {
77
+ try {
78
+ if (changeNumber)
79
+ localStorage.setItem(this.keys.buildTillKey(), changeNumber + '');
80
+ else
81
+ localStorage.removeItem(this.keys.buildTillKey());
82
+ }
83
+ catch (e) {
84
+ this.log.error(e);
85
+ }
86
+ };
131
87
  MySegmentsCacheInLocal.prototype.getChangeNumber = function () {
132
88
  var n = -1;
133
89
  var value = localStorage.getItem(this.keys.buildTillKey());
@@ -11,58 +11,23 @@ var MySegmentsCacheInMemory = /** @class */ (function (_super) {
11
11
  _this.segmentCache = {};
12
12
  return _this;
13
13
  }
14
- MySegmentsCacheInMemory.prototype.clear = function () {
15
- this.segmentCache = {};
16
- };
17
14
  MySegmentsCacheInMemory.prototype.addToSegment = function (name) {
15
+ if (this.segmentCache[name])
16
+ return false;
18
17
  this.segmentCache[name] = true;
19
18
  return true;
20
19
  };
21
20
  MySegmentsCacheInMemory.prototype.removeFromSegment = function (name) {
21
+ if (!this.segmentCache[name])
22
+ return false;
22
23
  delete this.segmentCache[name];
23
24
  return true;
24
25
  };
25
26
  MySegmentsCacheInMemory.prototype.isInSegment = function (name) {
26
27
  return this.segmentCache[name] === true;
27
28
  };
28
- /**
29
- * Reset (update) the cached list of segments with the given list, removing and adding segments if necessary.
30
- * @NOTE based on the way we use segments in the browser, this way is the best option
31
- *
32
- * @param {string[]} names list of segment names
33
- * @returns boolean indicating if the cache was updated (i.e., given list was different from the cached one)
34
- */
35
- MySegmentsCacheInMemory.prototype.resetSegments = function (names, changeNumber) {
36
- var _this = this;
29
+ MySegmentsCacheInMemory.prototype.setChangeNumber = function (name, changeNumber) {
37
30
  this.cn = changeNumber;
38
- var isDiff = false;
39
- var index;
40
- var storedSegmentKeys = Object.keys(this.segmentCache);
41
- // Extreme fast => everything is empty
42
- if (names.length === 0 && storedSegmentKeys.length === names.length)
43
- return isDiff;
44
- // Quick path
45
- if (storedSegmentKeys.length !== names.length) {
46
- isDiff = true;
47
- this.segmentCache = {};
48
- names.forEach(function (s) {
49
- _this.addToSegment(s);
50
- });
51
- }
52
- else {
53
- // Slowest path => we need to find at least 1 difference because
54
- for (index = 0; index < names.length && this.isInSegment(names[index]); index++) {
55
- // TODO: why empty statement?
56
- }
57
- if (index < names.length) {
58
- isDiff = true;
59
- this.segmentCache = {};
60
- names.forEach(function (s) {
61
- _this.addToSegment(s);
62
- });
63
- }
64
- }
65
- return isDiff;
66
31
  };
67
32
  MySegmentsCacheInMemory.prototype.getChangeNumber = function () {
68
33
  return this.cn || -1;
@@ -1,6 +1,7 @@
1
1
  import { timeout } from '../../../utils/promise/timeout';
2
2
  import { SDK_SEGMENTS_ARRIVED } from '../../../readiness/constants';
3
3
  import { SYNC_MYSEGMENTS_FETCH_RETRY } from '../../../logger/constants';
4
+ import { MEMBERSHIP_LS_UPDATE } from '../../streaming/constants';
4
5
  /**
5
6
  * factory of MySegments updater, a task that:
6
7
  * - fetches mySegments using `mySegmentsFetcher`
@@ -19,26 +20,15 @@ export function mySegmentsUpdaterFactory(log, mySegmentsFetcher, storage, segmen
19
20
  }
20
21
  // @TODO if allowing pluggable storages, handle async execution
21
22
  function updateSegments(segmentsData) {
22
- var _a, _b, _c, _d;
23
23
  var shouldNotifyUpdate;
24
- if (Array.isArray(segmentsData)) {
25
- // Add/Delete the segment names
26
- segmentsData.forEach(function (_a) {
27
- var isLS = _a.isLS, name = _a.name, add = _a.add;
28
- var cache = isLS ? largeSegments : segments;
29
- if (cache.isInSegment(name) !== add) {
30
- shouldNotifyUpdate = true;
31
- if (add)
32
- cache.addToSegment(name);
33
- else
34
- cache.removeFromSegment(name);
35
- }
36
- });
24
+ if (segmentsData.type !== undefined) {
25
+ shouldNotifyUpdate = segmentsData.type === MEMBERSHIP_LS_UPDATE ?
26
+ largeSegments.resetSegments(segmentsData) :
27
+ segments.resetSegments(segmentsData);
37
28
  }
38
29
  else {
39
- // Reset the list of segment names
40
- shouldNotifyUpdate = segments.resetSegments((((_a = segmentsData.ms) === null || _a === void 0 ? void 0 : _a.k) || []).map(function (segment) { return segment.n; }), (_b = segmentsData.ms) === null || _b === void 0 ? void 0 : _b.cn);
41
- shouldNotifyUpdate = largeSegments.resetSegments((((_c = segmentsData.ls) === null || _c === void 0 ? void 0 : _c.k) || []).map(function (segment) { return segment.n; }), (_d = segmentsData.ls) === null || _d === void 0 ? void 0 : _d.cn) || shouldNotifyUpdate;
30
+ shouldNotifyUpdate = segments.resetSegments(segmentsData.ms || {});
31
+ shouldNotifyUpdate = largeSegments.resetSegments(segmentsData.ls || {}) || shouldNotifyUpdate;
42
32
  }
43
33
  // Notify update if required
44
34
  if (splits.usesSegments() && (shouldNotifyUpdate || readyOnAlreadyExistentState)) {
@@ -10,7 +10,7 @@ import { hash } from '../../../utils/murmur3/murmur3';
10
10
  export function authenticateFactory(fetchAuth) {
11
11
  /**
12
12
  * Run authentication requests to Auth Server, and returns a promise that resolves with the decoded JTW token.
13
- * @param {string[] | undefined} userKeys set of user Keys to track MY_SEGMENTS_CHANGES. It is undefined for server-side API.
13
+ * @param {string[] | undefined} userKeys set of user Keys to track membership updates. It is undefined for server-side API.
14
14
  */
15
15
  return function authenticate(userKeys) {
16
16
  return fetchAuth(userKeys)
@@ -1,6 +1,6 @@
1
1
  import { errorParser, messageParser } from './NotificationParser';
2
2
  import { notificationKeeperFactory } from './NotificationKeeper';
3
- import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, MY_SEGMENTS_UPDATE_V3, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MY_LARGE_SEGMENTS_UPDATE } from '../constants';
3
+ import { PUSH_RETRYABLE_ERROR, PUSH_NONRETRYABLE_ERROR, OCCUPANCY, CONTROL, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, MEMBERSHIP_MS_UPDATE, MEMBERSHIP_LS_UPDATE } from '../constants';
4
4
  import { STREAMING_PARSING_ERROR_FAILS, ERROR_STREAMING_SSE, STREAMING_PARSING_MESSAGE_FAILS, STREAMING_NEW_MESSAGE } from '../../../logger/constants';
5
5
  import { ABLY_ERROR, NON_REQUESTED, SSE_CONNECTION_ERROR } from '../../../utils/constants';
6
6
  /**
@@ -66,18 +66,16 @@ export function SSEHandlerFactory(log, pushEmitter, telemetryTracker) {
66
66
  var parsedData = messageWithParsedData.parsedData, data = messageWithParsedData.data, channel = messageWithParsedData.channel, timestamp = messageWithParsedData.timestamp;
67
67
  log.debug(STREAMING_NEW_MESSAGE, [data]);
68
68
  // we only handle update events if streaming is up
69
- // @ts-expect-error
70
- var type = parsedData.type || parsedData.t;
71
- if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(type) === -1)
69
+ if (!notificationKeeper.isStreamingUp() && [OCCUPANCY, CONTROL].indexOf(parsedData.type) === -1)
72
70
  return;
73
- switch (type) {
71
+ switch (parsedData.type) {
74
72
  /* update events */
75
73
  case SPLIT_UPDATE:
76
74
  case SEGMENT_UPDATE:
77
- case MY_SEGMENTS_UPDATE_V3:
78
- case MY_LARGE_SEGMENTS_UPDATE:
75
+ case MEMBERSHIP_MS_UPDATE:
76
+ case MEMBERSHIP_LS_UPDATE:
79
77
  case SPLIT_KILL:
80
- pushEmitter.emit(type, parsedData);
78
+ pushEmitter.emit(parsedData.type, parsedData);
81
79
  break;
82
80
  /* occupancy & control events, handled by NotificationManagerKeeper */
83
81
  case OCCUPANCY:
@@ -1,8 +1,9 @@
1
1
  import { Backoff } from '../../../utils/Backoff';
2
+ import { MEMBERSHIPS } from '../../../utils/constants';
2
3
  /**
3
4
  * MySegmentsUpdateWorker factory
4
5
  */
5
- export function MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, updateType) {
6
+ export function MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker) {
6
7
  var maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
7
8
  var currentChangeNumber = -1;
8
9
  var handleNewEvent = false;
@@ -30,7 +31,7 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, upd
30
31
  return; // halt if `stop` has been called
31
32
  if (result !== false) { // Unlike `Splits|SegmentsUpdateWorker`, we cannot use `mySegmentsCache.getChangeNumber` since `/mySegments` endpoint doesn't provide this value.
32
33
  if (_segmentsData)
33
- telemetryTracker.trackUpdatesFromSSE(updateType);
34
+ telemetryTracker.trackUpdatesFromSSE(MEMBERSHIPS);
34
35
  currentChangeNumber = Math.max(currentChangeNumber, currentMaxChangeNumber_1); // use `currentMaxChangeNumber`, in case that `maxChangeNumber` was updated during fetch.
35
36
  }
36
37
  if (handleNewEvent) {
@@ -53,13 +54,14 @@ export function MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, upd
53
54
  * @param segmentsData data for KeyList or SegmentRemoval instant updates
54
55
  * @param delay optional time to wait for BoundedFetchRequest or BoundedFetchRequest updates
55
56
  */
56
- put: function (changeNumber, segmentsData, delay) {
57
+ put: function (mySegmentsData, payload, delay) {
58
+ var type = mySegmentsData.type, cn = mySegmentsData.cn;
57
59
  // Ignore event if it is outdated or if there is a pending fetch request (_delay is set)
58
- if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber || _delay)
60
+ if (cn <= currentChangeNumber || cn <= maxChangeNumber || _delay)
59
61
  return;
60
- maxChangeNumber = changeNumber;
62
+ maxChangeNumber = cn;
61
63
  handleNewEvent = true;
62
- _segmentsData = segmentsData;
64
+ _segmentsData = payload && { type: type, cn: cn, added: payload.added, removed: payload.removed };
63
65
  _delay = delay;
64
66
  if (backoff.timeoutID || !isHandlingEvent)
65
67
  __handleMySegmentsUpdateCall();
@@ -22,11 +22,11 @@ export var PUSH_SUBSYSTEM_UP = 'PUSH_SUBSYSTEM_UP';
22
22
  */
23
23
  export var PUSH_SUBSYSTEM_DOWN = 'PUSH_SUBSYSTEM_DOWN';
24
24
  // Update-type push notifications, handled by NotificationProcessor
25
- export var MY_SEGMENTS_UPDATE_V3 = 'MY_SEGMENTS_UPDATE_V3';
25
+ export var MEMBERSHIP_MS_UPDATE = 'MEMBERSHIP_MS_UPDATE';
26
+ export var MEMBERSHIP_LS_UPDATE = 'MEMBERSHIP_LS_UPDATE';
26
27
  export var SEGMENT_UPDATE = 'SEGMENT_UPDATE';
27
28
  export var SPLIT_KILL = 'SPLIT_KILL';
28
29
  export var SPLIT_UPDATE = 'SPLIT_UPDATE';
29
- export var MY_LARGE_SEGMENTS_UPDATE = 'MY_LARGE_SEGMENTS_UPDATE';
30
30
  // Control-type push notifications, handled by NotificationKeeper
31
31
  export var CONTROL = 'CONTROL';
32
32
  export var OCCUPANCY = 'OCCUPANCY';
@@ -8,13 +8,13 @@ import { authenticateFactory, hashUserKey } from './AuthClient';
8
8
  import { forOwn } from '../../utils/lang';
9
9
  import { SSEClient } from './SSEClient';
10
10
  import { getMatching } from '../../utils/key';
11
- import { MY_SEGMENTS_UPDATE_V3, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType, MY_LARGE_SEGMENTS_UPDATE } from './constants';
12
- import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MY_SEGMENTS_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
11
+ import { MEMBERSHIP_MS_UPDATE, MEMBERSHIP_LS_UPDATE, PUSH_NONRETRYABLE_ERROR, PUSH_SUBSYSTEM_DOWN, SECONDS_BEFORE_EXPIRATION, SEGMENT_UPDATE, SPLIT_KILL, SPLIT_UPDATE, PUSH_RETRYABLE_ERROR, PUSH_SUBSYSTEM_UP, ControlType } from './constants';
12
+ import { STREAMING_FALLBACK, STREAMING_REFRESH_TOKEN, STREAMING_CONNECTING, STREAMING_DISABLED, ERROR_STREAMING_AUTH, STREAMING_DISCONNECTING, STREAMING_RECONNECT, STREAMING_PARSING_MEMBERSHIP_UPDATE, STREAMING_PARSING_SPLIT_UPDATE } from '../../logger/constants';
13
13
  import { UpdateStrategy } from './SSEHandler/types';
14
14
  import { getDelay, isInBitmap, parseBitmap, parseFFUpdatePayload, parseKeyList } from './parseUtils';
15
15
  import { _Set } from '../../utils/lang/sets';
16
16
  import { hash64 } from '../../utils/murmur3/murmur3_64';
17
- import { TOKEN_REFRESH, AUTH_REJECTION, MY_LARGE_SEGMENT, MY_SEGMENT } from '../../utils/constants';
17
+ import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
18
18
  /**
19
19
  * PushManager factory:
20
20
  * - for server-side if key is not provided in settings.
@@ -45,10 +45,10 @@ export function pushManagerFactory(params, pollingManager) {
45
45
  var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
46
46
  // For server-side we pass the segmentsSyncTask, used by SplitsUpdateWorker to fetch new segments
47
47
  var splitsUpdateWorker = SplitsUpdateWorker(log, storage.splits, pollingManager.splitsSyncTask, readiness.splits, telemetryTracker, userKey ? undefined : pollingManager.segmentsSyncTask);
48
- // [Only for client-side] map of hashes to user keys, to dispatch MY_SEGMENTS_UPDATE events to the corresponding MySegmentsUpdateWorker
48
+ // [Only for client-side] map of hashes to user keys, to dispatch membership update events to the corresponding MySegmentsUpdateWorker
49
49
  var userKeyHashes = {};
50
50
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
51
- // Hash64 is used to process MY_SEGMENTS_UPDATE events and dispatch actions to the corresponding MySegmentsUpdateWorker.
51
+ // Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
52
52
  var clients = {};
53
53
  // [Only for client-side] variable to flag that a new client was added. It is needed to reconnect streaming.
54
54
  var connectForNewClient = false;
@@ -197,7 +197,7 @@ export function pushManagerFactory(params, pollingManager) {
197
197
  splitsUpdateWorker.put(parsedData);
198
198
  });
199
199
  function handleMySegmentsUpdate(parsedData) {
200
- var isLS = parsedData.t === MY_LARGE_SEGMENTS_UPDATE;
200
+ var isLS = parsedData.type === MEMBERSHIP_LS_UPDATE;
201
201
  switch (parsedData.u) {
202
202
  case UpdateStrategy.BoundedFetchRequest: {
203
203
  var bitmap_1;
@@ -205,13 +205,13 @@ export function pushManagerFactory(params, pollingManager) {
205
205
  bitmap_1 = parseBitmap(parsedData.d, parsedData.c);
206
206
  }
207
207
  catch (e) {
208
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['BoundedFetchRequest', e]);
208
+ log.warn(STREAMING_PARSING_MEMBERSHIP_UPDATE, ['BoundedFetchRequest', e]);
209
209
  break;
210
210
  }
211
211
  forOwn(clients, function (_a, matchingKey) {
212
212
  var hash64 = _a.hash64, worker = _a.worker, workerLarge = _a.workerLarge;
213
213
  if (isInBitmap(bitmap_1, hash64.hex)) {
214
- (isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
214
+ (isLS ? workerLarge : worker).put(parsedData, undefined, getDelay(parsedData, matchingKey));
215
215
  }
216
216
  });
217
217
  return;
@@ -224,51 +224,48 @@ export function pushManagerFactory(params, pollingManager) {
224
224
  removed_1 = new _Set(keyList.r);
225
225
  }
226
226
  catch (e) {
227
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', e]);
227
+ log.warn(STREAMING_PARSING_MEMBERSHIP_UPDATE, ['KeyList', e]);
228
228
  break;
229
229
  }
230
230
  if (!parsedData.n || !parsedData.n.length) {
231
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['KeyList', 'No segment name was provided']);
231
+ log.warn(STREAMING_PARSING_MEMBERSHIP_UPDATE, ['KeyList', 'No segment name was provided']);
232
232
  break;
233
233
  }
234
234
  forOwn(clients, function (_a) {
235
235
  var hash64 = _a.hash64, worker = _a.worker, workerLarge = _a.workerLarge;
236
236
  var add = added_1.has(hash64.dec) ? true : removed_1.has(hash64.dec) ? false : undefined;
237
237
  if (add !== undefined) {
238
- (isLS ? workerLarge : worker).put(parsedData.cn, [{
239
- isLS: isLS,
240
- name: parsedData.n[0],
241
- add: add,
242
- }]);
238
+ (isLS ? workerLarge : worker).put(parsedData, {
239
+ added: add ? [parsedData.n[0]] : [],
240
+ removed: add ? [] : [parsedData.n[0]]
241
+ });
243
242
  }
244
243
  });
245
244
  return;
246
245
  }
247
246
  case UpdateStrategy.SegmentRemoval:
248
247
  if (!parsedData.n || !parsedData.n.length) {
249
- log.warn(STREAMING_PARSING_MY_SEGMENTS_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
248
+ log.warn(STREAMING_PARSING_MEMBERSHIP_UPDATE, ['SegmentRemoval', 'No segment name was provided']);
250
249
  break;
251
250
  }
252
251
  forOwn(clients, function (_a) {
253
252
  var worker = _a.worker, workerLarge = _a.workerLarge;
254
- (isLS ? workerLarge : worker).put(parsedData.cn, parsedData.n.map(function (largeSegment) { return ({
255
- isLS: isLS,
256
- name: largeSegment,
257
- add: false,
258
- cn: parsedData.cn
259
- }); }));
253
+ (isLS ? workerLarge : worker).put(parsedData, {
254
+ added: [],
255
+ removed: parsedData.n
256
+ });
260
257
  });
261
258
  return;
262
259
  }
263
260
  // `UpdateStrategy.UnboundedFetchRequest` and fallbacks of other cases
264
261
  forOwn(clients, function (_a, matchingKey) {
265
262
  var worker = _a.worker, workerLarge = _a.workerLarge;
266
- (isLS ? workerLarge : worker).put(parsedData.cn, undefined, getDelay(parsedData, matchingKey));
263
+ (isLS ? workerLarge : worker).put(parsedData, undefined, getDelay(parsedData, matchingKey));
267
264
  });
268
265
  }
269
266
  if (userKey) {
270
- pushEmitter.on(MY_SEGMENTS_UPDATE_V3, handleMySegmentsUpdate);
271
- pushEmitter.on(MY_LARGE_SEGMENTS_UPDATE, handleMySegmentsUpdate);
267
+ pushEmitter.on(MEMBERSHIP_MS_UPDATE, handleMySegmentsUpdate);
268
+ pushEmitter.on(MEMBERSHIP_LS_UPDATE, handleMySegmentsUpdate);
272
269
  }
273
270
  else {
274
271
  pushEmitter.on(SEGMENT_UPDATE, segmentsUpdateWorker.put);
@@ -306,8 +303,8 @@ export function pushManagerFactory(params, pollingManager) {
306
303
  userKeyHashes[hash] = userKey;
307
304
  clients[userKey] = {
308
305
  hash64: hash64(userKey),
309
- worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_SEGMENT),
310
- workerLarge: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker, MY_LARGE_SEGMENT)
306
+ worker: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker),
307
+ workerLarge: MySegmentsUpdateWorker(mySegmentsSyncTask, telemetryTracker)
311
308
  };
312
309
  connectForNewClient = true; // we must reconnect on start, to listen the channel for the new user key
313
310
  // Reconnects in case of a new client.
@@ -60,8 +60,7 @@ export var EVENTS = 'ev';
60
60
  export var TELEMETRY = 'te';
61
61
  export var TOKEN = 'to';
62
62
  export var SEGMENT = 'se';
63
- export var MY_SEGMENT = 'ms';
64
- export var MY_LARGE_SEGMENT = 'mls';
63
+ export var MEMBERSHIPS = 'ms';
65
64
  export var TREATMENT = 't';
66
65
  export var TREATMENTS = 'ts';
67
66
  export var TREATMENT_WITH_CONFIG = 'tc';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.16.1-rc.10",
3
+ "version": "1.16.1-rc.11",
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
@@ -224,20 +224,17 @@ export interface ISegmentChangesResponse {
224
224
  till: number
225
225
  }
226
226
 
227
+ export interface IMySegmentsResponse {
228
+ cn?: number,
229
+ k?: {
230
+ n: string
231
+ }[]
232
+ }
233
+
227
234
  /** Interface of the parsed JSON response of `/memberships/{userKey}` */
228
235
  export interface IMembershipsResponse {
229
- ms?: {
230
- cn?: number,
231
- k?: Array<{
232
- n: string
233
- }>
234
- },
235
- ls?: {
236
- cn?: number,
237
- k?: Array<{
238
- n: string
239
- }>
240
- }
236
+ ms?: IMySegmentsResponse,
237
+ ls?: IMySegmentsResponse
241
238
  }
242
239
 
243
240
  /** Metadata internal type for storages */
@@ -79,7 +79,7 @@ export const WARN_SPLITS_FILTER_IGNORED = 219;
79
79
  export const WARN_SPLITS_FILTER_INVALID = 220;
80
80
  export const WARN_SPLITS_FILTER_EMPTY = 221;
81
81
  export const WARN_SDK_KEY = 222;
82
- export const STREAMING_PARSING_MY_SEGMENTS_UPDATE = 223;
82
+ export const STREAMING_PARSING_MEMBERSHIP_UPDATE = 223;
83
83
  export const STREAMING_PARSING_SPLIT_UPDATE = 224;
84
84
  export const WARN_INVALID_FLAGSET = 225;
85
85
  export const WARN_LOWERCASE_FLAGSET = 226;
@@ -32,7 +32,7 @@ export const codesWarn: [number, string][] = codesError.concat([
32
32
  [c.WARN_SPLITS_FILTER_EMPTY, c.LOG_PREFIX_SETTINGS + ': feature flag filter configuration must be a non-empty array of filter objects.'],
33
33
  [c.WARN_SDK_KEY, c.LOG_PREFIX_SETTINGS + ': You already have %s. We recommend keeping only one instance of the factory at all times (Singleton pattern) and reusing it throughout your application'],
34
34
 
35
- [c.STREAMING_PARSING_MY_SEGMENTS_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching Memberships due to an error processing %s notification: %s'],
35
+ [c.STREAMING_PARSING_MEMBERSHIP_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching Memberships due to an error processing %s notification: %s'],
36
36
  [c.STREAMING_PARSING_SPLIT_UPDATE, c.LOG_PREFIX_SYNC_STREAMING + 'Fetching SplitChanges due to an error processing SPLIT_UPDATE notification: %s'],
37
37
  [c.WARN_INVALID_FLAGSET, '%s: you passed %s, flag set must adhere to the regular expressions %s. This means a flag set must start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.'],
38
38
  [c.WARN_LOWERCASE_FLAGSET, '%s: flag set %s should be all lowercase - converting string to lowercase.'],
@@ -4,7 +4,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
4
4
  import { ISplitApi } from './types';
5
5
  import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { ITelemetryTracker } from '../trackers/types';
7
- import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
7
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MEMBERSHIPS } from '../utils/constants';
8
8
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
9
9
 
10
10
  const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
@@ -75,7 +75,7 @@ export function splitApiFactory(
75
75
  * - match user keys with special characters. E.g.: 'foo%bar', 'foo/bar'
76
76
  */
77
77
  const url = `${urls.sdk}/memberships/${encodeURIComponent(userMatchingKey)}`;
78
- return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MY_SEGMENT));
78
+ return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(MEMBERSHIPS));
79
79
  },
80
80
 
81
81
  /**