@splitsoftware/splitio-commons 2.0.0 → 2.0.1-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/CHANGES.txt +6 -3
  2. package/README.md +1 -1
  3. package/cjs/listeners/node.js +1 -1
  4. package/cjs/sdkClient/sdkClient.js +3 -6
  5. package/cjs/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  6. package/cjs/storages/inRedis/SegmentsCacheInRedis.js +2 -2
  7. package/cjs/storages/inRedis/SplitsCacheInRedis.js +1 -1
  8. package/cjs/storages/inRedis/index.js +1 -1
  9. package/cjs/storages/pluggable/SegmentsCachePluggable.js +2 -2
  10. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +2 -2
  11. package/cjs/sync/polling/updaters/splitChangesUpdater.js +1 -1
  12. package/cjs/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  13. package/cjs/sync/syncTask.js +2 -2
  14. package/cjs/utils/settingsValidation/index.js +1 -1
  15. package/esm/listeners/node.js +1 -1
  16. package/esm/sdkClient/sdkClient.js +3 -6
  17. package/esm/storages/inMemory/SegmentsCacheInMemory.js +1 -1
  18. package/esm/storages/inRedis/SegmentsCacheInRedis.js +2 -2
  19. package/esm/storages/inRedis/SplitsCacheInRedis.js +1 -1
  20. package/esm/storages/inRedis/index.js +1 -1
  21. package/esm/storages/pluggable/SegmentsCachePluggable.js +2 -2
  22. package/esm/sync/polling/updaters/segmentChangesUpdater.js +2 -2
  23. package/esm/sync/polling/updaters/splitChangesUpdater.js +1 -1
  24. package/esm/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.js +3 -3
  25. package/esm/sync/syncTask.js +2 -2
  26. package/esm/utils/settingsValidation/index.js +1 -1
  27. package/package.json +1 -1
  28. package/src/listeners/node.ts +2 -2
  29. package/src/sdkClient/sdkClient.ts +3 -7
  30. package/src/sdkFactory/types.ts +2 -2
  31. package/src/storages/AbstractMySegmentsCacheSync.ts +1 -1
  32. package/src/storages/inMemory/SegmentsCacheInMemory.ts +1 -1
  33. package/src/storages/inRedis/SegmentsCacheInRedis.ts +2 -2
  34. package/src/storages/inRedis/SplitsCacheInRedis.ts +1 -1
  35. package/src/storages/inRedis/index.ts +1 -1
  36. package/src/storages/pluggable/SegmentsCachePluggable.ts +2 -2
  37. package/src/storages/types.ts +3 -3
  38. package/src/sync/polling/updaters/segmentChangesUpdater.ts +2 -2
  39. package/src/sync/polling/updaters/splitChangesUpdater.ts +1 -1
  40. package/src/sync/streaming/UpdateWorkers/MySegmentsUpdateWorker.ts +5 -4
  41. package/src/sync/streaming/UpdateWorkers/SegmentsUpdateWorker.ts +3 -3
  42. package/src/sync/syncTask.ts +2 -2
  43. package/src/utils/settingsValidation/index.ts +1 -1
  44. package/src/utils/settingsValidation/types.ts +1 -1
  45. package/types/splitio.d.ts +17 -17
package/CHANGES.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 2.0.1 (November 25, 2024)
2
+ - Bugfixing - Fixed an issue with the SDK_UPDATE event on server-side, where it was not being emitted if there was an empty segment and the SDK received a feature flag update notification.
3
+
1
4
  2.0.0 (November 1, 2024)
2
5
  - Added support for targeting rules based on large segments.
3
6
  - Added `factory.destroy()` method, which invokes the `destroy` method on all SDK clients created by the factory.
@@ -20,7 +23,7 @@
20
23
  - Updated some transitive dependencies for vulnerability fixes.
21
24
 
22
25
  1.16.0 (June 13, 2024)
23
- - Added the `getOptions` method to the `IPlatform` interface to allow the SDK to pass request options to the `fetch` function and `EventSource` constructor when fetching data from the Split servers. The method is optional and, if provided, it is called twice: first for the `fetch` options and then for the `EventSource` options. Useful for advanced use cases like configuring a proxy or validating HTTPS certificates in NodeJS.
26
+ - Added the `getOptions` method to the `IPlatform` interface to allow the SDK to pass request options to the `fetch` function and `EventSource` constructor when fetching data from the Split servers. The method is optional and, if provided, it is called twice: first for the `fetch` options and then for the `EventSource` options. Useful for advanced use cases like configuring a proxy or validating HTTPS certificates in Node.js.
24
27
  - Updated the Redis storage to lazily import the `ioredis` dependency when the storage is created. This prevents errors when the SDK is imported or bundled in a .mjs file, as `ioredis` is a CommonJS module.
25
28
  - Bugfixing - Restored some input validation error logs that were removed in version 1.12.0. The logs inform the user when the `getTreatment(s)` methods are called with an invalid value as feature flag name or flag set name.
