@splitsoftware/splitio-commons 1.14.0 → 1.14.1-rc.0

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
+ 1.15.0 (May 15, 2024)
2
+ - Added an optional settings validation parameter to let overwrite the default flag spec version, used by the JS Synchronizer.
3
+
1
4
  1.14.0 (May 6, 2024)
2
5
  - Added support for targeting rules based on semantic versions (https://semver.org/).
3
6
  - Added special impression label "targeting rule type unsupported by sdk" when the matcher type is not supported by the SDK, which returns 'control' treatment.
@@ -20,6 +20,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
20
20
  var urls = settings.urls;
21
21
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
22
22
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
23
+ var flagSpecVersion = settings.sync.flagSpecVersion;
23
24
  var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform.getFetch);
24
25
  return {
25
26
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
@@ -32,7 +33,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
32
33
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
33
34
  },
34
35
  fetchAuth: function (userMatchingKeys) {
35
- var url = urls.auth + "/v2/auth?s=" + constants_1.FLAGS_SPEC;
36
+ var url = urls.auth + "/v2/auth?s=" + flagSpecVersion;
36
37
  if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
37
38
  var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
38
39
  if (queryParams)
@@ -41,7 +42,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
41
42
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(constants_1.TOKEN));
42
43
  },
43
44
  fetchSplitChanges: function (since, noCache, till) {
44
- var url = urls.sdk + "/splitChanges?s=" + constants_1.FLAGS_SPEC + "&since=" + since + (filterQueryString || '') + (till ? '&till=' + till : '');
45
+ var url = urls.sdk + "/splitChanges?s=" + flagSpecVersion + "&since=" + since + (filterQueryString || '') + (till ? '&till=' + till : '');
45
46
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(constants_1.SPLITS))
46
47
  .catch(function (err) {
47
48
  if (err.statusCode === 414)
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getStorageHash = exports.KeyBuilder = exports.validatePrefix = void 0;
4
- var constants_1 = require("../utils/constants");
5
4
  var lang_1 = require("../utils/lang");
6
5
  var murmur3_1 = require("../utils/murmur3/murmur3");
7
6
  var everythingAtTheEnd = /[^.]+$/;
@@ -71,6 +70,6 @@ exports.KeyBuilder = KeyBuilder;
71
70
  * The hash is in hexadecimal format (8 characters max, 32 bits).
72
71
  */
73
72
  function getStorageHash(settings) {
74
- return (0, murmur3_1.hash)(settings.core.authorizationKey + "::" + settings.sync.__splitFiltersValidation.queryString + "::" + constants_1.FLAGS_SPEC).toString(16);
73
+ return (0, murmur3_1.hash)(settings.core.authorizationKey + "::" + settings.sync.__splitFiltersValidation.queryString + "::" + settings.sync.flagSpecVersion).toString(16);
75
74
  }
76
75
  exports.getStorageHash = getStorageHash;
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.SSEClient = void 0;
4
4
  var lang_1 = require("../../../utils/lang");
5
- var VERSION = '1.1';
5
+ var ABLY_API_VERSION = '1.1';
6
6
  var CONTROL_CHANNEL_REGEX = /^control_/;
7
7
  /**
8
8
  * Build metadata headers for SSE connection.
@@ -60,7 +60,7 @@ var SSEClient = /** @class */ (function () {
60
60
  var params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
61
61
  return encodeURIComponent(params + channel);
62
62
  }).join(',');
63
- var url = this.streamingUrl + "?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
63
+ var url = this.streamingUrl + "?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + ABLY_API_VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
64
64
  this.connection = new this.eventSource(
65
65
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
66
66
  // because native EventSource implementations for browser doesn't support headers.
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MY_SEGMENT = exports.SEGMENT = exports.TOKEN = exports.TELEMETRY = exports.EVENTS = exports.IMPRESSIONS_COUNT = exports.IMPRESSIONS = exports.SPLITS = exports.NONE_ENUM = exports.DEBUG_ENUM = exports.OPTIMIZED_ENUM = exports.CONSUMER_PARTIAL_ENUM = exports.CONSUMER_ENUM = exports.STANDALONE_ENUM = exports.DEDUPED = exports.DROPPED = exports.QUEUED = exports.NAMES_FN_LABEL = exports.SPLITS_FN_LABEL = exports.SPLIT_FN_LABEL = exports.TRACK_FN_LABEL = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SETS = exports.GET_TREATMENTS_WITH_CONFIG_BY_FLAG_SET = exports.GET_TREATMENTS_BY_FLAG_SETS = exports.GET_TREATMENTS_BY_FLAG_SET = exports.GET_TREATMENTS_WITH_CONFIG = exports.GET_TREATMENT_WITH_CONFIG = exports.GET_TREATMENTS = exports.GET_TREATMENT = exports.CONSENT_UNKNOWN = exports.CONSENT_DECLINED = exports.CONSENT_GRANTED = exports.STORAGE_PLUGGABLE = exports.STORAGE_REDIS = exports.STORAGE_LOCALSTORAGE = exports.STORAGE_MEMORY = exports.CONSUMER_PARTIAL_MODE = exports.CONSUMER_MODE = exports.PRODUCER_MODE = exports.STANDALONE_MODE = exports.LOCALHOST_MODE = exports.NONE = exports.OPTIMIZED = exports.DEBUG = exports.SPLIT_EVENT = exports.SPLIT_IMPRESSION = exports.NA = exports.UNKNOWN = exports.CONTROL_WITH_CONFIG = exports.CONTROL = void 0;
4
- exports.FLAGS_SPEC = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
4
+ exports.FLAG_SPEC_VERSION = exports.PAUSED = exports.ENABLED = exports.DISABLED = exports.NON_REQUESTED = exports.REQUESTED = exports.POLLING = exports.STREAMING = exports.AUTH_REJECTION = exports.SYNC_MODE_UPDATE = exports.ABLY_ERROR = exports.TOKEN_REFRESH = exports.SSE_CONNECTION_ERROR = exports.STREAMING_STATUS = exports.OCCUPANCY_SEC = exports.OCCUPANCY_PRI = exports.CONNECTION_ESTABLISHED = exports.TRACK = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSETS = exports.TREATMENTS_WITH_CONFIG_BY_FLAGSET = exports.TREATMENTS_BY_FLAGSETS = exports.TREATMENTS_BY_FLAGSET = exports.TREATMENTS_WITH_CONFIG = exports.TREATMENT_WITH_CONFIG = exports.TREATMENTS = exports.TREATMENT = void 0;
5
5
  // Special treatments
6
6
  exports.CONTROL = 'control';
7
7
  exports.CONTROL_WITH_CONFIG = {
@@ -90,4 +90,4 @@ exports.NON_REQUESTED = 1;
90
90
  exports.DISABLED = 0;
91
91
  exports.ENABLED = 1;
92
92
  exports.PAUSED = 2;
93
- exports.FLAGS_SPEC = '1.1';
93
+ exports.FLAG_SPEC_VERSION = '1.1';
@@ -74,7 +74,8 @@ exports.base = {
74
74
  // impressions collection mode
75
75
  impressionsMode: constants_1.OPTIMIZED,
76
76
  localhostMode: undefined,
77
- enabled: true
77
+ enabled: true,
78
+ flagSpecVersion: constants_1.FLAG_SPEC_VERSION
78
79
  },
79
80
  // Logger
80
81
  log: undefined
@@ -90,7 +91,7 @@ function fromSecondsToMillis(n) {
90
91
  * @param validationParams defaults and fields validators used to validate and creates a settings object from a given config
91
92
  */
92
93
  function settingsValidation(config, validationParams) {
93
- var defaults = validationParams.defaults, runtime = validationParams.runtime, storage = validationParams.storage, integrations = validationParams.integrations, logger = validationParams.logger, localhost = validationParams.localhost, consent = validationParams.consent;
94
+ var defaults = validationParams.defaults, runtime = validationParams.runtime, storage = validationParams.storage, integrations = validationParams.integrations, logger = validationParams.logger, localhost = validationParams.localhost, consent = validationParams.consent, flagSpec = validationParams.flagSpec;
94
95
  // creates a settings object merging base, defaults and config objects.
95
96
  var withDefaults = (0, lang_1.merge)({}, exports.base, defaults, config);
96
97
  // ensure a valid logger.
@@ -98,7 +99,8 @@ function settingsValidation(config, validationParams) {
98
99
  var log = logger(withDefaults); // @ts-ignore, modify readonly prop
99
100
  withDefaults.log = log;
100
101
  // ensure a valid impressionsMode
101
- withDefaults.sync.impressionsMode = (0, impressionsMode_1.validImpressionsMode)(log, withDefaults.sync.impressionsMode);
102
+ var sync = withDefaults.sync;
103
+ sync.impressionsMode = (0, impressionsMode_1.validImpressionsMode)(log, sync.impressionsMode);
102
104
  function validateMinValue(paramName, actualValue, minValue) {
103
105
  if (actualValue >= minValue)
104
106
  return actualValue;
@@ -114,7 +116,7 @@ function settingsValidation(config, validationParams) {
114
116
  scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
115
117
  scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
116
118
  // Default impressionsRefreshRate for DEBUG mode is 60 secs
117
- if ((0, lang_1.get)(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === constants_1.DEBUG)
119
+ if ((0, lang_1.get)(config, 'scheduler.impressionsRefreshRate') === undefined && sync.impressionsMode === constants_1.DEBUG)
118
120
  scheduler.impressionsRefreshRate = 60;
119
121
  scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
120
122
  // Log deprecation for old telemetry param
@@ -166,22 +168,23 @@ function settingsValidation(config, validationParams) {
166
168
  if (integrations)
167
169
  withDefaults.integrations = integrations(withDefaults);
168
170
  if (localhost)
169
- withDefaults.sync.localhostMode = localhost(withDefaults);
171
+ sync.localhostMode = localhost(withDefaults);
170
172
  // validate push options
171
173
  if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop
172
174
  withDefaults.streamingEnabled = true;
173
175
  // Backoff bases.
174
- // We are not checking if bases are positive numbers. Thus, we might be reauthenticating immediately (`setTimeout` with NaN or negative number)
176
+ // We are not checking if bases are positive numbers. Thus, we might be re-authenticating immediately (`setTimeout` with NaN or negative number)
175
177
  scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
176
178
  }
177
179
  // validate sync enabled
178
- if (withDefaults.sync.enabled !== false) { // @ts-ignore, modify readonly prop
179
- withDefaults.sync.enabled = true;
180
+ if (sync.enabled !== false) {
181
+ sync.enabled = true;
180
182
  }
181
183
  // validate the `splitFilters` settings and parse splits query
182
- var splitFiltersValidation = (0, splitFilters_1.validateSplitFilters)(log, withDefaults.sync.splitFilters, withDefaults.mode);
183
- withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
184
- withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
184
+ var splitFiltersValidation = (0, splitFilters_1.validateSplitFilters)(log, sync.splitFilters, withDefaults.mode);
185
+ sync.splitFilters = splitFiltersValidation.validFilters;
186
+ sync.__splitFiltersValidation = splitFiltersValidation;
187
+ sync.flagSpecVersion = flagSpec ? flagSpec(withDefaults) : constants_1.FLAG_SPEC_VERSION;
185
188
  // ensure a valid user consent value
186
189
  // @ts-ignore, modify readonly prop
187
190
  withDefaults.userConsent = consent(withDefaults);
@@ -1,6 +1,6 @@
1
1
  import { splitHttpClientFactory } from './splitHttpClient';
2
2
  import { objectAssign } from '../utils/lang/objectAssign';
3
- import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT, FLAGS_SPEC } from '../utils/constants';
3
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
4
4
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
5
5
  var noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
6
6
  function userKeyToQueryParam(userKey) {
@@ -17,6 +17,7 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
17
17
  var urls = settings.urls;
18
18
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
19
19
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
20
+ var flagSpecVersion = settings.sync.flagSpecVersion;
20
21
  var splitHttpClient = splitHttpClientFactory(settings, platform.getFetch);
21
22
  return {
22
23
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
@@ -29,7 +30,7 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
29
30
  return splitHttpClient(url).then(function () { return true; }).catch(function () { return false; });
30
31
  },
31
32
  fetchAuth: function (userMatchingKeys) {
32
- var url = urls.auth + "/v2/auth?s=" + FLAGS_SPEC;
33
+ var url = urls.auth + "/v2/auth?s=" + flagSpecVersion;
33
34
  if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
34
35
  var queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
35
36
  if (queryParams)
@@ -38,7 +39,7 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
38
39
  return splitHttpClient(url, undefined, telemetryTracker.trackHttp(TOKEN));
39
40
  },
40
41
  fetchSplitChanges: function (since, noCache, till) {
41
- var url = urls.sdk + "/splitChanges?s=" + FLAGS_SPEC + "&since=" + since + (filterQueryString || '') + (till ? '&till=' + till : '');
42
+ var url = urls.sdk + "/splitChanges?s=" + flagSpecVersion + "&since=" + since + (filterQueryString || '') + (till ? '&till=' + till : '');
42
43
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
43
44
  .catch(function (err) {
44
45
  if (err.statusCode === 414)
@@ -1,4 +1,3 @@
1
- import { FLAGS_SPEC } from '../utils/constants';
2
1
  import { startsWith } from '../utils/lang';
3
2
  import { hash } from '../utils/murmur3/murmur3';
4
3
  var everythingAtTheEnd = /[^.]+$/;
@@ -67,5 +66,5 @@ export { KeyBuilder };
67
66
  * The hash is in hexadecimal format (8 characters max, 32 bits).
68
67
  */
69
68
  export function getStorageHash(settings) {
70
- return hash(settings.core.authorizationKey + "::" + settings.sync.__splitFiltersValidation.queryString + "::" + FLAGS_SPEC).toString(16);
69
+ return hash(settings.core.authorizationKey + "::" + settings.sync.__splitFiltersValidation.queryString + "::" + settings.sync.flagSpecVersion).toString(16);
71
70
  }
@@ -1,5 +1,5 @@
1
1
  import { isString } from '../../../utils/lang';
2
- var VERSION = '1.1';
2
+ var ABLY_API_VERSION = '1.1';
3
3
  var CONTROL_CHANNEL_REGEX = /^control_/;
4
4
  /**
5
5
  * Build metadata headers for SSE connection.
@@ -57,7 +57,7 @@ var SSEClient = /** @class */ (function () {
57
57
  var params = CONTROL_CHANNEL_REGEX.test(channel) ? '[?occupancy=metrics.publishers]' : '';
58
58
  return encodeURIComponent(params + channel);
59
59
  }).join(',');
60
- var url = this.streamingUrl + "?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
60
+ var url = this.streamingUrl + "?channels=" + channelsQueryParam + "&accessToken=" + authToken.token + "&v=" + ABLY_API_VERSION + "&heartbeats=true"; // same results using `&heartbeats=false`
61
61
  this.connection = new this.eventSource(
62
62
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
63
63
  // because native EventSource implementations for browser doesn't support headers.
@@ -86,4 +86,4 @@ export var NON_REQUESTED = 1;
86
86
  export var DISABLED = 0;
87
87
  export var ENABLED = 1;
88
88
  export var PAUSED = 2;
89
- export var FLAGS_SPEC = '1.1';
89
+ export var FLAG_SPEC_VERSION = '1.1';
@@ -1,7 +1,7 @@
1
1
  import { merge, get } from '../lang';
2
2
  import { validateMode } from './mode';
3
3
  import { validateSplitFilters } from './splitFilters';
4
- import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
4
+ import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG, FLAG_SPEC_VERSION } from '../constants';
5
5
  import { validImpressionsMode } from './impressionsMode';
6
6
  import { validateKey } from '../inputValidation/key';
7
7
  import { validateTrafficType } from '../inputValidation/trafficType';
@@ -71,7 +71,8 @@ export var base = {
71
71
  // impressions collection mode
72
72
  impressionsMode: OPTIMIZED,
73
73
  localhostMode: undefined,
74
- enabled: true
74
+ enabled: true,
75
+ flagSpecVersion: FLAG_SPEC_VERSION
75
76
  },
76
77
  // Logger
77
78
  log: undefined
@@ -87,7 +88,7 @@ function fromSecondsToMillis(n) {
87
88
  * @param validationParams defaults and fields validators used to validate and creates a settings object from a given config
88
89
  */
89
90
  export function settingsValidation(config, validationParams) {
90
- var defaults = validationParams.defaults, runtime = validationParams.runtime, storage = validationParams.storage, integrations = validationParams.integrations, logger = validationParams.logger, localhost = validationParams.localhost, consent = validationParams.consent;
91
+ var defaults = validationParams.defaults, runtime = validationParams.runtime, storage = validationParams.storage, integrations = validationParams.integrations, logger = validationParams.logger, localhost = validationParams.localhost, consent = validationParams.consent, flagSpec = validationParams.flagSpec;
91
92
  // creates a settings object merging base, defaults and config objects.
92
93
  var withDefaults = merge({}, base, defaults, config);
93
94
  // ensure a valid logger.
@@ -95,7 +96,8 @@ export function settingsValidation(config, validationParams) {
95
96
  var log = logger(withDefaults); // @ts-ignore, modify readonly prop
96
97
  withDefaults.log = log;
97
98
  // ensure a valid impressionsMode
98
- withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
99
+ var sync = withDefaults.sync;
100
+ sync.impressionsMode = validImpressionsMode(log, sync.impressionsMode);
99
101
  function validateMinValue(paramName, actualValue, minValue) {
100
102
  if (actualValue >= minValue)
101
103
  return actualValue;
@@ -111,7 +113,7 @@ export function settingsValidation(config, validationParams) {
111
113
  scheduler.eventsPushRate = fromSecondsToMillis(scheduler.eventsPushRate);
112
114
  scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
113
115
  // Default impressionsRefreshRate for DEBUG mode is 60 secs
114
- if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG)
116
+ if (get(config, 'scheduler.impressionsRefreshRate') === undefined && sync.impressionsMode === DEBUG)
115
117
  scheduler.impressionsRefreshRate = 60;
116
118
  scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
117
119
  // Log deprecation for old telemetry param
@@ -163,22 +165,23 @@ export function settingsValidation(config, validationParams) {
163
165
  if (integrations)
164
166
  withDefaults.integrations = integrations(withDefaults);
165
167
  if (localhost)
166
- withDefaults.sync.localhostMode = localhost(withDefaults);
168
+ sync.localhostMode = localhost(withDefaults);
167
169
  // validate push options
168
170
  if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop
169
171
  withDefaults.streamingEnabled = true;
170
172
  // Backoff bases.
171
- // We are not checking if bases are positive numbers. Thus, we might be reauthenticating immediately (`setTimeout` with NaN or negative number)
173
+ // We are not checking if bases are positive numbers. Thus, we might be re-authenticating immediately (`setTimeout` with NaN or negative number)
172
174
  scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
173
175
  }
174
176
  // validate sync enabled
175
- if (withDefaults.sync.enabled !== false) { // @ts-ignore, modify readonly prop
176
- withDefaults.sync.enabled = true;
177
+ if (sync.enabled !== false) {
178
+ sync.enabled = true;
177
179
  }
178
180
  // validate the `splitFilters` settings and parse splits query
179
- var splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
180
- withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
181
- withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
181
+ var splitFiltersValidation = validateSplitFilters(log, sync.splitFilters, withDefaults.mode);
182
+ sync.splitFilters = splitFiltersValidation.validFilters;
183
+ sync.__splitFiltersValidation = splitFiltersValidation;
184
+ sync.flagSpecVersion = flagSpec ? flagSpec(withDefaults) : FLAG_SPEC_VERSION;
182
185
  // ensure a valid user consent value
183
186
  // @ts-ignore, modify readonly prop
184
187
  withDefaults.userConsent = consent(withDefaults);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.14.0",
3
+ "version": "1.14.1-rc.0",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -4,7 +4,7 @@ import { splitHttpClientFactory } from './splitHttpClient';
4
4
  import { ISplitApi } from './types';
5
5
  import { objectAssign } from '../utils/lang/objectAssign';
6
6
  import { ITelemetryTracker } from '../trackers/types';
7
- import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT, FLAGS_SPEC } from '../utils/constants';
7
+ import { SPLITS, IMPRESSIONS, IMPRESSIONS_COUNT, EVENTS, TELEMETRY, TOKEN, SEGMENT, MY_SEGMENT } from '../utils/constants';
8
8
  import { ERROR_TOO_MANY_SETS } from '../logger/constants';
9
9
 
10
10
  const noCacheHeaderOptions = { headers: { 'Cache-Control': 'no-cache' } };
@@ -29,6 +29,7 @@ export function splitApiFactory(
29
29
  const urls = settings.urls;
30
30
  const filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
31
31
  const SplitSDKImpressionsMode = settings.sync.impressionsMode;
32
+ const flagSpecVersion = settings.sync.flagSpecVersion;
32
33
  const splitHttpClient = splitHttpClientFactory(settings, platform.getFetch);
33
34
 
34
35
  return {
@@ -44,7 +45,7 @@ export function splitApiFactory(
44
45
  },
45
46
 
46
47
  fetchAuth(userMatchingKeys?: string[]) {
47
- let url = `${urls.auth}/v2/auth?s=${FLAGS_SPEC}`;
48
+ let url = `${urls.auth}/v2/auth?s=${flagSpecVersion}`;
48
49
  if (userMatchingKeys) { // `userMatchingKeys` is undefined in server-side
49
50
  const queryParams = userMatchingKeys.map(userKeyToQueryParam).join('&');
50
51
  if (queryParams) url += '&' + queryParams;
@@ -53,7 +54,7 @@ export function splitApiFactory(
53
54
  },
54
55
 
55
56
  fetchSplitChanges(since: number, noCache?: boolean, till?: number) {
56
- const url = `${urls.sdk}/splitChanges?s=${FLAGS_SPEC}&since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
57
+ const url = `${urls.sdk}/splitChanges?s=${flagSpecVersion}&since=${since}${filterQueryString || ''}${till ? '&till=' + till : ''}`;
57
58
  return splitHttpClient(url, noCache ? noCacheHeaderOptions : undefined, telemetryTracker.trackHttp(SPLITS))
58
59
  .catch((err) => {
59
60
  if (err.statusCode === 414) settings.log.error(ERROR_TOO_MANY_SETS);
@@ -1,5 +1,4 @@
1
1
  import { ISettings } from '../types';
2
- import { FLAGS_SPEC } from '../utils/constants';
3
2
  import { startsWith } from '../utils/lang';
4
3
  import { hash } from '../utils/murmur3/murmur3';
5
4
 
@@ -86,5 +85,5 @@ export class KeyBuilder {
86
85
  * The hash is in hexadecimal format (8 characters max, 32 bits).
87
86
  */
88
87
  export function getStorageHash(settings: ISettings) {
89
- return hash(`${settings.core.authorizationKey}::${settings.sync.__splitFiltersValidation.queryString}::${FLAGS_SPEC}`).toString(16);
88
+ return hash(`${settings.core.authorizationKey}::${settings.sync.__splitFiltersValidation.queryString}::${settings.sync.flagSpecVersion}`).toString(16);
90
89
  }
@@ -4,7 +4,7 @@ import { isString } from '../../../utils/lang';
4
4
  import { IAuthTokenPushEnabled } from '../AuthClient/types';
5
5
  import { ISSEClient, ISseEventHandler } from './types';
6
6
 
7
- const VERSION = '1.1';
7
+ const ABLY_API_VERSION = '1.1';
8
8
 
9
9
  const CONTROL_CHANNEL_REGEX = /^control_/;
10
10
 
@@ -78,7 +78,7 @@ export class SSEClient implements ISSEClient {
78
78
  return encodeURIComponent(params + channel);
79
79
  }
80
80
  ).join(',');
81
- const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
81
+ const url = `${this.streamingUrl}?channels=${channelsQueryParam}&accessToken=${authToken.token}&v=${ABLY_API_VERSION}&heartbeats=true`; // same results using `&heartbeats=false`
82
82
 
83
83
  this.connection = new this.eventSource!(
84
84
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
package/src/types.ts CHANGED
@@ -118,7 +118,8 @@ export interface ISettings {
118
118
  impressionsMode: SplitIO.ImpressionsMode,
119
119
  __splitFiltersValidation: ISplitFiltersValidation,
120
120
  localhostMode?: SplitIO.LocalhostFactory,
121
- enabled: boolean
121
+ enabled: boolean,
122
+ flagSpecVersion: string
122
123
  },
123
124
  readonly runtime: {
124
125
  ip: string | false
@@ -105,4 +105,4 @@ export const DISABLED = 0;
105
105
  export const ENABLED = 1;
106
106
  export const PAUSED = 2;
107
107
 
108
- export const FLAGS_SPEC = '1.1';
108
+ export const FLAG_SPEC_VERSION = '1.1';
@@ -1,7 +1,7 @@
1
1
  import { merge, get } from '../lang';
2
2
  import { validateMode } from './mode';
3
3
  import { validateSplitFilters } from './splitFilters';
4
- import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG } from '../constants';
4
+ import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE, DEBUG, FLAG_SPEC_VERSION } from '../constants';
5
5
  import { validImpressionsMode } from './impressionsMode';
6
6
  import { ISettingsValidationParams } from './types';
7
7
  import { ISettings } from '../../types';
@@ -84,7 +84,8 @@ export const base = {
84
84
  // impressions collection mode
85
85
  impressionsMode: OPTIMIZED,
86
86
  localhostMode: undefined,
87
- enabled: true
87
+ enabled: true,
88
+ flagSpecVersion: FLAG_SPEC_VERSION
88
89
  },
89
90
 
90
91
  // Logger
@@ -104,7 +105,7 @@ function fromSecondsToMillis(n: number) {
104
105
  */
105
106
  export function settingsValidation(config: unknown, validationParams: ISettingsValidationParams) {
106
107
 
107
- const { defaults, runtime, storage, integrations, logger, localhost, consent } = validationParams;
108
+ const { defaults, runtime, storage, integrations, logger, localhost, consent, flagSpec } = validationParams;
108
109
 
109
110
  // creates a settings object merging base, defaults and config objects.
110
111
  const withDefaults = merge({}, base, defaults, config) as ISettings;
@@ -115,7 +116,8 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
115
116
  withDefaults.log = log;
116
117
 
117
118
  // ensure a valid impressionsMode
118
- withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
119
+ const sync = withDefaults.sync;
120
+ sync.impressionsMode = validImpressionsMode(log, sync.impressionsMode);
119
121
 
120
122
  function validateMinValue(paramName: string, actualValue: number, minValue: number) {
121
123
  if (actualValue >= minValue) return actualValue;
@@ -133,7 +135,7 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
133
135
  scheduler.telemetryRefreshRate = fromSecondsToMillis(validateMinValue('telemetryRefreshRate', scheduler.telemetryRefreshRate, 60));
134
136
 
135
137
  // Default impressionsRefreshRate for DEBUG mode is 60 secs
136
- if (get(config, 'scheduler.impressionsRefreshRate') === undefined && withDefaults.sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
138
+ if (get(config, 'scheduler.impressionsRefreshRate') === undefined && sync.impressionsMode === DEBUG) scheduler.impressionsRefreshRate = 60;
137
139
  scheduler.impressionsRefreshRate = fromSecondsToMillis(scheduler.impressionsRefreshRate);
138
140
 
139
141
  // Log deprecation for old telemetry param
@@ -186,25 +188,26 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
186
188
  // @ts-ignore, modify readonly prop
187
189
  if (integrations) withDefaults.integrations = integrations(withDefaults);
188
190
 
189
- if (localhost) withDefaults.sync.localhostMode = localhost(withDefaults);
191
+ if (localhost) sync.localhostMode = localhost(withDefaults);
190
192
 
191
193
  // validate push options
192
194
  if (withDefaults.streamingEnabled !== false) { // @ts-ignore, modify readonly prop
193
195
  withDefaults.streamingEnabled = true;
194
196
  // Backoff bases.
195
- // We are not checking if bases are positive numbers. Thus, we might be reauthenticating immediately (`setTimeout` with NaN or negative number)
197
+ // We are not checking if bases are positive numbers. Thus, we might be re-authenticating immediately (`setTimeout` with NaN or negative number)
196
198
  scheduler.pushRetryBackoffBase = fromSecondsToMillis(scheduler.pushRetryBackoffBase);
197
199
  }
198
200
 
199
201
  // validate sync enabled
200
- if (withDefaults.sync.enabled !== false) { // @ts-ignore, modify readonly prop
201
- withDefaults.sync.enabled = true;
202
+ if (sync.enabled !== false) {
203
+ sync.enabled = true;
202
204
  }
203
205
 
204
206
  // validate the `splitFilters` settings and parse splits query
205
- const splitFiltersValidation = validateSplitFilters(log, withDefaults.sync.splitFilters, withDefaults.mode);
206
- withDefaults.sync.splitFilters = splitFiltersValidation.validFilters;
207
- withDefaults.sync.__splitFiltersValidation = splitFiltersValidation;
207
+ const splitFiltersValidation = validateSplitFilters(log, sync.splitFilters, withDefaults.mode);
208
+ sync.splitFilters = splitFiltersValidation.validFilters;
209
+ sync.__splitFiltersValidation = splitFiltersValidation;
210
+ sync.flagSpecVersion = flagSpec ? flagSpec(withDefaults) : FLAG_SPEC_VERSION;
208
211
 
209
212
  // ensure a valid user consent value
210
213
  // @ts-ignore, modify readonly prop
@@ -26,4 +26,6 @@ export interface ISettingsValidationParams {
26
26
  localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'],
27
27
  /** User consent validator (`settings.userConsent`) */
28
28
  consent: (settings: ISettings) => ISettings['userConsent'],
29
+ /** Flag spec version validation. Configurable by the JS Synchronizer but not by the SDKs */
30
+ flagSpec?: (settings: ISettings) => ISettings['sync']['flagSpecVersion']
29
31
  }
package/types/types.d.ts CHANGED
@@ -113,6 +113,7 @@ export interface ISettings {
113
113
  __splitFiltersValidation: ISplitFiltersValidation;
114
114
  localhostMode?: SplitIO.LocalhostFactory;
115
115
  enabled: boolean;
116
+ flagSpecVersion: string;
116
117
  };
117
118
  readonly runtime: {
118
119
  ip: string | false;
@@ -78,4 +78,4 @@ export declare const NON_REQUESTED = 1;
78
78
  export declare const DISABLED = 0;
79
79
  export declare const ENABLED = 1;
80
80
  export declare const PAUSED = 2;
81
- export declare const FLAGS_SPEC = "1.1";
81
+ export declare const FLAG_SPEC_VERSION = "1.1";
@@ -38,6 +38,7 @@ export declare const base: {
38
38
  impressionsMode: string;
39
39
  localhostMode: undefined;
40
40
  enabled: boolean;
41
+ flagSpecVersion: string;
41
42
  };
42
43
  log: undefined;
43
44
  };
@@ -29,4 +29,6 @@ export interface ISettingsValidationParams {
29
29
  localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'];
30
30
  /** User consent validator (`settings.userConsent`) */
31
31
  consent: (settings: ISettings) => ISettings['userConsent'];
32
+ /** Flag spec version validation. Configurable by the JS Synchronizer but not by the SDKs */
33
+ flagSpec?: (settings: ISettings) => ISettings['sync']['flagSpecVersion'];
32
34
  }