@splitsoftware/splitio-commons 2.0.2 → 2.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGES.txt CHANGED
@@ -1,3 +1,6 @@
1
+ 2.0.3 (January 9, 2025)
2
+ - Bugfixing - Properly handle rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages).
3
+
1
4
  2.0.2 (December 3, 2024)
2
5
  - Updated the factory `init` and `destroy` methods to support re-initialization after destruction. This update ensures compatibility of the React SDK with React Strict Mode, where the factory's `init` and `destroy` effects are executed an extra time to validate proper resource cleanup.
3
6
  - Bugfixing - Sanitize the `SplitSDKMachineName` header value to avoid exceptions on HTTP/S requests when it contains non ISO-8859-1 characters (Related to issue https://github.com/splitio/javascript-client/issues/847).
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2024 Split Software, Inc.
1
+ Copyright © 2025 Split Software, Inc.
2
2
 
3
3
  Licensed under the Apache License, Version 2.0 (the "License");
4
4
  you may not use this file except in compliance with the License.
package/README.md CHANGED
@@ -14,7 +14,7 @@ This library is compatible with JavaScript ES5 and above.
14
14
  Please see [Contributors Guide](CONTRIBUTORS-GUIDE.md) to find all you need to submit a Pull Request (PR).
15
15
 
16
16
  ## License
17
- Licensed under the Apache License, Version 2.0. See: [Apache License](http://www.apache.org/licenses/).
17
+ Licensed under the Apache License, Version 2.0. See: [Apache License](https://www.apache.org/licenses/).
18
18
 
19
19
  ## About Split
20
20
 
@@ -46,4 +46,4 @@ For a comprehensive list of open source projects visit our [Github page](https:/
46
46
 
47
47
  **Learn more about Split:**
48
48
 
49
- Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information.
49
+ Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](https://help.split.io) for more detailed information.
@@ -1,15 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.largeSegmentMatcherContext = void 0;
4
- var thenable_1 = require("../../utils/promise/thenable");
5
4
  function largeSegmentMatcherContext(largeSegmentName, storage) {
6
5
  return function largeSegmentMatcher(key) {
7
6
  var isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
8
- if ((0, thenable_1.thenable)(isInLargeSegment)) {
9
- isInLargeSegment.then(function (result) {
10
- return result;
11
- });
12
- }
13
7
  return isInLargeSegment;
14
8
  };
15
9
  }
@@ -1,15 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.segmentMatcherContext = void 0;
4
- var thenable_1 = require("../../utils/promise/thenable");
5
4
  function segmentMatcherContext(segmentName, storage) {
6
5
  return function segmentMatcher(key) {
7
6
  var isInSegment = storage.segments.isInSegment(segmentName, key);
8
- if ((0, thenable_1.thenable)(isInSegment)) {
9
- isInSegment.then(function (result) {
10
- return result;
11
- });
12
- }
13
7
  return isInSegment;
14
8
  };
15
9
  }
@@ -43,7 +43,7 @@ var NodeSignalListener = /** @class */ (function () {
43
43
  var wrapUp = function () {
44
44
  // Cleaned up, remove handlers.
45
45
  _this.stop();
46
- // This handler prevented the default behaviour, start again.
46
+ // This handler prevented the default behavior, start again.
47
47
  // eslint-disable-next-line no-undef
48
48
  process.kill(process.pid, SIGTERM);
49
49
  };
@@ -56,7 +56,7 @@ var NodeSignalListener = /** @class */ (function () {
56
56
  this.settings.log.error(constants_1.LOG_PREFIX_CLEANUP + "Error with Split SDK graceful shutdown: " + err);
57
57
  }
58
58
  if ((0, thenable_1.thenable)(handlerResult)) {
59
- // Always exit, even with errors. The promise is returned for UT purposses.
59
+ // Always exit, even with errors. The promise is returned for UT purposes.
60
60
  return handlerResult.then(wrapUp).catch(wrapUp);
61
61
  }
62
62
  else {
@@ -241,9 +241,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
241
241
  this.log.error(constants_1.LOG_PREFIX + this.redisError);
242
242
  return Promise.reject(this.redisError);
243
243
  }
244
- var splits = {};
245
244
  var keys = names.map(function (name) { return _this.keys.buildSplitKey(name); });
246
245
  return (_a = this.redis).mget.apply(_a, keys).then(function (splitDefinitions) {
246
+ var splits = {};
247
247
  names.forEach(function (name, idx) {
248
248
  var split = splitDefinitions[idx];
249
249
  splits[name] = split && JSON.parse(split);
@@ -309,12 +309,14 @@ function pushManagerFactory(params, pollingManager) {
309
309
  // Reconnects in case of a new client.
310
310
  // Run in next event-loop cycle to save authentication calls
311
311
  // in case multiple clients are created in the current cycle.
312
- setTimeout(function checkForReconnect() {
313
- if (connectForNewClient) {
314
- connectForNewClient = false;
315
- connectPush();
316
- }
317
- }, 0);
312
+ if (this.isRunning()) {
313
+ setTimeout(function checkForReconnect() {
314
+ if (connectForNewClient) {
315
+ connectForNewClient = false;
316
+ connectPush();
317
+ }
318
+ }, 0);
319
+ }
318
320
  }
319
321
  },
320
322
  // [Only for client-side]
@@ -118,6 +118,8 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
118
118
  if (!pollingManager)
119
119
  return;
120
120
  var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
121
+ if (syncEnabled && pushManager)
122
+ pushManager.add(matchingKey, mySegmentsSyncTask);
121
123
  if (running) {
122
124
  if (syncEnabled) {
123
125
  if (pushManager) {
@@ -131,7 +133,6 @@ function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFactory) {
131
133
  // of segments since `syncAll` was already executed when starting the main client
132
134
  mySegmentsSyncTask.execute();
133
135
  }
134
- pushManager.add(matchingKey, mySegmentsSyncTask);
135
136
  }
136
137
  else {
137
138
  if (storage.splits.usesSegments())
@@ -25,7 +25,7 @@ function eventTrackerFactory(settings, eventsCache, whenInit, integrationsManage
25
25
  whenInit(function () {
26
26
  // Wrap in a timeout because we don't want it to be blocking.
27
27
  setTimeout(function () {
28
- // copy of event, to avoid unexpected behaviour if modified by integrations
28
+ // copy of event, to avoid unexpected behavior if modified by integrations
29
29
  var eventDataCopy = (0, objectAssign_1.objectAssign)({}, eventData);
30
30
  if (properties)
31
31
  eventDataCopy.properties = (0, objectAssign_1.objectAssign)({}, properties);
@@ -46,7 +46,7 @@ function impressionsTrackerFactory(settings, impressionsCache, strategy, whenIni
46
46
  if (impressionListener || integrationsManager) {
47
47
  var _loop_1 = function (i) {
48
48
  var impressionData = {
49
- // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
49
+ // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
50
50
  impression: (0, objectAssign_1.objectAssign)({}, impressionsToListener[i]),
51
51
  attributes: attributes,
52
52
  ip: ip,
@@ -139,7 +139,7 @@ function settingsValidation(config, validationParams) {
139
139
  withDefaults.core.key = 'localhost_key';
140
140
  }
141
141
  else {
142
- // Keeping same behaviour than JS SDK: if settings key or TT are invalid,
142
+ // Keeping same behavior than JS SDK: if settings key or TT are invalid,
143
143
  // `false` value is used as bound key/TT of the default client, which leads to some issues.
144
144
  // @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
145
145
  withDefaults.core.key = (0, key_1.validateKey)(log, maybeKey, constants_2.LOG_PREFIX_CLIENT_INSTANTIATION);
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function largeSegmentMatcherContext(largeSegmentName, storage) {
3
2
  return function largeSegmentMatcher(key) {
4
3
  var isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
5
- if (thenable(isInLargeSegment)) {
6
- isInLargeSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInLargeSegment;
11
5
  };
12
6
  }
@@ -1,12 +1,6 @@
1
- import { thenable } from '../../utils/promise/thenable';
2
1
  export function segmentMatcherContext(segmentName, storage) {
3
2
  return function segmentMatcher(key) {
4
3
  var isInSegment = storage.segments.isInSegment(segmentName, key);
5
- if (thenable(isInSegment)) {
6
- isInSegment.then(function (result) {
7
- return result;
8
- });
9
- }
10
4
  return isInSegment;
11
5
  };
12
6
  }
@@ -40,7 +40,7 @@ var NodeSignalListener = /** @class */ (function () {
40
40
  var wrapUp = function () {
41
41
  // Cleaned up, remove handlers.
42
42
  _this.stop();
43
- // This handler prevented the default behaviour, start again.
43
+ // This handler prevented the default behavior, start again.
44
44
  // eslint-disable-next-line no-undef
45
45
  process.kill(process.pid, SIGTERM);
46
46
  };
@@ -53,7 +53,7 @@ var NodeSignalListener = /** @class */ (function () {
53
53
  this.settings.log.error(LOG_PREFIX_CLEANUP + "Error with Split SDK graceful shutdown: " + err);
54
54
  }
55
55
  if (thenable(handlerResult)) {
56
- // Always exit, even with errors. The promise is returned for UT purposses.
56
+ // Always exit, even with errors. The promise is returned for UT purposes.
57
57
  return handlerResult.then(wrapUp).catch(wrapUp);
58
58
  }
59
59
  else {
@@ -238,9 +238,9 @@ var SplitsCacheInRedis = /** @class */ (function (_super) {
238
238
  this.log.error(LOG_PREFIX + this.redisError);
239
239
  return Promise.reject(this.redisError);
240
240
  }
241
- var splits = {};
242
241
  var keys = names.map(function (name) { return _this.keys.buildSplitKey(name); });
243
242
  return (_a = this.redis).mget.apply(_a, keys).then(function (splitDefinitions) {
243
+ var splits = {};
244
244
  names.forEach(function (name, idx) {
245
245
  var split = splitDefinitions[idx];
246
246
  splits[name] = split && JSON.parse(split);
@@ -306,12 +306,14 @@ export function pushManagerFactory(params, pollingManager) {
306
306
  // Reconnects in case of a new client.
307
307
  // Run in next event-loop cycle to save authentication calls
308
308
  // in case multiple clients are created in the current cycle.
309
- setTimeout(function checkForReconnect() {
310
- if (connectForNewClient) {
311
- connectForNewClient = false;
312
- connectPush();
313
- }
314
- }, 0);
309
+ if (this.isRunning()) {
310
+ setTimeout(function checkForReconnect() {
311
+ if (connectForNewClient) {
312
+ connectForNewClient = false;
313
+ connectPush();
314
+ }
315
+ }, 0);
316
+ }
315
317
  }
316
318
  },
317
319
  // [Only for client-side]
@@ -115,6 +115,8 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
115
115
  if (!pollingManager)
116
116
  return;
117
117
  var mySegmentsSyncTask = pollingManager.add(matchingKey, readinessManager, storage);
118
+ if (syncEnabled && pushManager)
119
+ pushManager.add(matchingKey, mySegmentsSyncTask);
118
120
  if (running) {
119
121
  if (syncEnabled) {
120
122
  if (pushManager) {
@@ -128,7 +130,6 @@ export function syncManagerOnlineFactory(pollingManagerFactory, pushManagerFacto
128
130
  // of segments since `syncAll` was already executed when starting the main client
129
131
  mySegmentsSyncTask.execute();
130
132
  }
131
- pushManager.add(matchingKey, mySegmentsSyncTask);
132
133
  }
133
134
  else {
134
135
  if (storage.splits.usesSegments())
@@ -22,7 +22,7 @@ export function eventTrackerFactory(settings, eventsCache, whenInit, integration
22
22
  whenInit(function () {
23
23
  // Wrap in a timeout because we don't want it to be blocking.
24
24
  setTimeout(function () {
25
- // copy of event, to avoid unexpected behaviour if modified by integrations
25
+ // copy of event, to avoid unexpected behavior if modified by integrations
26
26
  var eventDataCopy = objectAssign({}, eventData);
27
27
  if (properties)
28
28
  eventDataCopy.properties = objectAssign({}, properties);
@@ -43,7 +43,7 @@ export function impressionsTrackerFactory(settings, impressionsCache, strategy,
43
43
  if (impressionListener || integrationsManager) {
44
44
  var _loop_1 = function (i) {
45
45
  var impressionData = {
46
- // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
46
+ // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
47
47
  impression: objectAssign({}, impressionsToListener[i]),
48
48
  attributes: attributes,
49
49
  ip: ip,
@@ -136,7 +136,7 @@ export function settingsValidation(config, validationParams) {
136
136
  withDefaults.core.key = 'localhost_key';
137
137
  }
138
138
  else {
139
- // Keeping same behaviour than JS SDK: if settings key or TT are invalid,
139
+ // Keeping same behavior than JS SDK: if settings key or TT are invalid,
140
140
  // `false` value is used as bound key/TT of the default client, which leads to some issues.
141
141
  // @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
142
142
  withDefaults.core.key = validateKey(log, maybeKey, LOG_PREFIX_CLIENT_INSTANTIATION);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "2.0.2",
3
+ "version": "2.0.3",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -1,18 +1,11 @@
1
1
  import { MaybeThenable } from '../../dtos/types';
2
2
  import { ISegmentsCacheBase } from '../../storages/types';
3
- import { thenable } from '../../utils/promise/thenable';
4
3
 
5
4
  export function largeSegmentMatcherContext(largeSegmentName: string, storage: { largeSegments?: ISegmentsCacheBase }) {
6
5
 
7
6
  return function largeSegmentMatcher(key: string): MaybeThenable<boolean> {
8
7
  const isInLargeSegment = storage.largeSegments ? storage.largeSegments.isInSegment(largeSegmentName, key) : false;
9
8
 
10
- if (thenable(isInLargeSegment)) {
11
- isInLargeSegment.then(result => {
12
- return result;
13
- });
14
- }
15
-
16
9
  return isInLargeSegment;
17
10
  };
18
11
  }
@@ -1,18 +1,11 @@
1
1
  import { MaybeThenable } from '../../dtos/types';
2
2
  import { ISegmentsCacheBase } from '../../storages/types';
3
- import { thenable } from '../../utils/promise/thenable';
4
3
 
5
4
  export function segmentMatcherContext(segmentName: string, storage: { segments: ISegmentsCacheBase }) {
6
5
 
7
6
  return function segmentMatcher(key: string): MaybeThenable<boolean> {
8
7
  const isInSegment = storage.segments.isInSegment(segmentName, key);
9
8
 
10
- if (thenable(isInSegment)) {
11
- isInSegment.then(result => {
12
- return result;
13
- });
14
- }
15
-
16
9
  return isInSegment;
17
10
  };
18
11
  }
@@ -56,7 +56,7 @@ export class NodeSignalListener implements ISignalListener {
56
56
  // Cleaned up, remove handlers.
57
57
  this.stop();
58
58
 
59
- // This handler prevented the default behaviour, start again.
59
+ // This handler prevented the default behavior, start again.
60
60
  // eslint-disable-next-line no-undef
61
61
  process.kill(process.pid, SIGTERM);
62
62
  };
@@ -72,7 +72,7 @@ export class NodeSignalListener implements ISignalListener {
72
72
  }
73
73
 
74
74
  if (thenable(handlerResult)) {
75
- // Always exit, even with errors. The promise is returned for UT purposses.
75
+ // Always exit, even with errors. The promise is returned for UT purposes.
76
76
  return handlerResult.then(wrapUp).catch(wrapUp);
77
77
  } else {
78
78
  wrapUp();
@@ -266,10 +266,10 @@ export class SplitsCacheInRedis extends AbstractSplitsCacheAsync {
266
266
  return Promise.reject(this.redisError);
267
267
  }
268
268
 
269
- const splits: Record<string, ISplit | null> = {};
270
269
  const keys = names.map(name => this.keys.buildSplitKey(name));
271
270
  return this.redis.mget(...keys)
272
271
  .then(splitDefinitions => {
272
+ const splits: Record<string, ISplit | null> = {};
273
273
  names.forEach((name, idx) => {
274
274
  const split = splitDefinitions[idx];
275
275
  splits[name] = split && JSON.parse(split);
@@ -349,12 +349,14 @@ export function pushManagerFactory(
349
349
  // Reconnects in case of a new client.
350
350
  // Run in next event-loop cycle to save authentication calls
351
351
  // in case multiple clients are created in the current cycle.
352
- setTimeout(function checkForReconnect() {
353
- if (connectForNewClient) {
354
- connectForNewClient = false;
355
- connectPush();
356
- }
357
- }, 0);
352
+ if (this.isRunning()) {
353
+ setTimeout(function checkForReconnect() {
354
+ if (connectForNewClient) {
355
+ connectForNewClient = false;
356
+ connectPush();
357
+ }
358
+ }, 0);
359
+ }
358
360
  }
359
361
  },
360
362
  // [Only for client-side]
@@ -142,11 +142,12 @@ export function syncManagerOnlineFactory(
142
142
  if (!pollingManager) return;
143
143
 
144
144
  const mySegmentsSyncTask = (pollingManager as IPollingManagerCS).add(matchingKey, readinessManager, storage);
145
+ if (syncEnabled && pushManager) pushManager.add(matchingKey, mySegmentsSyncTask);
145
146
 
146
147
  if (running) {
147
148
  if (syncEnabled) {
148
149
  if (pushManager) {
149
- if (pollingManager!.isRunning()) {
150
+ if (pollingManager.isRunning()) {
150
151
  // if doing polling, we must start the periodic fetch of data
151
152
  if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
152
153
  } else {
@@ -154,7 +155,6 @@ export function syncManagerOnlineFactory(
154
155
  // of segments since `syncAll` was already executed when starting the main client
155
156
  mySegmentsSyncTask.execute();
156
157
  }
157
- pushManager.add(matchingKey, mySegmentsSyncTask);
158
158
  } else {
159
159
  if (storage.splits.usesSegments()) mySegmentsSyncTask.start();
160
160
  }
@@ -36,7 +36,7 @@ export function eventTrackerFactory(
36
36
  whenInit(() => {
37
37
  // Wrap in a timeout because we don't want it to be blocking.
38
38
  setTimeout(() => {
39
- // copy of event, to avoid unexpected behaviour if modified by integrations
39
+ // copy of event, to avoid unexpected behavior if modified by integrations
40
40
  const eventDataCopy = objectAssign({}, eventData);
41
41
  if (properties) eventDataCopy.properties = objectAssign({}, properties);
42
42
  // integrationsManager does not throw errors (they are internally handled by each integration module)
@@ -60,7 +60,7 @@ export function impressionsTrackerFactory(
60
60
  if (impressionListener || integrationsManager) {
61
61
  for (let i = 0; i < impressionsToListenerCount; i++) {
62
62
  const impressionData: SplitIO.ImpressionData = {
63
- // copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
63
+ // copy of impression, to avoid unexpected behavior if modified by integrations or impressionListener
64
64
  impression: objectAssign({}, impressionsToListener[i]),
65
65
  attributes,
66
66
  ip,
@@ -159,7 +159,7 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
159
159
  if (withDefaults.mode === LOCALHOST_MODE && maybeKey === undefined) {
160
160
  withDefaults.core.key = 'localhost_key';
161
161
  } else {
162
- // Keeping same behaviour than JS SDK: if settings key or TT are invalid,
162
+ // Keeping same behavior than JS SDK: if settings key or TT are invalid,
163
163
  // `false` value is used as bound key/TT of the default client, which leads to some issues.
164
164
  // @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
165
165
  withDefaults.core.key = validateKey(log, maybeKey, LOG_PREFIX_CLIENT_INSTANTIATION);
package/types/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // Declaration file for JavaScript Browser Split Software SDK
2
- // Project: http://www.split.io/
2
+ // Project: https://www.split.io/
3
3
  // Definitions by: Nico Zelaya <https://github.com/NicoZelaya/>
4
4
 
5
5
  /// <reference path="./splitio.d.ts" />
@@ -1,5 +1,5 @@
1
1
  // Type definitions for Split Software SDKs
2
- // Project: http://www.split.io/
2
+ // Project: https://www.split.io/
3
3
 
4
4
  import { RedisOptions } from 'ioredis';
5
5
  import { RequestOptions } from 'http';