26
29
  - Bugfixing - Fixed localhost mode to emit SDK_UPDATE when mocked feature flags are updated in the `features` object map of the config object (Related to issue https://github.com/splitio/javascript-browser-client/issues/119).
@@ -57,7 +60,7 @@
57
60
  - Added a new optional Split Filter configuration option. This allows the SDK and Split services to only synchronize the flags in the specified flag sets, avoiding unused or unwanted flags from being synced on the SDK instance, bringing all the benefits from a reduced payload.
58
61
  - Note: Only applicable when the SDK is in charge of the rollout data synchronization. When not applicable, the SDK will log a warning on init.
59
62
  - Added `sets` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager to expose flag sets on flag views.
60
- - Bugfixing - Fixed SDK key validation in NodeJS to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).
63
+ - Bugfixing - Fixed SDK key validation in Node.js to ensure the SDK_READY_TIMED_OUT event is emitted when a client-side type SDK key is provided instead of a server-side one (Related to issue https://github.com/splitio/javascript-client/issues/768).
61
64
 
62
65
  1.10.0 (October 20, 2023)
63
66
  - Added `defaultTreatment` property to the `SplitView` object returned by the `split` and `splits` methods of the SDK manager (Related to issue https://github.com/splitio/javascript-commons/issues/225).
@@ -135,7 +138,7 @@
135
138
  1.3.0 (April 6, 2022)
136
139
  - Added user consent feature to allow delaying or disabling the data tracking from SDK until user consent is explicitly granted or declined. Read more in our docs.
137
140
  - Added `scheduler.impressionsQueueSize` property to SDK configuration to limit the amount of impressions tracked in memory. Read more in our docs.
138
- - Added support to accept TLS configuration options to the Redis storage in NodeJS. Read more in our docs.
141
+ - Added support to accept TLS configuration options to the Redis storage in Node.js. Read more in our docs.
139
142
  - Updated format for MySegments keys in LocalStorage, keeping backwards compatibility (issue https://github.com/splitio/javascript-client/issues/638).
140
143
  - Updated some modules due to general polishing and refactors, including updates in some log messages.
141
144
  - Updated some dependencies for vulnerability fixes.
package/README.md CHANGED
@@ -33,7 +33,7 @@ Split has built and maintains SDKs for:
33
33
  * Java [Github](https://github.com/splitio/java-client) [Docs](https://help.split.io/hc/en-us/articles/360020405151-Java-SDK)
34
34
  * JavaScript [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020448791-JavaScript-SDK)
35
35
  * JavaScript for Browser [Github](https://github.com/splitio/javascript-browser-client) [Docs](https://help.split.io/hc/en-us/articles/360058730852-Browser-SDK)
36
- * Node [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
36
+ * Node.js [Github](https://github.com/splitio/javascript-client) [Docs](https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK)
37
37
  * PHP [Github](https://github.com/splitio/php-client) [Docs](https://help.split.io/hc/en-us/articles/360020350372-PHP-SDK)
38
38
  * PHP thin-client [Github](https://github.com/splitio/php-thin-client) [Docs](https://help.split.io/hc/en-us/articles/18305128673933-PHP-Thin-Client-SDK)
39
39
  * Python [Github](https://github.com/splitio/python-client) [Docs](https://help.split.io/hc/en-us/articles/360020359652-Python-SDK)
@@ -15,7 +15,7 @@ var EVENT_NAME = 'for SIGTERM signal.';
15
15
  var NodeSignalListener = /** @class */ (function () {
16
16
  function NodeSignalListener(syncManager, // private handler: () => MaybeThenable<void>,
17
17
  settings) {
18
- // @TODO review handler logic when implementing Node SDK
18
+ // @TODO review handler logic when implementing Node.js SDK
19
19
  this.handler = function () {
20
20
  if (syncManager) {
21
21
  // syncManager.stop();
@@ -45,19 +45,16 @@ function sdkClientFactory(params, isSharedClient) {
45
45
  destroy: function () {
46
46
  // Mark the SDK as destroyed immediately
47
47
  sdkReadinessManager.readinessManager.destroy();
48
- // For main client, release the SDK Key and record stat before flushing data
48
+ // For main client, cleanup the SDK Key, listeners and scheduled jobs, and record stat before flushing data
49
49
  if (!isSharedClient) {
50
50
  (0, apiKey_1.releaseApiKey)(settings.core.authorizationKey);
51
51
  telemetryTracker.sessionLength();
52
+ signalListener && signalListener.stop();
53
+ uniqueKeysTracker && uniqueKeysTracker.stop();
52
54
  }
53
55
  // Stop background jobs
54
56
  syncManager && syncManager.stop();
55
57
  return __flush().then(function () {
56
- // For main client, cleanup event listeners and scheduled jobs
57
- if (!isSharedClient) {
58
- signalListener && signalListener.stop();
59
- uniqueKeysTracker && uniqueKeysTracker.stop();
60
- }
61
58
  // Cleanup storage
62
59
  return storage.destroy();
63
60
  });
@@ -52,7 +52,7 @@ var SegmentsCacheInMemory = /** @class */ (function () {
52
52
  };
53
53
  SegmentsCacheInMemory.prototype.getChangeNumber = function (name) {
54
54
  var value = this.segmentChangeNumber[name];
55
- return (0, lang_1.isIntegerNumber)(value) ? value : -1;
55
+ return (0, lang_1.isIntegerNumber)(value) ? value : undefined;
56
56
  };
57
57
  // No-op. Not used in server-side
58
58
  SegmentsCacheInMemory.prototype.resetSegments = function () { return false; };
@@ -31,10 +31,10 @@ var SegmentsCacheInRedis = /** @class */ (function () {
31
31
  var _this = this;
32
32
  return this.redis.get(this.keys.buildSegmentTillKey(name)).then(function (value) {
33
33
  var i = parseInt(value, 10);
34
- return (0, lang_1.isNaNNumber)(i) ? -1 : i;
34
+ return (0, lang_1.isNaNNumber)(i) ? undefined : i;
35
35
  }).catch(function (e) {
36
36
  _this.log.error(constants_1.LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
37
- return -1;
37
+ return undefined;
38
38
  });
39
39
  };
40
40
  SegmentsCacheInRedis.prototype.registerSegments = function (segments) {
@@ -18,7 +18,7 @@ function processPipelineAnswer(results) {
18
18
  }
19
19
  /**
20
20
  * ISplitsCacheAsync implementation that stores split definitions in Redis.
21
- * Supported by Node.
21
+ * Supported by Node.js
22
22
  */
23
23
  var SplitsCacheInRedis = /** @class */ (function (_super) {
24
24
  (0, tslib_1.__extends)(SplitsCacheInRedis, _super);
@@ -13,7 +13,7 @@ var UniqueKeysCacheInRedis_1 = require("./UniqueKeysCacheInRedis");
13
13
  var ImpressionCountsCacheInRedis_1 = require("./ImpressionCountsCacheInRedis");
14
14
  var utils_1 = require("../utils");
15
15
  /**
16
- * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
16
+ * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
17
17
  * @see {@link https://www.npmjs.com/package/ioredis}
18
18
  */
19
19
  function InRedisStorage(options) {
@@ -45,10 +45,10 @@ var SegmentsCachePluggable = /** @class */ (function () {
45
45
  var _this = this;
46
46
  return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then(function (value) {
47
47
  var i = parseInt(value, 10);
48
- return (0, lang_1.isNaNNumber)(i) ? -1 : i;
48
+ return (0, lang_1.isNaNNumber)(i) ? undefined : i;
49
49
  }).catch(function (e) {
50
50
  _this.log.error(constants_1.LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
51
- return -1;
51
+ return undefined;
52
52
  });
53
53
  };
54
54
  /**
@@ -21,9 +21,9 @@ function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segments, read
21
21
  var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
22
22
  return sincePromise.then(function (since) {
23
23
  // if fetchOnlyNew flag, avoid processing already fetched segments
24
- return fetchOnlyNew && since !== -1 ?
24
+ return fetchOnlyNew && since !== undefined ?
25
25
  false :
26
- segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
26
+ segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
27
27
  return Promise.all(changes.map(function (x) {
28
28
  log.debug(constants_2.LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
29
29
  return segments.update(segmentName, x.added, x.removed, x.till);
@@ -14,7 +14,7 @@ function checkAllSegmentsExist(segments) {
14
14
  var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
15
15
  return registeredSegments.then(function (segmentNames) {
16
16
  return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
17
- .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== -1; }); });
17
+ .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
18
18
  });
19
19
  }
20
20
  /**
@@ -16,7 +16,7 @@ function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
16
16
  var backoff = new Backoff_1.Backoff(__handleSegmentUpdateCall, constants_1.FETCH_BACKOFF_BASE, constants_1.FETCH_BACKOFF_MAX_WAIT);
17
17
  function __handleSegmentUpdateCall() {
18
18
  isHandlingEvent = true;
19
- if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
19
+ if (maxChangeNumber > (segmentsCache.getChangeNumber(segment) || -1)) {
20
20
  handleNewEvent = false;
21
21
  // fetch segments revalidating data if cached
22
22
  segmentsSyncTask.execute(false, segment, true, cdnBypass ? maxChangeNumber : undefined).then(function () {
@@ -27,7 +27,7 @@ function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
27
27
  }
28
28
  else {
29
29
  var attempts = backoff.attempts + 1;
30
- if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
30
+ if (maxChangeNumber <= (segmentsCache.getChangeNumber(segment) || -1)) {
31
31
  log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
32
32
  isHandlingEvent = false;
33
33
  return;
@@ -54,7 +54,7 @@ function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
54
54
  }
55
55
  return {
56
56
  put: function (changeNumber) {
57
- var currentChangeNumber = segmentsCache.getChangeNumber(segment);
57
+ var currentChangeNumber = segmentsCache.getChangeNumber(segment) || -1;
58
58
  if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
59
59
  return;
60
60
  maxChangeNumber = changeNumber;
@@ -69,8 +69,8 @@ function syncTaskFactory(log, task, period, taskName) {
69
69
  }
70
70
  },
71
71
  stop: function () {
72
- running = false;
73
- if (timeoutID) {
72
+ if (running) {
73
+ running = false;
74
74
  log.debug(constants_1.SYNC_TASK_STOP, [taskName]);
75
75
  clearTimeout(timeoutID);
76
76
  timeoutID = undefined;
@@ -58,7 +58,7 @@ exports.base = {
58
58
  storage: undefined,
59
59
  // Defines if the logs are enabled, SDK wide.
60
60
  debug: undefined,
61
- // Defines the impression listener, but will only be used on NodeJS.
61
+ // Defines the impression listener.
62
62
  impressionListener: undefined,
63
63
  // Instance version.
64
64
  version: undefined,
@@ -12,7 +12,7 @@ var EVENT_NAME = 'for SIGTERM signal.';
12
12
  var NodeSignalListener = /** @class */ (function () {
13
13
  function NodeSignalListener(syncManager, // private handler: () => MaybeThenable<void>,
14
14
  settings) {
15
- // @TODO review handler logic when implementing Node SDK
15
+ // @TODO review handler logic when implementing Node.js SDK
16
16
  this.handler = function () {
17
17
  if (syncManager) {
18
18
  // syncManager.stop();
@@ -42,19 +42,16 @@ export function sdkClientFactory(params, isSharedClient) {
42
42
  destroy: function () {
43
43
  // Mark the SDK as destroyed immediately
44
44
  sdkReadinessManager.readinessManager.destroy();
45
- // For main client, release the SDK Key and record stat before flushing data
45
+ // For main client, cleanup the SDK Key, listeners and scheduled jobs, and record stat before flushing data
46
46
  if (!isSharedClient) {
47
47
  releaseApiKey(settings.core.authorizationKey);
48
48
  telemetryTracker.sessionLength();
49
+ signalListener && signalListener.stop();
50
+ uniqueKeysTracker && uniqueKeysTracker.stop();
49
51
  }
50
52
  // Stop background jobs
51
53
  syncManager && syncManager.stop();
52
54
  return __flush().then(function () {
53
- // For main client, cleanup event listeners and scheduled jobs
54
- if (!isSharedClient) {
55
- signalListener && signalListener.stop();
56
- uniqueKeysTracker && uniqueKeysTracker.stop();
57
- }
58
55
  // Cleanup storage
59
56
  return storage.destroy();
60
57
  });
@@ -49,7 +49,7 @@ var SegmentsCacheInMemory = /** @class */ (function () {
49
49
  };
50
50
  SegmentsCacheInMemory.prototype.getChangeNumber = function (name) {
51
51
  var value = this.segmentChangeNumber[name];
52
- return isIntegerNumber(value) ? value : -1;
52
+ return isIntegerNumber(value) ? value : undefined;
53
53
  };
54
54
  // No-op. Not used in server-side
55
55
  SegmentsCacheInMemory.prototype.resetSegments = function () { return false; };
@@ -28,10 +28,10 @@ var SegmentsCacheInRedis = /** @class */ (function () {
28
28
  var _this = this;
29
29
  return this.redis.get(this.keys.buildSegmentTillKey(name)).then(function (value) {
30
30
  var i = parseInt(value, 10);
31
- return isNaNNumber(i) ? -1 : i;
31
+ return isNaNNumber(i) ? undefined : i;
32
32
  }).catch(function (e) {
33
33
  _this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
34
- return -1;
34
+ return undefined;
35
35
  });
36
36
  };
37
37
  SegmentsCacheInRedis.prototype.registerSegments = function (segments) {
@@ -15,7 +15,7 @@ function processPipelineAnswer(results) {
15
15
  }
16
16
  /**
17
17
  * ISplitsCacheAsync implementation that stores split definitions in Redis.
18
- * Supported by Node.
18
+ * Supported by Node.js
19
19
  */
20
20
  var SplitsCacheInRedis = /** @class */ (function (_super) {
21
21
  __extends(SplitsCacheInRedis, _super);
@@ -10,7 +10,7 @@ import { UniqueKeysCacheInRedis } from './UniqueKeysCacheInRedis';
10
10
  import { ImpressionCountsCacheInRedis } from './ImpressionCountsCacheInRedis';
11
11
  import { metadataBuilder } from '../utils';
12
12
  /**
13
- * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
13
+ * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
14
14
  * @see {@link https://www.npmjs.com/package/ioredis}
15
15
  */
16
16
  export function InRedisStorage(options) {
@@ -42,10 +42,10 @@ var SegmentsCachePluggable = /** @class */ (function () {
42
42
  var _this = this;
43
43
  return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then(function (value) {
44
44
  var i = parseInt(value, 10);
45
- return isNaNNumber(i) ? -1 : i;
45
+ return isNaNNumber(i) ? undefined : i;
46
46
  }).catch(function (e) {
47
47
  _this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
48
- return -1;
48
+ return undefined;
49
49
  });
50
50
  };
51
51
  /**
@@ -18,9 +18,9 @@ export function segmentChangesUpdaterFactory(log, segmentChangesFetcher, segment
18
18
  var sincePromise = Promise.resolve(segments.getChangeNumber(segmentName));
19
19
  return sincePromise.then(function (since) {
20
20
  // if fetchOnlyNew flag, avoid processing already fetched segments
21
- return fetchOnlyNew && since !== -1 ?
21
+ return fetchOnlyNew && since !== undefined ?
22
22
  false :
23
- segmentChangesFetcher(since, segmentName, noCache, till).then(function (changes) {
23
+ segmentChangesFetcher(since || -1, segmentName, noCache, till).then(function (changes) {
24
24
  return Promise.all(changes.map(function (x) {
25
25
  log.debug(LOG_PREFIX_SYNC_SEGMENTS + "Processing " + segmentName + " with till = " + x.till + ". Added: " + x.added.length + ". Removed: " + x.removed.length);
26
26
  return segments.update(segmentName, x.added, x.removed, x.till);
@@ -11,7 +11,7 @@ function checkAllSegmentsExist(segments) {
11
11
  var registeredSegments = Promise.resolve(segments.getRegisteredSegments());
12
12
  return registeredSegments.then(function (segmentNames) {
13
13
  return Promise.all(segmentNames.map(function (segmentName) { return segments.getChangeNumber(segmentName); }))
14
- .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== -1; }); });
14
+ .then(function (changeNumbers) { return changeNumbers.every(function (changeNumber) { return changeNumber !== undefined; }); });
15
15
  });
16
16
  }
17
17
  /**
@@ -13,7 +13,7 @@ export function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
13
13
  var backoff = new Backoff(__handleSegmentUpdateCall, FETCH_BACKOFF_BASE, FETCH_BACKOFF_MAX_WAIT);
14
14
  function __handleSegmentUpdateCall() {
15
15
  isHandlingEvent = true;
16
- if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
16
+ if (maxChangeNumber > (segmentsCache.getChangeNumber(segment) || -1)) {
17
17
  handleNewEvent = false;
18
18
  // fetch segments revalidating data if cached
19
19
  segmentsSyncTask.execute(false, segment, true, cdnBypass ? maxChangeNumber : undefined).then(function () {
@@ -24,7 +24,7 @@ export function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
24
24
  }
25
25
  else {
26
26
  var attempts = backoff.attempts + 1;
27
- if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
27
+ if (maxChangeNumber <= (segmentsCache.getChangeNumber(segment) || -1)) {
28
28
  log.debug("Refresh completed" + (cdnBypass ? ' bypassing the CDN' : '') + " in " + attempts + " attempts.");
29
29
  isHandlingEvent = false;
30
30
  return;
@@ -51,7 +51,7 @@ export function SegmentsUpdateWorker(log, segmentsSyncTask, segmentsCache) {
51
51
  }
52
52
  return {
53
53
  put: function (changeNumber) {
54
- var currentChangeNumber = segmentsCache.getChangeNumber(segment);
54
+ var currentChangeNumber = segmentsCache.getChangeNumber(segment) || -1;
55
55
  if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber)
56
56
  return;
57
57
  maxChangeNumber = changeNumber;
@@ -66,8 +66,8 @@ export function syncTaskFactory(log, task, period, taskName) {
66
66
  }
67
67
  },
68
68
  stop: function () {
69
- running = false;
70
- if (timeoutID) {
69
+ if (running) {
70
+ running = false;
71
71
  log.debug(SYNC_TASK_STOP, [taskName]);
72
72
  clearTimeout(timeoutID);
73
73
  timeoutID = undefined;
@@ -55,7 +55,7 @@ export var base = {
55
55
  storage: undefined,
56
56
  // Defines if the logs are enabled, SDK wide.
57
57
  debug: undefined,
58
- // Defines the impression listener, but will only be used on NodeJS.
58
+ // Defines the impression listener.
59
59
  impressionListener: undefined,
60
60
  // Instance version.
61
61
  version: undefined,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.0.0",
3
+ "version": "2.0.1-rc.1",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -1,4 +1,4 @@
1
- // @TODO eventually migrate to JS-Node-SDK package.
1
+ // @TODO eventually migrate to Node.js SDK package.
2
2
  import { ISignalListener } from './types';
3
3
  import { thenable } from '../utils/promise/thenable';
4
4
  import { MaybeThenable } from '../dtos/types';
@@ -25,7 +25,7 @@ export class NodeSignalListener implements ISignalListener {
25
25
  syncManager: ISyncManager | undefined, // private handler: () => MaybeThenable<void>,
26
26
  settings: ISettings
27
27
  ) {
28
- // @TODO review handler logic when implementing Node SDK
28
+ // @TODO review handler logic when implementing Node.js SDK
29
29
  this.handler = function () {
30
30
  if (syncManager) {
31
31
  // syncManager.stop();
@@ -56,22 +56,18 @@ export function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: bo
56
56
  // Mark the SDK as destroyed immediately
57
57
  sdkReadinessManager.readinessManager.destroy();
58
58
 
59
- // For main client, release the SDK Key and record stat before flushing data
59
+ // For main client, cleanup the SDK Key, listeners and scheduled jobs, and record stat before flushing data
60
60
  if (!isSharedClient) {
61
61
  releaseApiKey(settings.core.authorizationKey);
62
62
  telemetryTracker.sessionLength();
63
+ signalListener && signalListener.stop();
64
+ uniqueKeysTracker && uniqueKeysTracker.stop();
63
65
  }
64
66
 
65
67
  // Stop background jobs
66
68
  syncManager && syncManager.stop();
67
69
 
68
70
  return __flush().then(() => {
69
- // For main client, cleanup event listeners and scheduled jobs
70
- if (!isSharedClient) {
71
- signalListener && signalListener.stop();
72
- uniqueKeysTracker && uniqueKeysTracker.stop();
73
- }
74
-
75
71
  // Cleanup storage
76
72
  return storage.destroy();
77
73
  });
@@ -28,7 +28,7 @@ export interface IPlatform {
28
28
  */
29
29
  getEventSource?: (settings: ISettings) => (IEventSourceConstructor | undefined)
30
30
  /**
31
- * EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
31
+ * EventEmitter constructor, like Node.js EventEmitter or a polyfill.
32
32
  */
33
33
  EventEmitter: new () => SplitIO.IEventEmitter,
34
34
  /**
@@ -104,7 +104,7 @@ export interface ISdkFactoryParams {
104
104
  filterAdapterFactory?: () => IFilterAdapter
105
105
 
106
106
  // Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed.
107
- // Pass only if `syncManager` (used by Node listener) and `splitApi` (used by Browser listener) are passed.
107
+ // Pass only if `syncManager` (used by NodeSignalListener) and `splitApi` (used by Browser listener) are passed.
108
108
  SignalListener?: new (
109
109
  syncManager: ISyncManager | undefined, // Used by NodeSignalListener to flush data, and by BrowserSignalListener to close streaming connection.
110
110
  settings: ISettings, // Used by BrowserSignalListener
@@ -42,7 +42,7 @@ export abstract class AbstractMySegmentsCacheSync implements ISegmentsCacheSync
42
42
  // @TODO for client-side it should be the number of clients, but it requires a refactor of MySegments caches to simplify the code.
43
43
  abstract getKeysCount(): number
44
44
 
45
- abstract getChangeNumber(name: string): number
45
+ abstract getChangeNumber(): number
46
46
 
47
47
  /**
48
48
  * For server-side synchronizer: the method is not used.
@@ -65,7 +65,7 @@ export class SegmentsCacheInMemory implements ISegmentsCacheSync {
65
65
  getChangeNumber(name: string) {
66
66
  const value = this.segmentChangeNumber[name];
67
67
 
68
- return isIntegerNumber(value) ? value : -1;
68
+ return isIntegerNumber(value) ? value : undefined;
69
69
  }
70
70
 
71
71
  // No-op. Not used in server-side
@@ -44,10 +44,10 @@ export class SegmentsCacheInRedis implements ISegmentsCacheAsync {
44
44
  return this.redis.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
45
45
  const i = parseInt(value as string, 10);
46
46
 
47
- return isNaNNumber(i) ? -1 : i;
47
+ return isNaNNumber(i) ? undefined : i;
48
48
  }).catch((e) => {
49
49
  this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
50
- return -1;
50
+ return undefined;
51
51
  });
52
52
  }
53
53
 
@@ -19,7 +19,7 @@ function processPipelineAnswer(results: Array<[Error | null, string]>): string[]
19
19
 
20
20
  /**
21
21
  * ISplitsCacheAsync implementation that stores split definitions in Redis.
22
- * Supported by Node.
22
+ * Supported by Node.js
23
23
  */
24
24
  export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
25
25
 
@@ -18,7 +18,7 @@ export interface InRedisStorageOptions {
18
18
  }
19
19
 
20
20
  /**
21
- * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.
21
+ * InRedis storage factory for consumer server-side SplitFactory, that uses `Ioredis` Redis client for Node.js
22
22
  * @see {@link https://www.npmjs.com/package/ioredis}
23
23
  */
24
24
  export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
@@ -55,10 +55,10 @@ export class SegmentsCachePluggable implements ISegmentsCacheAsync {
55
55
  return this.wrapper.get(this.keys.buildSegmentTillKey(name)).then((value: string | null) => {
56
56
  const i = parseInt(value as string, 10);
57
57
 
58
- return isNaNNumber(i) ? -1 : i;
58
+ return isNaNNumber(i) ? undefined : i;
59
59
  }).catch((e) => {
60
60
  this.log.error(LOG_PREFIX + 'Could not retrieve changeNumber from segments storage. Error: ' + e);
61
- return -1;
61
+ return undefined;
62
62
  });
63
63
  }
64
64
 
@@ -237,7 +237,7 @@ export interface ISegmentsCacheBase {
237
237
  isInSegment(name: string, key?: string): MaybeThenable<boolean> // different signature on Server and Client-Side
238
238
  registerSegments(names: string[]): MaybeThenable<boolean | void> // only for Server-Side
239
239
  getRegisteredSegments(): MaybeThenable<string[]> // only for Server-Side
240
- getChangeNumber(name: string): MaybeThenable<number> // only for Server-Side
240
+ getChangeNumber(name: string): MaybeThenable<number | undefined> // only for Server-Side
241
241
  update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): MaybeThenable<boolean> // only for Server-Side
242
242
  clear(): MaybeThenable<boolean | void>
243
243
  }
@@ -248,7 +248,7 @@ export interface ISegmentsCacheSync extends ISegmentsCacheBase {
248
248
  registerSegments(names: string[]): boolean
249
249
  getRegisteredSegments(): string[]
250
250
  getKeysCount(): number // only used for telemetry
251
- getChangeNumber(name?: string): number
251
+ getChangeNumber(name?: string): number | undefined
252
252
  update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): boolean // only for Server-Side
253
253
  resetSegments(segmentsData: MySegmentsData | IMySegmentsResponse): boolean // only for Sync Client-Side
254
254
  clear(): void
@@ -258,7 +258,7 @@ export interface ISegmentsCacheAsync extends ISegmentsCacheBase {
258
258
  isInSegment(name: string, key: string): Promise<boolean>
259
259
  registerSegments(names: string[]): Promise<boolean | void>
260
260
  getRegisteredSegments(): Promise<string[]>
261
- getChangeNumber(name: string): Promise<number>
261
+ getChangeNumber(name: string): Promise<number | undefined>
262
262
  update(name: string, addedKeys: string[], removedKeys: string[], changeNumber: number): Promise<boolean>
263
263
  clear(): Promise<boolean | void>
264
264
  }
@@ -33,9 +33,9 @@ export function segmentChangesUpdaterFactory(
33
33
 
34
34
  return sincePromise.then(since => {
35
35
  // if fetchOnlyNew flag, avoid processing already fetched segments
36
- return fetchOnlyNew && since !== -1 ?
36
+ return fetchOnlyNew && since !== undefined ?
37
37
  false :
38
- segmentChangesFetcher(since, segmentName, noCache, till).then((changes) => {
38
+ segmentChangesFetcher(since || -1, segmentName, noCache, till).then((changes) => {
39
39
  return Promise.all(changes.map(x => {
40
40
  log.debug(`${LOG_PREFIX_SYNC_SEGMENTS}Processing ${segmentName} with till = ${x.till}. Added: ${x.added.length}. Removed: ${x.removed.length}`);
41
41
  return segments.update(segmentName, x.added, x.removed, x.till);
@@ -19,7 +19,7 @@ function checkAllSegmentsExist(segments: ISegmentsCacheBase): Promise<boolean> {
19
19
  let registeredSegments = Promise.resolve(segments.getRegisteredSegments());
20
20
  return registeredSegments.then(segmentNames => {
21
21
  return Promise.all(segmentNames.map(segmentName => segments.getChangeNumber(segmentName)))
22
- .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== -1));
22
+ .then(changeNumbers => changeNumbers.every(changeNumber => changeNumber !== undefined));
23
23
  });
24
24
  }
25
25
 
@@ -3,10 +3,11 @@ import { Backoff } from '../../../utils/Backoff';
3
3
  import { IUpdateWorker } from './types';
4
4
  import { ITelemetryTracker } from '../../../trackers/types';
5
5
  import { MEMBERSHIPS } from '../../../utils/constants';
6
- import { ISegmentsCacheSync, IStorageSync } from '../../../storages/types';
6
+ import { IStorageSync } from '../../../storages/types';
7
7
  import { ILogger } from '../../../logger/types';
8
8
  import { FETCH_BACKOFF_MAX_RETRIES } from './constants';
9
9
  import { MEMBERSHIPS_LS_UPDATE, MEMBERSHIPS_MS_UPDATE } from '../constants';
10
+ import { AbstractMySegmentsCacheSync } from '../../../storages/AbstractMySegmentsCacheSync';
10
11
 
11
12
  /**
12
13
  * MySegmentsUpdateWorker factory
@@ -16,7 +17,7 @@ export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync,
16
17
  let _delay: undefined | number;
17
18
  let _delayTimeoutID: any;
18
19
 
19
- function createUpdateWorker(mySegmentsCache: ISegmentsCacheSync) {
20
+ function createUpdateWorker(mySegmentsCache: AbstractMySegmentsCacheSync) {
20
21
 
21
22
  let maxChangeNumber = 0; // keeps the maximum changeNumber among queued events
22
23
  let currentChangeNumber = -1;
@@ -117,8 +118,8 @@ export function MySegmentsUpdateWorker(log: ILogger, storage: Pick<IStorageSync,
117
118
  }
118
119
 
119
120
  const updateWorkers = {
120
- [MEMBERSHIPS_MS_UPDATE]: createUpdateWorker(storage.segments),
121
- [MEMBERSHIPS_LS_UPDATE]: createUpdateWorker(storage.largeSegments!),
121
+ [MEMBERSHIPS_MS_UPDATE]: createUpdateWorker(storage.segments as AbstractMySegmentsCacheSync),
122
+ [MEMBERSHIPS_LS_UPDATE]: createUpdateWorker(storage.largeSegments as AbstractMySegmentsCacheSync),
122
123
  };
123
124
 
124
125
  return {
@@ -21,7 +21,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
21
21
 
22
22
  function __handleSegmentUpdateCall() {
23
23
  isHandlingEvent = true;
24
- if (maxChangeNumber > segmentsCache.getChangeNumber(segment)) {
24
+ if (maxChangeNumber > (segmentsCache.getChangeNumber(segment) || -1)) {
25
25
  handleNewEvent = false;
26
26
 
27
27
  // fetch segments revalidating data if cached
@@ -32,7 +32,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
32
32
  } else {
33
33
  const attempts = backoff.attempts + 1;
34
34
 
35
- if (maxChangeNumber <= segmentsCache.getChangeNumber(segment)) {
35
+ if (maxChangeNumber <= (segmentsCache.getChangeNumber(segment) || -1)) {
36
36
  log.debug(`Refresh completed${cdnBypass ? ' bypassing the CDN' : ''} in ${attempts} attempts.`);
37
37
  isHandlingEvent = false;
38
38
  return;
@@ -60,7 +60,7 @@ export function SegmentsUpdateWorker(log: ILogger, segmentsSyncTask: ISegmentsSy
60
60
 
61
61
  return {
62
62
  put(changeNumber: number) {
63
- const currentChangeNumber = segmentsCache.getChangeNumber(segment);
63
+ const currentChangeNumber = segmentsCache.getChangeNumber(segment) || -1;
64
64
 
65
65
  if (changeNumber <= currentChangeNumber || changeNumber <= maxChangeNumber) return;
66
66
 
@@ -68,8 +68,8 @@ export function syncTaskFactory<Input extends any[], Output = any>(log: ILogger,
68
68
  },
69
69
 
70
70
  stop() {
71
- running = false;
72
- if (timeoutID) {
71
+ if (running) {
72
+ running = false;
73
73
  log.debug(SYNC_TASK_STOP, [taskName]);
74
74
  clearTimeout(timeoutID);
75
75
  timeoutID = undefined;
@@ -64,7 +64,7 @@ export const base = {
64
64
  // Defines if the logs are enabled, SDK wide.
65
65
  debug: undefined,
66
66
 
67
- // Defines the impression listener, but will only be used on NodeJS.
67
+ // Defines the impression listener.
68
68
  impressionListener: undefined,
69
69
 
70
70
  // Instance version.
@@ -2,7 +2,7 @@ import { ISettings } from '../../types';
2
2
 
3
3
  /**
4
4
  * Parameters used to specialize the settings validation for each API variant
5
- * (client-side, server-side) and environment (Node server, Browser, etc)
5
+ * (client-side, server-side) and environment (Node.js, Browser, etc)
6
6
  */
7
7
  export interface ISettingsValidationParams {
8
8
  /**
@@ -164,7 +164,7 @@ interface INonPluggableSharedSettings {
164
164
  */
165
165
  interface IServerSideSharedSettings {
166
166
  /**
167
- * SDK Core settings for NodeJS.
167
+ * SDK Core settings for Node.js.
168
168
  */
169
169
  core: {
170
170
  /**
@@ -187,7 +187,7 @@ interface IServerSideSharedSettings {
187
187
  IPAddressesEnabled?: boolean;
188
188
  };
189
189
  /**
190
- * SDK Startup settings for NodeJS.
190
+ * SDK Startup settings for Node.js.
191
191
  */
192
192
  startup?: {
193
193
  /**
@@ -450,7 +450,7 @@ interface IClientSideSyncSharedSettings extends IClientSideSharedSettings, ISync
450
450
  declare namespace SplitIO {
451
451
 
452
452
  /**
453
- * EventEmitter interface based on a subset of the NodeJS.EventEmitter methods.
453
+ * EventEmitter interface based on a subset of the Node.js EventEmitter methods.
454
454
  */
455
455
  interface IEventEmitter {
456
456
  addListener(event: string, listener: (...args: any[]) => void): this;
@@ -462,7 +462,7 @@ declare namespace SplitIO {
462
462
  emit(event: string, ...args: any[]): boolean;
463
463
  }
464
464
  /**
465
- * NodeJS.EventEmitter interface
465
+ * Node.js EventEmitter interface
466
466
  * @see {@link https://nodejs.org/api/events.html}
467
467
  */
468
468
  interface EventEmitter extends IEventEmitter {
@@ -478,7 +478,7 @@ declare namespace SplitIO {
478
478
  listeners(event: string | symbol): Function[];
479
479
  rawListeners(event: string | symbol): Function[];
480
480
  listenerCount(type: string | symbol): number;
481
- // Added in Node 6...
481
+ // Added in Node.js 6...
482
482
  prependListener(event: string | symbol, listener: (...args: any[]) => void): this;
483
483
  prependOnceListener(event: string | symbol, listener: (...args: any[]) => void): this;
484
484
  eventNames(): Array<string | symbol>;
@@ -557,7 +557,7 @@ declare namespace SplitIO {
557
557
  readonly debug: boolean | LogLevel | ILogger;
558
558
  readonly version: string;
559
559
  /**
560
- * Mocked features map if using in client-side, or mocked features file path string if using in server-side (NodeJS).
560
+ * Mocked features map if using in client-side, or mocked features file path string if using in server-side (Node.js).
561
561
  */
562
562
  features: MockedFeaturesMap | MockedFeaturesFilePath;
563
563
  readonly streamingEnabled: boolean;
@@ -576,7 +576,7 @@ declare namespace SplitIO {
576
576
  };
577
577
  readonly impressionListener?: IImpressionListener;
578
578
  /**
579
- * User consent status if using in client-side. Undefined if using in server-side (NodeJS).
579
+ * User consent status if using in client-side. Undefined if using in server-side (Node.js).
580
580
  */
581
581
  readonly userConsent?: ConsentStatus;
582
582
  }
@@ -936,11 +936,11 @@ declare namespace SplitIO {
936
936
  wrapper: Object;
937
937
  }
938
938
  /**
939
- * Synchronous storage valid types for NodeJS.
939
+ * Synchronous storage valid types for Node.js.
940
940
  */
941
941
  type NodeSyncStorage = 'MEMORY';
942
942
  /**
943
- * Asynchronous storages valid types for NodeJS.
943
+ * Asynchronous storages valid types for Node.js.
944
944
  */
945
945
  type NodeAsyncStorage = 'REDIS';
946
946
  /**
@@ -1237,14 +1237,14 @@ declare namespace SplitIO {
1237
1237
  };
1238
1238
  }
1239
1239
  /**
1240
- * Settings interface for JavaScript SDK instances created on NodeJS, with server-side API and synchronous in-memory storage.
1240
+ * Settings interface for JavaScript SDK instances created on Node.js, with server-side API and synchronous in-memory storage.
1241
1241
  * If your storage is asynchronous (Redis for example) use SplitIO.INodeAsyncSettings instead.
1242
1242
  *
1243
1243
  * @see {@link https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK#configuration}
1244
1244
  */
1245
1245
  interface INodeSettings extends IServerSideSharedSettings, ISyncSharedSettings, INonPluggableSharedSettings {
1246
1246
  /**
1247
- * Defines which kind of storage we can instantiate on NodeJS for 'standalone' mode.
1247
+ * Defines which kind of storage we can instantiate on Node.js for 'standalone' mode.
1248
1248
  * The only possible storage type is 'MEMORY', which is the default.
1249
1249
  */
1250
1250
  storage?: {
@@ -1263,7 +1263,7 @@ declare namespace SplitIO {
1263
1263
  };
1264
1264
  sync?: ISyncSharedSettings['sync'] & {
1265
1265
  /**
1266
- * Custom options object for HTTP(S) requests in NodeJS.
1266
+ * Custom options object for HTTP(S) requests in Node.js.
1267
1267
  * If provided, this object is merged with the options object passed by the SDK for EventSource and Node-Fetch calls.
1268
1268
  * @see {@link https://www.npmjs.com/package/node-fetch#options}
1269
1269
  */
@@ -1291,7 +1291,7 @@ declare namespace SplitIO {
1291
1291
  */
1292
1292
  getHeaderOverrides?: (context: { headers: Record<string, string> }) => Record<string, string>;
1293
1293
  /**
1294
- * Custom NodeJS HTTP(S) Agent used by the SDK for HTTP(S) requests.
1294
+ * Custom Node.js HTTP(S) Agent used by the SDK for HTTP(S) requests.
1295
1295
  *
1296
1296
  * You can use it, for example, for certificate pinning or setting a network proxy:
1297
1297
  *
@@ -1319,7 +1319,7 @@ declare namespace SplitIO {
1319
1319
  };
1320
1320
  }
1321
1321
  /**
1322
- * Settings interface for JavaScript SDK instances created on NodeJS, with asynchronous storage like Redis.
1322
+ * Settings interface for JavaScript SDK instances created on Node.js, with asynchronous storage like Redis.
1323
1323
  * If your storage is synchronous (by default we use memory, which is sync) use SplitIO.INodeSettings instead.
1324
1324
  *
1325
1325
  * @see {@link https://help.split.io/hc/en-us/articles/360020564931-Node-js-SDK#configuration}
@@ -1332,7 +1332,7 @@ declare namespace SplitIO {
1332
1332
  */
1333
1333
  mode: 'consumer';
1334
1334
  /**
1335
- * Defines which kind of async storage we can instantiate on NodeJS for 'consumer' mode.
1335
+ * Defines which kind of async storage we can instantiate on Node.js for 'consumer' mode.
1336
1336
  * The only possible storage type is 'REDIS'.
1337
1337
  */
1338
1338
  storage: {
@@ -1501,7 +1501,7 @@ declare namespace SplitIO {
1501
1501
  }
1502
1502
  /**
1503
1503
  * This represents the interface for the Client instance on server-side, where the user key is not bound to the instance and must be provided on each method call.
1504
- * This interface is available in NodeJS, or when importing the 'server' sub-package of JS SDK (e.g., `import { SplitFactory } from '@splitsoftware/splitio/server'`).
1504
+ * This interface is available in Node.js, or when importing the 'server' sub-package of JS SDK (e.g., `import { SplitFactory } from '@splitsoftware/splitio/server'`).
1505
1505
  */
1506
1506
  interface IClient extends IBasicClient {
1507
1507
  /**
@@ -1592,7 +1592,7 @@ declare namespace SplitIO {
1592
1592
  /**
1593
1593
  * This represents the interface for the Client instance on server-side with asynchronous storage, like REDIS.
1594
1594
  * User key is not bound to the instance and must be provided on each method call, which returns a promise.
1595
- * This interface is available in NodeJS, or when importing the 'server' sub-package in JS SDK (e.g., `import { SplitFactory } from '@splitsoftware/splitio/server'`).
1595
+ * This interface is available in Node.js, or when importing the 'server' sub-package in JS SDK (e.g., `import { SplitFactory } from '@splitsoftware/splitio/server'`).
1596
1596
  */
1597
1597
  interface IAsyncClient extends IBasicClient {
1598
1598
  /**