@splitsoftware/splitio-commons 3.1.1-rc.11 → 3.1.1-rc.12

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 (62) hide show
  1. package/CHANGES.txt +1 -0
  2. package/cjs/services/authProvider.js +2 -2
  3. package/cjs/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
  4. package/cjs/services/splitApi.js +2 -2
  5. package/cjs/storages/inLocalStorage/DefinitionsCacheInLocal.js +2 -1
  6. package/cjs/storages/inLocalStorage/RBSegmentsCacheInLocal.js +2 -1
  7. package/cjs/storages/inMemory/DefinitionsCacheInMemory.js +2 -1
  8. package/cjs/storages/inMemory/RBSegmentsCacheInMemory.js +2 -1
  9. package/cjs/storages/inRedis/DefinitionsCacheInRedis.js +3 -1
  10. package/cjs/storages/inRedis/RBSegmentsCacheInRedis.js +3 -1
  11. package/cjs/storages/pluggable/DefinitionsCachePluggable.js +3 -1
  12. package/cjs/storages/pluggable/RBSegmentsCachePluggable.js +3 -1
  13. package/cjs/sync/polling/fetchers/splitChangesFetcher.js +1 -1
  14. package/cjs/sync/polling/updaters/definitionChangesUpdater.js +14 -4
  15. package/cjs/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +5 -3
  16. package/cjs/sync/streaming/parseUtils.js +4 -4
  17. package/cjs/sync/streaming/pushManager.js +4 -3
  18. package/esm/services/authProvider.js +1 -1
  19. package/esm/{sync/streaming/AuthClient/index.js → services/fetchAuth.js} +2 -2
  20. package/esm/services/splitApi.js +1 -1
  21. package/esm/storages/inLocalStorage/DefinitionsCacheInLocal.js +2 -1
  22. package/esm/storages/inLocalStorage/RBSegmentsCacheInLocal.js +2 -1
  23. package/esm/storages/inMemory/DefinitionsCacheInMemory.js +2 -1
  24. package/esm/storages/inMemory/RBSegmentsCacheInMemory.js +2 -1
  25. package/esm/storages/inRedis/DefinitionsCacheInRedis.js +3 -1
  26. package/esm/storages/inRedis/RBSegmentsCacheInRedis.js +3 -1
  27. package/esm/storages/pluggable/DefinitionsCachePluggable.js +3 -1
  28. package/esm/storages/pluggable/RBSegmentsCachePluggable.js +3 -1
  29. package/esm/sync/polling/fetchers/splitChangesFetcher.js +1 -1
  30. package/esm/sync/polling/updaters/definitionChangesUpdater.js +14 -4
  31. package/esm/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.js +6 -4
  32. package/esm/sync/streaming/parseUtils.js +2 -2
  33. package/esm/sync/streaming/pushManager.js +4 -3
  34. package/package.json +1 -1
  35. package/src/dtos/types.ts +4 -4
  36. package/src/services/authProvider.ts +2 -2
  37. package/src/{sync/streaming/AuthClient/index.ts → services/fetchAuth.ts} +3 -4
  38. package/src/services/splitApi.ts +1 -1
  39. package/src/services/types.ts +21 -4
  40. package/src/storages/AbstractDefinitionsCacheAsync.ts +3 -3
  41. package/src/storages/AbstractDefinitionsCacheSync.ts +2 -2
  42. package/src/storages/inLocalStorage/DefinitionsCacheInLocal.ts +2 -2
  43. package/src/storages/inLocalStorage/RBSegmentsCacheInLocal.ts +3 -3
  44. package/src/storages/inMemory/DefinitionsCacheInMemory.ts +2 -2
  45. package/src/storages/inMemory/RBSegmentsCacheInMemory.ts +2 -2
  46. package/src/storages/inRedis/DefinitionsCacheInRedis.ts +6 -4
  47. package/src/storages/inRedis/RBSegmentsCacheInRedis.ts +7 -5
  48. package/src/storages/pluggable/DefinitionsCachePluggable.ts +4 -2
  49. package/src/storages/pluggable/RBSegmentsCachePluggable.ts +5 -3
  50. package/src/storages/types.ts +6 -6
  51. package/src/sync/polling/fetchers/splitChangesFetcher.ts +5 -5
  52. package/src/sync/polling/types.ts +22 -1
  53. package/src/sync/polling/updaters/definitionChangesUpdater.ts +26 -20
  54. package/src/sync/streaming/SSEClient/index.ts +1 -1
  55. package/src/sync/streaming/SSEClient/types.ts +1 -1
  56. package/src/sync/streaming/UpdateWorkers/DefinitionsUpdateWorker.ts +15 -11
  57. package/src/sync/streaming/UpdateWorkers/types.ts +6 -0
  58. package/src/sync/streaming/parseUtils.ts +3 -4
  59. package/src/sync/streaming/pushManager.ts +4 -3
  60. package/cjs/sync/streaming/AuthClient/types.js +0 -2
  61. package/esm/sync/streaming/AuthClient/types.js +0 -1
  62. package/src/sync/streaming/AuthClient/types.ts +0 -19
