@splitsoftware/splitio-commons 3.1.1-rc.1 → 3.1.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 (72) hide show
  1. package/CHANGES.txt +12 -1
  2. package/cjs/evaluator/index.js +11 -6
  3. package/cjs/presets/serverSide.js +3 -3
  4. package/cjs/sdkClient/client.js +3 -5
  5. package/cjs/sdkClient/sdkLifecycle.js +2 -0
  6. package/cjs/services/authProvider.js +23 -10
  7. package/cjs/services/secureSplitHttpClient.js +10 -13
  8. package/cjs/services/serviceApi.js +23 -21
  9. package/cjs/services/splitApi.js +10 -9
  10. package/cjs/storages/inRedis/RedisAdapter.js +8 -5
  11. package/cjs/sync/polling/pollingManagerCS.js +84 -79
  12. package/cjs/sync/polling/pollingManagerSS.js +43 -35
  13. package/cjs/sync/polling/updaters/definitionChangesUpdater.js +2 -2
  14. package/cjs/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  15. package/cjs/sync/streaming/AuthClient/index.js +13 -14
  16. package/cjs/sync/streaming/SSEHandler/index.js +1 -0
  17. package/cjs/sync/streaming/constants.js +2 -1
  18. package/cjs/sync/streaming/pushManager.js +5 -10
  19. package/cjs/sync/submitters/impressionsSubmitter.js +1 -1
  20. package/cjs/sync/syncManagerOnline.js +2 -7
  21. package/cjs/utils/Backoff.js +16 -4
  22. package/esm/evaluator/index.js +11 -6
  23. package/esm/presets/serverSide.js +3 -3
  24. package/esm/sdkClient/client.js +3 -5
  25. package/esm/sdkClient/sdkLifecycle.js +2 -0
  26. package/esm/services/authProvider.js +24 -11
  27. package/esm/services/secureSplitHttpClient.js +10 -13
  28. package/esm/services/serviceApi.js +24 -22
  29. package/esm/services/splitApi.js +10 -9
  30. package/esm/storages/inRedis/RedisAdapter.js +8 -5
  31. package/esm/sync/polling/pollingManagerCS.js +84 -79
  32. package/esm/sync/polling/pollingManagerSS.js +43 -35
  33. package/esm/sync/polling/updaters/definitionChangesUpdater.js +3 -3
  34. package/esm/sync/polling/updaters/segmentChangesUpdater.js +1 -1
  35. package/esm/sync/streaming/AuthClient/index.js +11 -11
  36. package/esm/sync/streaming/SSEHandler/index.js +2 -1
  37. package/esm/sync/streaming/constants.js +1 -0
  38. package/esm/sync/streaming/pushManager.js +6 -11
  39. package/esm/sync/submitters/impressionsSubmitter.js +1 -1
  40. package/esm/sync/syncManagerOnline.js +2 -7
  41. package/esm/utils/Backoff.js +16 -4
  42. package/package.json +6 -7
  43. package/src/dtos/types.ts +1 -1
  44. package/src/evaluator/index.ts +11 -5
  45. package/src/evaluator/types.ts +1 -0
  46. package/src/presets/serverSide.ts +3 -3
  47. package/src/sdkClient/client.ts +3 -4
  48. package/src/sdkClient/sdkLifecycle.ts +3 -0
  49. package/src/services/authProvider.ts +41 -19
  50. package/src/services/secureSplitHttpClient.ts +10 -18
  51. package/src/services/serviceApi.ts +27 -24
  52. package/src/services/splitApi.ts +10 -9
  53. package/src/services/types.ts +5 -4
  54. package/src/storages/inRedis/RedisAdapter.ts +8 -5
  55. package/src/sync/polling/pollingManagerCS.ts +80 -78
  56. package/src/sync/polling/pollingManagerSS.ts +49 -45
  57. package/src/sync/polling/updaters/definitionChangesUpdater.ts +3 -3
  58. package/src/sync/polling/updaters/segmentChangesUpdater.ts +1 -1
  59. package/src/sync/streaming/AuthClient/index.ts +14 -15
  60. package/src/sync/streaming/AuthClient/types.ts +9 -13
  61. package/src/sync/streaming/SSEClient/index.ts +2 -2
  62. package/src/sync/streaming/SSEClient/types.ts +2 -2
  63. package/src/sync/streaming/SSEHandler/index.ts +2 -1
  64. package/src/sync/streaming/SSEHandler/types.ts +2 -2
  65. package/src/sync/streaming/constants.ts +1 -0
  66. package/src/sync/streaming/pushManager.ts +32 -42
  67. package/src/sync/streaming/types.ts +3 -2
  68. package/src/sync/submitters/impressionsSubmitter.ts +3 -3
  69. package/src/sync/submitters/types.ts +2 -2
  70. package/src/sync/syncManagerOnline.ts +2 -8
  71. package/src/utils/Backoff.ts +16 -4
  72. package/types/splitio.d.ts +5 -4