package/CHANGES.txt CHANGED
@@ -1,4 +1,5 @@
1
1
  3.2.0 (XXX XX, 2026)
2
+ - Added support for streaming in the Configs SDK, handling CONFIG_UPDATE notifications. Unlike feature flag notifications, the previous change number of CONFIG_UPDATE and RB_SEGMENT_UPDATE notifications are scoped to the referenced entity rather than to the environment, and so instant updates are applied without updating the storage change number.
2
3
  - Added support for AI configs.
3
4
  - Added support for ioredis v6 (Related to issue https://github.com/splitio/javascript-client/issues/951). Note that ioredis v6 requires Node.js 20 or above; stay on ioredis v4 or v5 for older Node.js versions.
4
5
  - Removed the `@types/ioredis` dependency, which is no longer required since the public type definitions don't depend on ioredis types. The `@types/node` dependency, previously installed transitively by `@types/ioredis`, is now declared explicitly, since the public type definitions use Node.js types for the `agent` and `tls` options.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.authProviderFactory = void 0;
4
- var AuthClient_1 = require("../sync/streaming/AuthClient");
4
+ var fetchAuth_1 = require("./fetchAuth");
5
5
  var Backoff_1 = require("../utils/Backoff");
6
6
  var constants_1 = require("../logger/constants");
7
7
  var constants_2 = require("../utils/constants");
@@ -18,7 +18,7 @@ function noCachedCredentialError() {
18
18
  */
19
19
  function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
20
20
  var urls = settings.urls, log = settings.log;
21
- var fetchAuth = (0, AuthClient_1.fetchAuthFactory)(function () {
21
+ var fetchAuth = (0, fetchAuth_1.fetchAuthFactory)(function () {
22
22
  var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
23
23
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
24
24
  });
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.fetchAuthFactory = void 0;
4
- var objectAssign_1 = require("../../../utils/lang/objectAssign");
5
- var jwt_1 = require("../../../utils/jwt");
4
+ var objectAssign_1 = require("../utils/lang/objectAssign");
5
+ var jwt_1 = require("../utils/jwt");
6
6
  /**
7
7
  * Factory of authentication function.
8
8
  *
@@ -5,7 +5,7 @@ var splitHttpClient_1 = require("./splitHttpClient");
5
5
  var objectAssign_1 = require("../utils/lang/objectAssign");
6
6
  var constants_1 = require("../utils/constants");
7
7
  var constants_2 = require("../logger/constants");
8
- var AuthClient_1 = require("../sync/streaming/AuthClient");
8
+ var fetchAuth_1 = require("./fetchAuth");
9
9
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
10
10
  function userKeyToQueryParam(userKey) {
11
11
  return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
@@ -24,7 +24,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
24
24
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
25
25
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
26
26
  return {
27
- fetchAuth: (0, AuthClient_1.fetchAuthFactory)(function (userMatchingKeys) {
27
+ fetchAuth: (0, fetchAuth_1.fetchAuthFactory)(function (userMatchingKeys) {
28
28
  var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
29
29
  if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
30
30
  var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
@@ -98,7 +98,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
98
98
  };
99
99
  DefinitionsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
100
100
  try {
101
- this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
101
+ if (changeNumber !== undefined)
102
+ this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
102
103
  // update "last updated" timestamp with current time
103
104
  this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
104
105
  this.hasSync = true;
@@ -25,7 +25,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
25
25
  };
26
26
  RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
27
27
  try {
28
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
28
+ if (changeNumber !== undefined)
29
+ this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
29
30
  this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
30
31
  }
31
32
  catch (e) {
@@ -70,7 +70,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
70
70
  return this.definitionsCache[name] || null;
71
71
  };
72
72
  DefinitionsCacheInMemory.prototype.setChangeNumber = function (changeNumber) {
73
- this.changeNumber = changeNumber;
73
+ if (changeNumber !== undefined)
74
+ this.changeNumber = changeNumber;
74
75
  return true;
75
76
  };
76
77
  DefinitionsCacheInMemory.prototype.getChangeNumber = function () {
@@ -18,7 +18,8 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
18
18
  var _this = this;
19
19
  var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
20
20
  updated = toRemove.map(function (toRemove) { return _this.remove(toRemove); }).some(function (result) { return result; }) || updated;
21
- this.changeNumber = changeNumber;
21
+ if (changeNumber !== undefined)
22
+ this.changeNumber = changeNumber;
22
23
  return updated;
23
24
  };
24
25
  RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
@@ -126,7 +126,9 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
126
126
  * or rejected if it fails.
127
127
  */
128
128
  DefinitionsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
129
- return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
129
+ if (changeNumber !== undefined) {
130
+ return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
131
+ }
130
132
  };
131
133
  /**
132
134
  * Get till number or -1 if it's not defined.
@@ -43,7 +43,9 @@ var RBSegmentsCacheInRedis = /** @class */ (function () {
43
43
  });
44
44
  };
45
45
  RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
46
- return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
46
+ if (changeNumber !== undefined) {
47
+ return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
48
+ }
47
49
  };
48
50
  RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
49
51
  var _this = this;
@@ -186,7 +186,9 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
186
186
  * or rejected if it fails (e.g., wrapper operation fails).
187
187
  */
188
188
  DefinitionsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
189
- return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
189
+ if (changeNumber !== undefined) {
190
+ return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
191
+ }
190
192
  };