package/CHANGES.txt CHANGED
@@ -1,6 +1,10 @@
1
- 3.2.0 (August 10, 2026)
1
+ 3.2.0 (XXX XX, 2026)
2
2
  - Added support for AI configs.
3
+ - 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
+ - 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.
3
5
  - Removed Configs SDK-related types and modules and moved them to the Configs SDK repository.
6
+ - Bugfix - Fixed a memory leak in the `Backoff` utility, where promises returned by pending scheduled calls were never settled when the backoff was reset.
7
+ - Bugfix - Fixed the authentication service to not send unauthenticated requests when the SDK is destroyed while an authentication retry is pending.
4
8
 
5
9
  3.1.0 (July 23, 2026)
6
10
  - Added support for rule-based segments in /api/v1/configs endpoint.
@@ -20,6 +24,13 @@
20
24
  - Removed the misleading warning log 'No listeners for SDK_READY event detected', since users can use the `whenReady` method to wait for the SDK to be ready.
21
25
  - BREAKING CHANGES: Renamed some types and modules, and updated the signatures of others for clarity and reusability.
22
26
 
27
+ 2.13.0 (September 24, 2026)
28
+ - 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.
29
+ - 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.
30
+
31
+ 2.12.2 (September 23, 2026)
32
+ - Updated some transitive dependencies for vulnerability fixes.
33
+
23
34
  2.12.1 (June 25, 2026)
24
35
  - Updated internal modules to handle `null` values from `/splitChanges` response.
25
36
  - Updated some dependencies for vulnerability fixes.
@@ -25,6 +25,12 @@ function treatmentsException(definitionNames) {
25
25
  });
26
26
  return evaluations;
27
27
  }