191
193
  /**
192
194
  * Get till number or -1 if it's not defined.
@@ -43,7 +43,9 @@ var RBSegmentsCachePluggable = /** @class */ (function () {
43
43
  });
44
44
  };
45
45
  RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
46
- return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
46
+ if (changeNumber !== undefined) {
47
+ return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
48
+ }
47
49
  };
48
50
  RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
49
51
  var _this = this;
@@ -16,7 +16,7 @@ function isSplitChangesLegacyResponse(data) {
16
16
  function partitionByStatus(items, till, since) {
17
17
  var updated = [], removed = [];
18
18
  items.forEach(function (item) { return item.status === 'ARCHIVED' ? removed.push(item.name) : updated.push(item); });
19
- return { updated: updated, removed: removed, till: till, since: since };
19
+ return { updated: updated, removed: removed, till: till, since: since !== null && since !== void 0 ? since : undefined };
20
20
  }
21
21
  /**
22
22
  * Factory of SplitChanges fetcher.
@@ -8,6 +8,7 @@ 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
+ var thenable_1 = require("../../../utils/promise/thenable");
11
12
  /**
12
13
  * Collect segments from a raw FF or RBS definition.
13
14
  * Exported for testing purposes.
@@ -115,7 +116,7 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
115
116
  * @param noCache - true to revalidate data to fetch
116
117
  * @param till - query param to bypass CDN requests
117
118
  */
118
- return function definitionChangesUpdater(noCache, till, instantUpdate) {
119
+ return function definitionChangesUpdater(noCache, till, instantUpdate, pcns) {
119
120
  /**
120
121
  * @param since - current changeNumber at definitionsCache
121
122
  * @param retry - current number of retry attempts
@@ -123,8 +124,14 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
123
124
  function _definitionChangesUpdater(sinces, retry) {
124
125
  if (retry === void 0) { retry = 0; }
125
126
  var since = sinces[0], rbSince = sinces[1];
126
- log.debug(constants_2.SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
127
- return Promise.resolve(instantUpdate ?
127
+ // If provided, `since` and `rbSince` must not be higher than it, to avoid missing an update that the scoped `pcn` indicates hasn't been fetched yet.
128
+ if (pcns) {
129
+ if (pcns.since !== undefined && pcns.since < since)
130
+ since = pcns.since;
131
+ if (pcns.rbSince !== undefined && pcns.rbSince < rbSince)
132
+ rbSince = pcns.rbSince;
133
+ }
134
+ var definitionChangesRequest = instantUpdate ?
128
135
  instantUpdate.type === constants_4.RB_SEGMENT_UPDATE ?
129
136
  { rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
130
137
  // IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
@@ -133,7 +140,10 @@ function definitionChangesUpdaterFactory(log, definitionChangesFetcher, storage,
133
140
  { d: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
134
141
  definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
135
142
  }) :
136
- definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
143
+ definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
144
+ if ((0, thenable_1.thenable)(definitionChangesRequest))
145
+ log.debug(constants_2.SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
146
+ return Promise.resolve(definitionChangesRequest)
137
147
  .then(function (definitionChanges) {
138
148
  var usedSegments = new Set();
139
149
  var updatedDefinitions = [];
@@ -9,9 +9,11 @@ var constants_4 = require("../constants");
9
9
  var parseUtils_1 = require("../parseUtils");
10
10
  var constants_5 = require("./constants");
11
11
  /**
12
- * DefinitionsUpdateWorker factory
12
+ * DefinitionsUpdateWorker factory for Flags SDKs, where notifications pcn and changeNumber are environment-scoped
13
13
  */
14
- function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
14
+ function DefinitionsUpdateWorker(params, pollingManager) {
15
+ var log = params.settings.log, storage = params.storage, telemetryTracker = params.telemetryTracker, definitionsEventEmitter = params.readiness.definitions;
16
+ var definitionsSyncTask = pollingManager.definitionsSyncTask;
15
17
  var ff = DefinitionsUpdateWorker(storage.definitions);
16
18
  var rbs = DefinitionsUpdateWorker(storage.rbSegments);
17
19
  function DefinitionsUpdateWorker(cache) {
@@ -96,7 +98,7 @@ function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsE
96
98
  put: function (parsedData) {
97
99
  if (parsedData.d && parsedData.c !== undefined) {
98
100
  try {
99
- var payload = (0, parseUtils_1.parseFFUpdatePayload)(parsedData.c, parsedData.d);
101
+ var payload = (0, parseUtils_1.parseUpdatePayload)(parsedData.c, parsedData.d);
100
102
  if (payload) {
101
103
  (parsedData.type === constants_4.RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
102
104
  return;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getDelay = exports.parseFFUpdatePayload = exports.isInBitmap = exports.parseBitmap = exports.parseCompressedData = void 0;
3
+ exports.getDelay = exports.parseUpdatePayload = exports.isInBitmap = exports.parseBitmap = exports.parseCompressedData = void 0;
4
4
  var decompress_1 = require("../../utils/decompress");
5
5
  var base64_1 = require("../../utils/base64");
6
6
  var murmur3_1 = require("../../utils/murmur3/murmur3");
@@ -79,14 +79,14 @@ function isInBitmap(bitmap, hash64hex) {
79
79
  }
80
80
  exports.isInBitmap = isInBitmap;
81
81
  /**
82
- * Parse feature flags notifications for instant feature flag updates
82
+ * Parse notifications for instant updates
83
83
  */
84
- function parseFFUpdatePayload(compression, data) {
84
+ function parseUpdatePayload(compression, data) {
85
85
  return compression > 0 ?
86
86
  parseCompressedData(data, compression, false) :
87
87
  JSON.parse((0, base64_1.decodeFromBase64)(data));
88
88
  }
89
- exports.parseFFUpdatePayload = parseFFUpdatePayload;
89
+ exports.parseUpdatePayload = parseUpdatePayload;
90
90
  var DEFAULT_MAX_INTERVAL = 60000;
91
91
  function getDelay(parsedData, matchingKey) {
92
92
  if (parsedData.h === 0)
@@ -21,8 +21,9 @@ var constants_3 = require("../../utils/constants");
21
21
  * - for server-side if key is not provided in settings.
22
22
  * - for client-side, with support for multiple clients, if key is provided in settings
23
23
  */
24
- function pushManagerFactory(params, pollingManager) {
25
- var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, readiness = params.readiness, platform = params.platform, telemetryTracker = params.telemetryTracker;
24
+ function pushManagerFactory(params, pollingManager, definitionsUpdateWorkerFactory) {
25
+ if (definitionsUpdateWorkerFactory === void 0) { definitionsUpdateWorkerFactory = DefinitionsUpdateWorker_1.DefinitionsUpdateWorker; }
26
+ var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, platform = params.platform, telemetryTracker = params.telemetryTracker;
26
27
  // `userKey` is the matching key of main client in client-side SDK.
27
28
  // It can be used to check if running on client-side or server-side SDK.
28
29
  var userKey = (0, key_1.checkIfServerSide)(settings) ? undefined : (0, key_1.getMatching)(settings.core.key);
@@ -44,7 +45,7 @@ function pushManagerFactory(params, pollingManager) {
44
45
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
45
46
  var segmentsUpdateWorker = userKey ? undefined : (0, SegmentsUpdateWorker_1.SegmentsUpdateWorker)(log, pollingManager.segmentsSyncTask, storage.segments);
46
47
  // For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
47
- var definitionsUpdateWorker = (0, DefinitionsUpdateWorker_1.DefinitionsUpdateWorker)(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
48
+ var definitionsUpdateWorker = definitionsUpdateWorkerFactory(params, pollingManager);
48
49
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
49
50
  // Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
50
51
  var clients = {};
@@ -1,4 +1,4 @@
1
- import { fetchAuthFactory } from '../sync/streaming/AuthClient';
1
+ import { fetchAuthFactory } from './fetchAuth';
2
2
  import { Backoff } from '../utils/Backoff';
3
3
  import { LOG_PREFIX_SYNC_AUTH } from '../logger/constants';
4
4
  import { TOKEN } from '../utils/constants';
@@ -1,5 +1,5 @@
1
- import { objectAssign } from '../../../utils/lang/objectAssign';
2
- import { decodeJWTtoken } from '../../../utils/jwt';
1
+ import { objectAssign } from '../utils/lang/objectAssign';
2
+ import { decodeJWTtoken } from '../utils/jwt';
3
3
  /**
4
4
  * Factory of authentication function.
5
5
  *
@@ -2,7 +2,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
2
2
  import { objectAssign } from '../utils/lang/objectAssign';
3
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
- import { fetchAuthFactory } from '../sync/streaming/AuthClient';
5
+ import { fetchAuthFactory } from './fetchAuth';
6
6
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
7
7
  function userKeyToQueryParam(userKey) {
8
8
  return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
@@ -95,7 +95,8 @@ var DefinitionsCacheInLocal = /** @class */ (function (_super) {
95
95
  };
96
96
  DefinitionsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
97
97
  try {
98
- this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
98
+ if (changeNumber !== undefined)
99
+ this.storage.setItem(this.keys.buildDefinitionsTillKey(), changeNumber + '');
99
100
  // update "last updated" timestamp with current time
100
101
  this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
101
102
  this.hasSync = true;
@@ -22,7 +22,8 @@ var RBSegmentsCacheInLocal = /** @class */ (function () {
22
22
  };
23
23
  RBSegmentsCacheInLocal.prototype.setChangeNumber = function (changeNumber) {
24
24
  try {
25
- this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
25
+ if (changeNumber !== undefined)
26
+ this.storage.setItem(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
26
27
  this.storage.setItem(this.keys.buildLastUpdatedKey(), Date.now() + '');
27
28
  }
28
29
  catch (e) {
@@ -67,7 +67,8 @@ var DefinitionsCacheInMemory = /** @class */ (function (_super) {
67
67
  return this.definitionsCache[name] || null;
68
68
  };
69
69
  DefinitionsCacheInMemory.prototype.setChangeNumber = function (changeNumber) {
70
- this.changeNumber = changeNumber;
70
+ if (changeNumber !== undefined)
71
+ this.changeNumber = changeNumber;
71
72
  return true;
72
73
  };
73
74
  DefinitionsCacheInMemory.prototype.getChangeNumber = function () {
@@ -15,7 +15,8 @@ var RBSegmentsCacheInMemory = /** @class */ (function () {
15
15
  var _this = this;
16
16
  var updated = toAdd.map(function (toAdd) { return _this.add(toAdd); }).some(function (result) { return result; });
17
17
  updated = toRemove.map(function (toRemove) { return _this.remove(toRemove); }).some(function (result) { return result; }) || updated;
18
- this.changeNumber = changeNumber;
18
+ if (changeNumber !== undefined)
19
+ this.changeNumber = changeNumber;
19
20
  return updated;
20
21
  };
21
22
  RBSegmentsCacheInMemory.prototype.add = function (rbSegment) {
@@ -123,7 +123,9 @@ var DefinitionsCacheInRedis = /** @class */ (function (_super) {
123
123
  * or rejected if it fails.
124
124
  */
125
125
  DefinitionsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
126
- return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
126
+ if (changeNumber !== undefined) {
127
+ return this.redis.set(this.keys.buildDefinitionsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
128
+ }
127
129
  };
128
130
  /**
129
131
  * Get till number or -1 if it's not defined.
@@ -40,7 +40,9 @@ var RBSegmentsCacheInRedis = /** @class */ (function () {
40
40
  });
41
41
  };
42
42
  RBSegmentsCacheInRedis.prototype.setChangeNumber = function (changeNumber) {
43
- return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
43
+ if (changeNumber !== undefined) {
44
+ return this.redis.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '').then(function (status) { return status === 'OK'; });
45
+ }
44
46
  };
45
47
  RBSegmentsCacheInRedis.prototype.getChangeNumber = function () {
46
48
  var _this = this;
@@ -183,7 +183,9 @@ var DefinitionsCachePluggable = /** @class */ (function (_super) {
183
183
  * or rejected if it fails (e.g., wrapper operation fails).
184
184
  */
185
185
  DefinitionsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
186
- return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
186
+ if (changeNumber !== undefined) {
187
+ return this.wrapper.set(this.keys.buildDefinitionsTillKey(), changeNumber + '');
188
+ }
187
189
  };
188
190
  /**
189
191
  * Get till number or -1 if it's not defined.
@@ -40,7 +40,9 @@ var RBSegmentsCachePluggable = /** @class */ (function () {
40
40
  });
41
41
  };
42
42
  RBSegmentsCachePluggable.prototype.setChangeNumber = function (changeNumber) {
43
- return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
43
+ if (changeNumber !== undefined) {
44
+ return this.wrapper.set(this.keys.buildRBSegmentsTillKey(), changeNumber + '');
45
+ }
44
46
  };
45
47
  RBSegmentsCachePluggable.prototype.getChangeNumber = function () {
46
48
  var _this = this;
@@ -13,7 +13,7 @@ function isSplitChangesLegacyResponse(data) {
13
13
  function partitionByStatus(items, till, since) {
14
14
  var updated = [], removed = [];
15
15
  items.forEach(function (item) { return item.status === 'ARCHIVED' ? removed.push(item.name) : updated.push(item); });
16
- return { updated: updated, removed: removed, till: till, since: since };
16
+ return { updated: updated, removed: removed, till: till, since: since !== null && since !== void 0 ? since : undefined };
17
17
  }
18
18
  /**
19
19
  * Factory of SplitChanges fetcher.
@@ -5,6 +5,7 @@ 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 { RB_SEGMENT_UPDATE } from '../../streaming/constants';
8
+ import { thenable } from '../../../utils/promise/thenable';
8
9
  /**
9
10
  * Collect segments from a raw FF or RBS definition.
10
11
  * Exported for testing purposes.
@@ -110,7 +111,7 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
110
111
  * @param noCache - true to revalidate data to fetch
111
112
  * @param till - query param to bypass CDN requests
112
113
  */
113
- return function definitionChangesUpdater(noCache, till, instantUpdate) {
114
+ return function definitionChangesUpdater(noCache, till, instantUpdate, pcns) {
114
115
  /**
115
116
  * @param since - current changeNumber at definitionsCache
116
117
  * @param retry - current number of retry attempts
@@ -118,8 +119,14 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
118
119
  function _definitionChangesUpdater(sinces, retry) {
119
120
  if (retry === void 0) { retry = 0; }
120
121
  var since = sinces[0], rbSince = sinces[1];
121
- log.debug(SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
122
- return Promise.resolve(instantUpdate ?
122
+ // If provided, `since` and `rbSince` must not be higher than it, to avoid missing an update that the scoped `pcn` indicates hasn't been fetched yet.
123
+ if (pcns) {
124
+ if (pcns.since !== undefined && pcns.since < since)
125
+ since = pcns.since;
126
+ if (pcns.rbSince !== undefined && pcns.rbSince < rbSince)
127
+ rbSince = pcns.rbSince;
128
+ }
129
+ var definitionChangesRequest = instantUpdate ?
123
130
  instantUpdate.type === RB_SEGMENT_UPDATE ?
124
131
  { rbs: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
125
132
  // IFFU edge case: a change to definition that adds an IN_RULE_BASED_SEGMENT matcher that is not present yet
@@ -128,7 +135,10 @@ export function definitionChangesUpdaterFactory(log, definitionChangesFetcher, s
128
135
  { d: convertInstantUpdateToDefinitionChanges(instantUpdate) } :
129
136
  definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
130
137
  }) :
131
- definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator))
138
+ definitionChangesFetcher(since, noCache, till, rbSince, _promiseDecorator);
139
+ if (thenable(definitionChangesRequest))
140
+ log.debug(SYNC_FETCH, [definitionChangesFetcher.type, since, rbSince]);
141
+ return Promise.resolve(definitionChangesRequest)
132
142
  .then(function (definitionChanges) {
133
143
  var usedSegments = new Set();
134
144
  var updatedDefinitions = [];
@@ -3,12 +3,14 @@ import { SDK_DEFINITIONS_ARRIVED } from '../../../readiness/constants';
3
3
  import { Backoff } from '../../../utils/Backoff';
4
4
  import { SPLITS } from '../../../utils/constants';
5
5
  import { RB_SEGMENT_UPDATE } from '../constants';
6
- import { parseFFUpdatePayload } from '../parseUtils';
6
+ import { parseUpdatePayload } from '../parseUtils';
7
7
  import { FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT, FETCH_BACKOFF_MAX_RETRIES } from './constants';
8
8
  /**
9
- * DefinitionsUpdateWorker factory
9
+ * DefinitionsUpdateWorker factory for Flags SDKs, where notifications pcn and changeNumber are environment-scoped
10
10
  */
11
- export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, definitionsEventEmitter, telemetryTracker) {
11
+ export function DefinitionsUpdateWorker(params, pollingManager) {
12
+ var log = params.settings.log, storage = params.storage, telemetryTracker = params.telemetryTracker, definitionsEventEmitter = params.readiness.definitions;
13
+ var definitionsSyncTask = pollingManager.definitionsSyncTask;
12
14
  var ff = DefinitionsUpdateWorker(storage.definitions);
13
15
  var rbs = DefinitionsUpdateWorker(storage.rbSegments);
14
16
  function DefinitionsUpdateWorker(cache) {
@@ -93,7 +95,7 @@ export function DefinitionsUpdateWorker(log, storage, definitionsSyncTask, defin
93
95
  put: function (parsedData) {
94
96
  if (parsedData.d && parsedData.c !== undefined) {
95
97
  try {
96
- var payload = parseFFUpdatePayload(parsedData.c, parsedData.d);
98
+ var payload = parseUpdatePayload(parsedData.c, parsedData.d);
97
99
  if (payload) {
98
100
  (parsedData.type === RB_SEGMENT_UPDATE ? rbs : ff).put(parsedData, payload);
99
101
  return;
@@ -73,9 +73,9 @@ export function isInBitmap(bitmap, hash64hex) {
73
73
  return (bitmap[internal] & 1 << offset) > 0;
74
74
  }
75
75
  /**
76
- * Parse feature flags notifications for instant feature flag updates
76
+ * Parse notifications for instant updates
77
77
  */
78
- export function parseFFUpdatePayload(compression, data) {
78
+ export function parseUpdatePayload(compression, data) {
79
79
  return compression > 0 ?
80
80
  parseCompressedData(data, compression, false) :
81
81
  JSON.parse(decodeFromBase64(data));
@@ -18,8 +18,9 @@ import { TOKEN_REFRESH, AUTH_REJECTION } from '../../utils/constants';
18
18
  * - for server-side if key is not provided in settings.
19
19
  * - for client-side, with support for multiple clients, if key is provided in settings
20
20
  */
21
- export function pushManagerFactory(params, pollingManager) {
22
- var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, readiness = params.readiness, platform = params.platform, telemetryTracker = params.telemetryTracker;
21
+ export function pushManagerFactory(params, pollingManager, definitionsUpdateWorkerFactory) {
22
+ if (definitionsUpdateWorkerFactory === void 0) { definitionsUpdateWorkerFactory = DefinitionsUpdateWorker; }
23
+ var settings = params.settings, storage = params.storage, serviceApi = params.serviceApi, platform = params.platform, telemetryTracker = params.telemetryTracker;
23
24
  // `userKey` is the matching key of main client in client-side SDK.
24
25
  // It can be used to check if running on client-side or server-side SDK.
25
26
  var userKey = checkIfServerSide(settings) ? undefined : getMatching(settings.core.key);
@@ -41,7 +42,7 @@ export function pushManagerFactory(params, pollingManager) {
41
42
  // MySegmentsUpdateWorker (client-side) are initiated in `add` method
42
43
  var segmentsUpdateWorker = userKey ? undefined : SegmentsUpdateWorker(log, pollingManager.segmentsSyncTask, storage.segments);
43
44
  // For server-side we pass the segmentsSyncTask, used by DefinitionsUpdateWorker to fetch new segments
44
- var definitionsUpdateWorker = DefinitionsUpdateWorker(log, storage, pollingManager.definitionsSyncTask, readiness.definitions, telemetryTracker);
45
+ var definitionsUpdateWorker = definitionsUpdateWorkerFactory(params, pollingManager);
45
46
  // [Only for client-side] map of user keys to their corresponding hash64 and MySegmentsUpdateWorkers.
46
47
  // Hash64 is used to process membership update events and dispatch actions to the corresponding MySegmentsUpdateWorker.
47
48
  var clients = {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "3.1.1-rc.11",
3
+ "version": "3.1.1-rc.12",
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
@@ -243,14 +243,14 @@ export interface IDefinition extends TargetingEntity {
243
243
  /** Interface of the parsed JSON response of `/splitChanges` */
244
244
  export interface IDefinitionChangesResponse {
245
245
  d?: {
246
- till: number,
247
- since?: number | null,
246
+ till?: number,
247
+ since?: number,
248
248
  updated: IDefinition[],
249
249
  removed: string[],
250
250
  },
251
251
  rbs?: {
252
- till: number,
253
- since?: number | null,
252
+ till?: number,
253
+ since?: number,
254
254
  updated: IRBSegment[],
255
255
  removed: string[],
256
256
  }
@@ -1,6 +1,6 @@
1
1
  import { ISplitHttpClient, NetworkError } from './types';
2
- import { IJwtCredential } from '../sync/streaming/AuthClient/types';
3
- import { fetchAuthFactory } from '../sync/streaming/AuthClient';
2
+ import { IJwtCredential } from './types';
3
+ import { fetchAuthFactory } from './fetchAuth';
4
4
  import { Backoff } from '../utils/Backoff';
5
5
  import { LOG_PREFIX_SYNC_AUTH } from '../logger/constants';
6
6
  import { ISettings } from '../types';
@@ -1,7 +1,6 @@
1
- import { IJwtCredential, IFetchAuth } from './types';
2
- import { objectAssign } from '../../../utils/lang/objectAssign';
3
- import { decodeJWTtoken } from '../../../utils/jwt';
4
- import { IResponse } from '../../../services/types';
1
+ import { IJwtCredential, IFetchAuth, IResponse } from './types';
2
+ import { objectAssign } from '../utils/lang/objectAssign';
3
+ import { decodeJWTtoken } from '../utils/jwt';
5
4
 
6
5
  /**
7
6
  * Factory of authentication function.
@@ -6,7 +6,7 @@ import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { ITelemetryTracker } from '../trackers/types';
7
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
- import { fetchAuthFactory } from '../sync/streaming/AuthClient';
9
+ import { fetchAuthFactory } from './fetchAuth';
10
10
 
11
11
  const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
12
12