28
+ function setEvaluationDataFromDefinition(evaluation, definition) {
29
+ return (0, objectAssign_1.objectAssign)(evaluation, {
30
+ definition: definition,
31
+ config: definition.configurations && definition.configurations[evaluation.treatment] || null
32
+ });
33
+ }
28
34
  function evaluateFeature(log, key, definitionName, attributes, storage) {
29
35
  var definition;
30
36
  try {
@@ -98,8 +104,8 @@ function getEvaluation(log, key, definition, attributes, storage) {
98
104
  var split = (0, Engine_1.engineParser)(log, definition, storage);
99
105
  var evaluation = split.getTreatment(key, attributes, evaluateFeature);
100
106
  return (0, thenable_1.thenable)(evaluation) ?
101
- evaluation.then(function (result) { return (0, objectAssign_1.objectAssign)(result, { definition: definition }); }) :
102
- (0, objectAssign_1.objectAssign)(evaluation, { definition: definition });
107
+ evaluation.then(function (result) { return setEvaluationDataFromDefinition(result, definition); }) :
108
+ setEvaluationDataFromDefinition(evaluation, definition);
103
109
  }
104
110
  return EVALUATION_DEFINITION_NOT_FOUND;
105
111
  }
@@ -131,11 +137,10 @@ function evaluateDefaultTreatment(definitionName, storage) {
131
137
  exports.evaluateDefaultTreatment = evaluateDefaultTreatment;
132
138
  function getDefaultTreatment(definition) {
133
139
  if (definition) {
134
- return {
140
+ return setEvaluationDataFromDefinition({
135
141
  treatment: definition.defaultTreatment,
136
- label: labels_1.NO_CONDITION_MATCH,
137
- definition: definition,
138
- };
142
+ label: labels_1.NO_CONDITION_MATCH, // "default rule"
143
+ }, definition);
139
144
  }
140
145
  return EVALUATION_DEFINITION_NOT_FOUND;
141
146
  }
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.serverSideModules = void 0;
4
- var serviceApi_1 = require("../services/serviceApi");
4
+ var splitApi_1 = require("../services/splitApi");
5
5
  var syncManagerOnline_1 = require("../sync/syncManagerOnline");
6
6
  var pushManager_1 = require("../sync/streaming/pushManager");
7
7
  var pollingManagerSS_1 = require("../sync/polling/pollingManagerSS");
@@ -9,10 +9,10 @@ var InMemoryStorage_1 = require("../storages/inMemory/InMemoryStorage");
9
9
  var sdkManager_1 = require("../sdkManager");
10
10
  var sdkClientMethod_1 = require("../sdkClient/sdkClientMethod");
11
11
  var impressionObserverSS_1 = require("../trackers/impressionObserver/impressionObserverSS");
12
- var syncManagerOnlineSSFactory = (0, syncManagerOnline_1.syncManagerOnlineFactory)(pollingManagerSS_1.pollingManagerSSFactory, pushManager_1.pushManagerFactory);
12
+ var syncManagerOnlineSSFactory = (0, syncManagerOnline_1.syncManagerOnlineFactory)((0, pollingManagerSS_1.pollingManagerSSFactory)(), pushManager_1.pushManagerFactory);
13
13
  exports.serverSideModules = {
14
14
  storageFactory: InMemoryStorage_1.InMemoryStorageFactory,
15
- serviceApiFactory: serviceApi_1.serviceApiFactory,
15
+ serviceApiFactory: splitApi_1.splitApiFactory,
16
16
  syncManagerFactory: syncManagerOnlineSSFactory,
17
17
  sdkManagerFactory: sdkManager_1.sdkManagerFactory,
18
18
  sdkClientMethodFactory: sdkClientMethod_1.sdkClientMethodFactory,
@@ -112,13 +112,11 @@ function clientFactory(params) {
112
112
  }
113
113
  // Internal function
114
114
  function processEvaluation(evaluation, featureFlagName, key, withConfig, invokingMethodName, queue, options) {
115
- var _a;
116
115
  if (options === void 0) { options = {}; }
117
116
  var matchingKey = (0, key_1.getMatching)(key);
118
117
  var bucketingKey = (0, key_1.getBucketing)(key);
119
118
  var definition = evaluation.definition;
120
- var treatment = evaluation.treatment, label = evaluation.label;
121
- var config = ((_a = definition === null || definition === void 0 ? void 0 : definition.configurations) === null || _a === void 0 ? void 0 : _a[treatment]) || null;
119
+ var treatment = evaluation.treatment, label = evaluation.label, _a = evaluation.config, config = _a === void 0 ? null : _a;
122
120
  if (treatment === constants_1.CONTROL) {
123
121
  var fallbackTreatment = fallbackCalculator(featureFlagName, label);
124
122
  treatment = fallbackTreatment.treatment;
@@ -135,10 +133,10 @@ function clientFactory(params) {
135
133
  time: Date.now(),
136
134
  bucketingKey: bucketingKey,
137
135
  label: label,
138
- changeNumber: definition.changeNumber,
136
+ changeNumber: definition === null || definition === void 0 ? void 0 : definition.changeNumber,
139
137
  properties: stringify(options.properties)
140
138
  },
141
- disabled: options.impressionsDisabled || definition.impressionsDisabled
139
+ disabled: options.impressionsDisabled || (definition === null || definition === void 0 ? void 0 : definition.impressionsDisabled)
142
140
  });
143
141
  }
144
142
  if (withConfig) {
@@ -61,6 +61,8 @@ function sdkLifecycleFactory(params, isSharedClient) {
61
61
  }
62
62
  // Stop background jobs
63
63
  syncManager && syncManager.stop();
64
+ // Stop the service API (the auth provider backoff retries specifically) before flushing,
65
+ // so that a pending/never-resolved auth retry doesn't block the flush forever
64
66
  serviceApi && serviceApi.stop();
65
67
  return __flush().then(function () {
66
68
  // Cleanup storage
@@ -9,32 +9,35 @@ var SKEW_SECONDS = 30;
9
9
  function isExpired(credential) {
10
10
  return Date.now() / 1000 + SKEW_SECONDS >= credential.decodedToken.exp;
11
11
  }
12
+ function noCachedCredentialError() {
13
+ return new Error(constants_1.LOG_PREFIX_SYNC_AUTH + 'stopped without a cached credential');
14
+ }
12
15
  /**
13
16
  * Factory of AuthProvider, which provides JWT credentials for authenticated HTTP requests.
14
17
  * Credentials are fetched lazily on demand, cached in memory, and retried with backoff on failure.
15
18
  */
16
19
  function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
17
20
  var urls = settings.urls, log = settings.log;
18
- function fetchAuth() {
21
+ var fetchAuth = (0, AuthClient_1.fetchAuthFactory)(function () {
19
22
  var url = "".concat(urls.auth, "/api/v3/auth?capabilities=config,aiconfig");
20
23
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_2.TOKEN), false, true);
21
- }
22
- var authenticate = (0, AuthClient_1.authenticateFactory)(fetchAuth);
24
+ });
23
25
  var backoff = new Backoff_1.Backoff(fetchCredential);
24
26
  var cachedCredential;
25
27
  var inFlightPromise;
26
28
  var stopped = false;
27
29
  function fetchCredential() {
28
- return authenticate().then(function (credential) {
30
+ return fetchAuth().then(function (credential) {
29
31
  log.info(constants_1.LOG_PREFIX_SYNC_AUTH + 'credential fetched successfully');
30
32
  cachedCredential = credential;
31
33
  inFlightPromise = undefined;
32
34
  backoff.reset();
33
35
  return credential;
34
36
  }).catch(function (error) {
35
- // Avoid rejected promises and unnecessary retries after stop()
37
+ // Avoid unnecessary retries after stop(): fall back to any cached credential, or reject
38
+ // (never resolve with `undefined`, which callers would otherwise send as an unauthenticated request).
36
39
  if (stopped)
37
- return cachedCredential;
40
+ return cachedCredential || Promise.reject(noCachedCredentialError());
38
41
  if (error.statusCode && error.statusCode >= 400 && error.statusCode < 500) {
39
42
  log.error(constants_1.LOG_PREFIX_SYNC_AUTH + 'non-retryable error fetching credential (status ' + error.statusCode + '): ' + error.message);
40
43
  inFlightPromise = undefined;
@@ -49,18 +52,28 @@ function authProviderFactory(settings, splitHttpClient, telemetryTracker) {
49
52
  if (cachedCredential && !isExpired(cachedCredential)) {
50
53
  return Promise.resolve(cachedCredential);
51
54
  }
55
+ // Reuse any fetch already in flight (e.g. one started just before stop()), instead of firing a redundant one.
56
+ if (inFlightPromise)
57
+ return inFlightPromise;
58
+ // No cached credential to fall back to and stopped: reject so callers don't send an unauthenticated request.
59
+ if (stopped && !cachedCredential) {
60
+ return Promise.reject(noCachedCredentialError());
61
+ }
52
62
  if (cachedCredential)
53
63
  log.debug(constants_1.LOG_PREFIX_SYNC_AUTH + 'cached credential expired');
54
- return inFlightPromise || (inFlightPromise = fetchCredential());
64
+ // If stopped, this is a last, bounded refetch: fetchCredential()'s catch short-circuits (no backoff retry)
65
+ // once stopped, so it's a single attempt that falls back to the stale cached credential on failure.
66
+ return inFlightPromise = fetchCredential();
55
67
  },
56
68
  invalidate: function () {
57
69
  cachedCredential = undefined;
58
70
  },
59
71
  stop: function () {
60
72
  stopped = true;
61
- cachedCredential = undefined;
62
- inFlightPromise = undefined;
63
- backoff.reset();
73
+ // Keep any in-flight fetch and already-cached credential usable (e.g. by a final flush on destroy).
74
+ // If a retry is only pending (not actively in flight), settle it immediately instead of waiting out the
75
+ // backoff delay: with the cached credential if there is one, or rejected otherwise.
76
+ backoff.reset(cachedCredential ? { value: cachedCredential } : { error: noCachedCredentialError() });
64
77
  }
65
78
  };
66
79
  }
@@ -2,31 +2,28 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.secureSplitHttpClientFactory = void 0;
4
4
  var tslib_1 = require("tslib");
5
- var splitHttpClient_1 = require("./splitHttpClient");
6
- var authProvider_1 = require("./authProvider");
7
5
  /**
8
6
  * Factory of Secure HTTP client, which authenticates requests using a JWT token.
9
7
  * On 401 responses, invalidates the cached credential and retries once with a fresh token.
10
8
  *
11
- * @param settings - SDK settings
12
- * @param platform - object containing environment-specific dependencies
13
- * @param fetchAuth - function to fetch auth credentials from the /v2/auth endpoint
9
+ * @param splitHttpClient - `splitHttpClientFactory` to use for making requests
10
+ * @param authProvider - `authProviderFactory` to use for authentication
14
11
  */
15
- function secureSplitHttpClientFactory(settings, platform, telemetryTracker) {
16
- var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
17
- var authProvider = (0, authProvider_1.authProviderFactory)(settings, splitHttpClient, telemetryTracker);
18
- function makeRequest(url, options, latencyTracker, logErrorsAsInfo, token) {
19
- return splitHttpClient(url, tslib_1.__assign(tslib_1.__assign({}, options), { headers: tslib_1.__assign(tslib_1.__assign({}, options === null || options === void 0 ? void 0 : options.headers), { Authorization: "Bearer ".concat(token) }) }), latencyTracker, logErrorsAsInfo, true);
12
+ function secureSplitHttpClientFactory(splitHttpClient, authProvider) {
13
+ function makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, token) {
14
+ return splitHttpClient(url, token ? tslib_1.__assign(tslib_1.__assign({}, options), { headers: tslib_1.__assign(tslib_1.__assign({}, options === null || options === void 0 ? void 0 : options.headers), { Authorization: "Bearer ".concat(token) }) }) : options, latencyTracker, logErrorsAsInfo, newVersionHeader);
20
15
  }
21
- var httpClient = function (url, options, latencyTracker, logErrorsAsInfo) {
16
+ var httpClient = function (url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt) {
17
+ if (newVersionHeader === void 0) { newVersionHeader = true; }
18
+ if (useJwt === void 0) { useJwt = true; }
22
19
  return authProvider.credential().then(function (credential) {
23
- return makeRequest(url, options, latencyTracker, logErrorsAsInfo, credential.token)
20
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? credential.token : undefined)
24
21
  .catch(function (error) {
25
22
  if (error.statusCode === 401) {
26
23
  // retry once for 401, in case the token has just expired
27
24
  authProvider.invalidate();
28
25
  return authProvider.credential().then(function (newCredential) {
29
- return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newCredential.token);
26
+ return makeRequest(url, options, latencyTracker, logErrorsAsInfo, newVersionHeader, useJwt ? newCredential.token : undefined);
30
27
  });
31
28
  }
32
29
  throw error;
@@ -5,25 +5,36 @@ 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 authProvider_1 = require("./authProvider");
9
+ var secureSplitHttpClient_1 = require("./secureSplitHttpClient");
8
10
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
9
- function userKeyToQueryParam(userKey) {
10
- return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
11
- }
12
11
  /**
13
12
  * Factory of ServiceApi objects, which group the collection of HTTP endpoints used by the SDKs
14
13
  *
15
14
  * @param settings - validated settings object
16
15
  * @param platform - object containing environment-specific dependencies
17
16
  * @param telemetryTracker - telemetry tracker
18
- * @param secureSplitHttpClientFactory - factory of SecureSplitHttpClient objects
19
17
  */
20
- function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttpClientFactory) {
18
+ function serviceApiFactory(settings, platform, telemetryTracker) {
21
19
  var urls = settings.urls;
22
20
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
23
21
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
24
22
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
25
- var secureSplitHttpClient = secureSplitHttpClientFactory(settings, platform, telemetryTracker);
23
+ // Shared authProvider so that the SSE authentication (via `fetchAuth`,
24
+ // used by `pushManager`) and every authenticated HTTP request to the Configs
25
+ // API reuse the same cached credential instead of each fetching their own.
26
+ var authProvider = (0, authProvider_1.authProviderFactory)(settings, splitHttpClient, telemetryTracker);
27
+ var secureSplitHttpClient = (0, secureSplitHttpClient_1.secureSplitHttpClientFactory)(splitHttpClient, authProvider);
28
+ var initialAuth = true;
26
29
  return {
30
+ fetchAuth: function () {
31
+ // Guard condition to avoid invalidating the cached credential on the first pushManager authentication
32
+ if (initialAuth)
33
+ initialAuth = false;
34
+ else
35
+ authProvider.invalidate();
36
+ return authProvider.credential();
37
+ },
27
38
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
28
39
  getSdkAPIHealthCheck: function () {
29
40
  var url = "".concat(urls.sdk, "/api/version");
@@ -33,15 +44,6 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
33
44
  var url = "".concat(urls.events, "/api/version");
34
45
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
35
46
  },
36
- fetchAuth: function (userMatchingKeys) {
37
- var url = "".concat(urls.auth, "/api/v2/auth?s=").concat(settings.sync.flagSpecVersion);
38
- if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
39
- var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
40
- if (queryParams)
41
- url += '&' + queryParams;
42
- }
43
- return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
44
- },
45
47
  fetchSplitChanges: function (since, noCache, till, rbSince) {
46
48
  var url = "".concat(urls.sdk, "/api/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
47
49
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
@@ -82,7 +84,7 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
82
84
  */
83
85
  postEventsBulk: function (body, headers) {
84
86
  var url = "".concat(urls.events, "/api/events/bulk");
85
- return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.EVENTS));
87
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.EVENTS), false, false, false);
86
88
  },
87
89
  /**
88
90
  * Post impressions.
@@ -92,12 +94,12 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
92
94
  */
93
95
  postTestImpressionsBulk: function (body, headers) {
94
96
  var url = "".concat(urls.events, "/api/testImpressions/bulk");
95
- return splitHttpClient(url, {
97
+ return secureSplitHttpClient(url, {
96
98
  // Adding extra headers to send impressions in OPTIMIZED or DEBUG modes.
97
99
  method: 'POST',
98
100
  body: body,
99
101
  headers: (0, objectAssign_1.objectAssign)({ SplitSDKImpressionsMode: SplitSDKImpressionsMode }, headers)
100
- }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS));
102
+ }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS), false, false, false);
101
103
  },
102
104
  /**
103
105
  * Post impressions counts.
@@ -107,7 +109,7 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
107
109
  */
108
110
  postTestImpressionsCount: function (body, headers) {
109
111
  var url = "".concat(urls.events, "/api/testImpressions/count");
110
- return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS_COUNT));
112
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.IMPRESSIONS_COUNT), false, false, false);
111
113
  },
112
114
  /**
113
115
  * Post unique keys for client side.
@@ -117,7 +119,7 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
117
119
  */
118
120
  postUniqueKeysBulkCs: function (body, headers) {
119
121
  var url = "".concat(urls.telemetry, "/api/v1/keys/cs");
120
- return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY));
122
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
121
123
  },
122
124
  /**
123
125
  * Post unique keys for server side.
@@ -127,7 +129,7 @@ function serviceApiFactory(settings, platform, telemetryTracker, secureSplitHttp
127
129
  */
128
130
  postUniqueKeysBulkSs: function (body, headers) {
129
131
  var url = "".concat(urls.telemetry, "/api/v1/keys/ss");
130
- return splitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY));
132
+ return secureSplitHttpClient(url, { method: 'POST', body: body, headers: headers }, telemetryTracker.trackHttp(constants_1.TELEMETRY), false, false, false);
131
133
  },
132
134
  postMetricsConfig: function (body, headers) {
133
135
  var url = "".concat(urls.telemetry, "/api/v1/metrics/config");
@@ -5,6 +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
9
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
9
10
  function userKeyToQueryParam(userKey) {
10
11
  return 'users=' + encodeURIComponent(userKey); // no need to check availability of `encodeURIComponent`, since it is a global highly supported.
@@ -23,6 +24,15 @@ function splitApiFactory(settings, platform, telemetryTracker) {
23
24
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
24
25
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
25
26
  return {
27
+ fetchAuth: (0, AuthClient_1.fetchAuthFactory)(function (userMatchingKeys) {
28
+ var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
29
+ if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
30
+ var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
31
+ if (queryParams)
32
+ url += '&' + queryParams;
33
+ }
34
+ return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
35
+ }),
26
36
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
27
37
  getSdkAPIHealthCheck: function () {
28
38
  var url = "".concat(urls.sdk, "/version");
@@ -32,15 +42,6 @@ function splitApiFactory(settings, platform, telemetryTracker) {
32
42
  var url = "".concat(urls.events, "/version");
33
43
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
34
44
  },
35
- fetchAuth: function (userMatchingKeys) {
36
- var url = "".concat(urls.auth, "/v2/auth?s=").concat(settings.sync.flagSpecVersion);
37
- if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
38
- var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
39
- if (queryParams)
40
- url += '&' + queryParams;
41
- }
42
- return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
43
- },
44
45
  fetchSplitChanges: function (since, noCache, till, rbSince) {
45
46
  var url = "".concat(urls.sdk, "/splitChanges?s=").concat(settings.sync.flagSpecVersion, "&since=").concat(since).concat(rbSince ? '&rbSince=' + rbSince : '').concat(filterQueryString || '').concat(till ? '&till=' + till : '');
46
47
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.RedisAdapter = void 0;
4
4
  var tslib_1 = require("tslib");
5
5
  // Dynamically require ioredis to prevent strict TypeScript binding
6
- // and handle module export differences between v4 and v5.
6
+ // and handle module export differences between v4 and later major versions.
7
7
  var RedisConstructor;
8
8
  try {
9
9
  var ioredisLib = require('ioredis');
@@ -11,7 +11,7 @@ try {
11
11
  }
12
12
  catch (e) {
13
13
  // If we reach here, the peer dependency is missing
14
- throw new Error('ioredis is missing. Please install ioredis v4 or v5.');
14
+ throw new Error('ioredis is missing. Please install ioredis v4, v5 or v6.');
15
15
  }
16
16
  var lang_1 = require("../../utils/lang");
17
17
  var thenable_1 = require("../../utils/promise/thenable");
@@ -31,13 +31,16 @@ var DEFAULT_LIBRARY_OPTIONS = {
31
31
  enableOfflineQueue: false,
32
32
  connectTimeout: DEFAULT_OPTIONS.connectionTimeout,
33
33
  lazyConnect: false,
34
- // CRITICAL: v5 defaults this to 0 (disabled), which breaks dynamic clusters.
35
- // v4 defaulted to 5000. We explicitly set it here to ensure v5 works like v4.
34
+ // CRITICAL: v5 and v6 default this to 0 (disabled), which breaks dynamic clusters.
35
+ // v4 defaulted to 5000. We explicitly set it here to ensure v5 and v6 work like v4.
36
36
  slotsRefreshInterval: 5000,
37
+ // v6 defaults to RESP3 (`protocol: 3`). The SDK doesn't use any RESP3 feature,
38
+ // so we stick to RESP2 to keep the v4 and v5 behavior. Ignored by v4 and v5.
39
+ protocol: 2,
37
40
  };
38
41
  /**
39
42
  * Redis adapter on top of the library of choice (written with ioredis) for some extra control.
40
- * Refactored to use Composition instead of Inheritance to support both v4 and v5.
43
+ * Refactored to use Composition instead of Inheritance to support v4, v5 and v6.
41
44
  */
42
45
  var RedisAdapter = /** @class */ (function () {
43
46
  function RedisAdapter(log, storageSettings) {
@@ -8,93 +8,98 @@ var key_1 = require("../../utils/key");
8
8
  var constants_1 = require("../../readiness/constants");
9
9
  var constants_2 = require("../../logger/constants");
10
10
  var AbstractDefinitionsCacheSync_1 = require("../../storages/AbstractDefinitionsCacheSync");
11
+ var splitChangesFetcher_1 = require("./fetchers/splitChangesFetcher");
11
12
  /**
12
13
  * Expose start / stop mechanism for polling data from services.
13
14
  * For client-side API with multiple clients.
14
15
  */
15
- function pollingManagerCSFactory(params, definitionChangesFetcher) {
16
- var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
17
- var log = settings.log;
18
- var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
19
- // Map of matching keys to their corresponding MySegmentsSyncTask.
20
- var mySegmentsSyncTasks = {};
21
- var matchingKey = (0, key_1.getMatching)(settings.core.key);
22
- var mySegmentsSyncTask = add(matchingKey, readiness, storage);
23
- function startMySegmentsSyncTasks() {
24
- (0, lang_1.forOwn)(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
25
- mySegmentsSyncTask.start();
26
- });
27
- }
28
- function stopMySegmentsSyncTasks() {
29
- (0, lang_1.forOwn)(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
30
- if (mySegmentsSyncTask.isRunning())
31
- mySegmentsSyncTask.stop();
32
- });
33
- }
34
- // smart pausing
35
- readiness.definitions.on(constants_1.SDK_DEFINITIONS_ARRIVED, function () {
36
- if (!definitionsSyncTask.isRunning())
37
- return; // noop if not doing polling
38
- var usingSegments = (0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage);
39
- if (usingSegments !== mySegmentsSyncTask.isRunning()) {
40
- log.info(constants_2.POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
41
- if (usingSegments) {
42
- startMySegmentsSyncTasks();
43
- }
44
- else {
45
- stopMySegmentsSyncTasks();
46
- }
47
- }
48
- });
49
- function add(matchingKey, readiness, storage) {
50
- var mySegmentsSyncTask = (0, mySegmentsSyncTask_1.mySegmentsSyncTaskFactory)(serviceApi.fetchMemberships, storage, readiness, settings, matchingKey);
51
- // smart ready
52
- function smartReady(metadata) {
53
- if (!readiness.isReady() && !(0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
54
- readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED, metadata);
16
+ function pollingManagerCSFactory(definitionFetcherFactory) {
17
+ if (definitionFetcherFactory === void 0) { definitionFetcherFactory = splitChangesFetcher_1.splitChangesFetcherFactory; }
18
+ return function (params) {
19
+ var serviceApi = params.serviceApi, storage = params.storage, readiness = params.readiness, settings = params.settings;
20
+ var log = settings.log;
21
+ var definitionChangesFetcher = definitionFetcherFactory(params);
22
+ var definitionsSyncTask = (0, definitionsSyncTask_1.definitionsSyncTaskFactory)(definitionChangesFetcher, storage, readiness, settings);
23
+ // Map of matching keys to their corresponding MySegmentsSyncTask.
24
+ var mySegmentsSyncTasks = {};
25
+ var matchingKey = (0, key_1.getMatching)(settings.core.key);
26
+ var mySegmentsSyncTask = add(matchingKey, readiness, storage);
27
+ function startMySegmentsSyncTasks() {
28
+ (0, lang_1.forOwn)(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
29
+ mySegmentsSyncTask.start();
30
+ });
55
31
  }
56
- if (!(0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
57
- setTimeout(smartReady, 0);
58
- else
59
- readiness.definitions.once(constants_1.SDK_DEFINITIONS_ARRIVED, smartReady);
60
- mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
61
- return mySegmentsSyncTask;
62
- }
63
- return {
64
- definitionsSyncTask: definitionsSyncTask,
65
- segmentsSyncTask: mySegmentsSyncTask,
66
- // Start periodic fetching (polling)
67
- start: function () {
68
- log.info(constants_2.POLLING_START);
69
- definitionsSyncTask.start();
70
- if ((0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
71
- startMySegmentsSyncTasks();
72
- },
73
- // Stop periodic fetching (polling)
74
- stop: function () {
75
- log.info(constants_2.POLLING_STOP);
76
- if (definitionsSyncTask.isRunning())
77
- definitionsSyncTask.stop();
78
- stopMySegmentsSyncTasks();
79
- },
80
- // Used by SyncManager to know if running in polling mode.
81
- isRunning: definitionsSyncTask.isRunning,
82
- // fetch definitions and segments
83
- syncAll: function () {
84
- var promises = [definitionsSyncTask.execute()];
32
+ function stopMySegmentsSyncTasks() {
85
33
  (0, lang_1.forOwn)(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
86
- promises.push(mySegmentsSyncTask.execute());
34
+ if (mySegmentsSyncTask.isRunning())
35
+ mySegmentsSyncTask.stop();
87
36
  });
88
- return Promise.all(promises);
89
- },
90
- // Support for handling mySegments sync of multiple clients
91
- add: add,
92
- remove: function (matchingKey) {
93
- delete mySegmentsSyncTasks[matchingKey];
94
- },
95
- get: function (matchingKey) {
96
- return mySegmentsSyncTasks[matchingKey];
97
37
  }
38
+ // smart pausing
39
+ readiness.definitions.on(constants_1.SDK_DEFINITIONS_ARRIVED, function () {
40
+ if (!definitionsSyncTask.isRunning())
41
+ return; // noop if not doing polling
42
+ var usingSegments = (0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage);
43
+ if (usingSegments !== mySegmentsSyncTask.isRunning()) {
44
+ log.info(constants_2.POLLING_SMART_PAUSING, [usingSegments ? 'ON' : 'OFF']);
45
+ if (usingSegments) {
46
+ startMySegmentsSyncTasks();
47
+ }
48
+ else {
49
+ stopMySegmentsSyncTasks();
50
+ }
51
+ }
52
+ });
53
+ function add(matchingKey, readiness, storage) {
54
+ var mySegmentsSyncTask = (0, mySegmentsSyncTask_1.mySegmentsSyncTaskFactory)(serviceApi.fetchMemberships, storage, readiness, settings, matchingKey);
55
+ // smart ready
56
+ function smartReady(metadata) {
57
+ if (!readiness.isReady() && !(0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
58
+ readiness.segments.emit(constants_1.SDK_SEGMENTS_ARRIVED, metadata);
59
+ }
60
+ if (!(0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
61
+ setTimeout(smartReady, 0);
62
+ else
63
+ readiness.definitions.once(constants_1.SDK_DEFINITIONS_ARRIVED, smartReady);
64
+ mySegmentsSyncTasks[matchingKey] = mySegmentsSyncTask;
65
+ return mySegmentsSyncTask;
66
+ }
67
+ return {
68
+ definitionsSyncTask: definitionsSyncTask,
69
+ segmentsSyncTask: mySegmentsSyncTask,
70
+ // Start periodic fetching (polling)
71
+ start: function () {
72
+ log.info(constants_2.POLLING_START);
73
+ definitionsSyncTask.start();
74
+ if ((0, AbstractDefinitionsCacheSync_1.usesSegmentsSync)(storage))
75
+ startMySegmentsSyncTasks();
76
+ },
77
+ // Stop periodic fetching (polling)
78
+ stop: function () {
79
+ log.info(constants_2.POLLING_STOP);
80
+ if (definitionsSyncTask.isRunning())
81
+ definitionsSyncTask.stop();
82
+ stopMySegmentsSyncTasks();
83
+ },
84
+ // Used by SyncManager to know if running in polling mode.
85
+ isRunning: definitionsSyncTask.isRunning,
86
+ // fetch definitions and segments
87
+ syncAll: function () {
88
+ var promises = [definitionsSyncTask.execute()];
89
+ (0, lang_1.forOwn)(mySegmentsSyncTasks, function (mySegmentsSyncTask) {
90
+ promises.push(mySegmentsSyncTask.execute());
91
+ });
92
+ return Promise.all(promises);
93
+ },
94
+ // Support for handling mySegments sync of multiple clients
95
+ add: add,
96
+ remove: function (matchingKey) {
97
+ delete mySegmentsSyncTasks[matchingKey];
98
+ },
99
+ get: function (matchingKey) {
100
+ return mySegmentsSyncTasks[matchingKey];
101
+ }
102
+ };
98
103
  };
99
104
  }
100
105
  exports.pollingManagerCSFactory = pollingManagerCSFactory;