@splitsoftware/splitio-commons 1.15.1-rc.0 → 1.15.1-rc.2

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,4 +1,8 @@
1
+ 1.16.0 (June XX, 2024)
2
+ - Added the `getOptions` method to the `IPlatform` interface to allow the SDK to pass request options to the `fetch` method and `EventSource` constructor when fetching data from the Split servers. The method is optional and, if provided, it is called twice: first for the `fetch` options and then for the `EventSource` options.
3
+
1
4
  1.15.1 (May 28, 2024)
5
+ - Updated the Redis storage to lazily import the `ioredis` dependency when the storage is created. This prevents errors when the SDK is imported or bundled in a .mjs file, as `ioredis` is a CommonJS module.
2
6
  - Bugfixing - Restored some input validation error logs that were removed in version 1.12.0. The logs inform the user when the `getTreatment(s)` methods are called with an invalid value as feature flag name or flag set name.
3
7
 
4
8
  1.15.0 (May 13, 2024)
@@ -165,6 +165,7 @@ function clientFactory(params) {
165
165
  getTreatmentsByFlagSet: getTreatmentsByFlagSet,
166
166
  getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
167
167
  track: track,
168
+ isClientSide: false
168
169
  };
169
170
  }
170
171
  exports.clientFactory = clientFactory;
@@ -21,7 +21,7 @@ function splitApiFactory(settings, platform, telemetryTracker) {
21
21
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
22
22
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
23
23
  var flagSpecVersion = settings.sync.flagSpecVersion;
24
- var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform.getFetch);
24
+ var splitHttpClient = (0, splitHttpClient_1.splitHttpClientFactory)(settings, platform);
25
25
  return {
26
26
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
27
27
  getSdkAPIHealthCheck: function () {
@@ -8,11 +8,13 @@ var messageNoFetch = 'Global fetch API is not available.';
8
8
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
9
9
  *
10
10
  * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
11
- * @param getFetch retrieves the Fetch API for HTTP requests
11
+ * @param platform object containing environment-specific dependencies
12
12
  */
13
- function splitHttpClientFactory(settings, getFetch) {
14
- var log = settings.log, authorizationKey = settings.core.authorizationKey, version = settings.version, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname;
15
- var fetch = getFetch && getFetch();
13
+ function splitHttpClientFactory(settings, _a) {
14
+ var getOptions = _a.getOptions, getFetch = _a.getFetch;
15
+ var log = settings.log, authorizationKey = settings.core.authorizationKey, version = settings.version, _b = settings.runtime, ip = _b.ip, hostname = _b.hostname;
16
+ var options = getOptions && getOptions(settings);
17
+ var fetch = getFetch && getFetch(settings);
16
18
  // if fetch is not available, log Error
17
19
  if (!fetch)
18
20
  log.error(constants_1.ERROR_CLIENT_CANNOT_GET_READY, [messageNoFetch]);
@@ -30,11 +32,11 @@ function splitHttpClientFactory(settings, getFetch) {
30
32
  if (reqOpts === void 0) { reqOpts = {}; }
31
33
  if (latencyTracker === void 0) { latencyTracker = function () { }; }
32
34
  if (logErrorsAsInfo === void 0) { logErrorsAsInfo = false; }
33
- var request = {
35
+ var request = (0, objectAssign_1.objectAssign)({
34
36
  headers: reqOpts.headers ? (0, objectAssign_1.objectAssign)({}, headers, reqOpts.headers) : headers,
35
37
  method: reqOpts.method || 'GET',
36
38
  body: reqOpts.body
37
- };
39
+ }, options);
38
40
  // using `fetch(url, options)` signature to work with unfetch, a lightweight ponyfill of fetch API.
39
41
  return fetch ? fetch(url, request)
40
42
  // https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.InRedisStorage = void 0;
4
- var RedisAdapter_1 = require("./RedisAdapter");
5
4
  var KeyBuilder_1 = require("../KeyBuilder");
6
5
  var KeyBuilderSS_1 = require("../KeyBuilderSS");
7
6
  var SplitsCacheInRedis_1 = require("./SplitsCacheInRedis");
@@ -19,12 +18,15 @@ var utils_1 = require("../utils");
19
18
  */
20
19
  function InRedisStorage(options) {
21
20
  if (options === void 0) { options = {}; }
21
+ // Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
22
+ // Redis storage is not supported with .mjs files.
23
+ var RD = require('./RedisAdapter').RedisAdapter;
22
24
  var prefix = (0, KeyBuilder_1.validatePrefix)(options.prefix);
23
25
  function InRedisStorageFactory(params) {
24
26
  var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, impressionsMode = _a.sync.impressionsMode;
25
27
  var metadata = (0, utils_1.metadataBuilder)(settings);
26
28
  var keys = new KeyBuilderSS_1.KeyBuilderSS(prefix, metadata);
27
- var redisClient = new RedisAdapter_1.RedisAdapter(log, options.options || {});
29
+ var redisClient = new RD(log, options.options || {});
28
30
  var telemetry = new TelemetryCacheInRedis_1.TelemetryCacheInRedis(log, keys, redisClient);
29
31
  var impressionCountsCache = impressionsMode !== constants_1.DEBUG ? new ImpressionCountsCacheInRedis_1.ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
30
32
  var uniqueKeysCache = impressionsMode === constants_1.NONE ? new UniqueKeysCacheInRedis_1.UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
@@ -2,6 +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 objectAssign_1 = require("../../../utils/lang/objectAssign");
5
6
  var ABLY_API_VERSION = '1.1';
6
7
  var CONTROL_CHANNEL_REGEX = /^control_/;
7
8
  /**
@@ -32,18 +33,20 @@ var SSEClient = /** @class */ (function () {
32
33
  *
33
34
  * @param settings Validated settings.
34
35
  * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
35
- * @param getEventSource Function to get the EventSource constructor.
36
- * @throws 'EventSource API is not available. ' if EventSource is not available.
36
+ * @param platform object containing environment-specific dependencies
37
+ * @throws 'EventSource API is not available.' if EventSource is not available.
37
38
  */
38
- function SSEClient(settings, useHeaders, getEventSource) {
39
- this.eventSource = getEventSource && getEventSource();
39
+ function SSEClient(settings, useHeaders, _a) {
40
+ var getEventSource = _a.getEventSource, getOptions = _a.getOptions;
41
+ this.eventSource = getEventSource && getEventSource(settings);
40
42
  // if eventSource is not available, throw an exception
41
43
  if (!this.eventSource)
42
- throw new Error('EventSource API is not available. ');
44
+ throw new Error('EventSource API is not available.');
43
45
  this.streamingUrl = settings.urls.streaming + '/sse';
44
46
  // @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
45
47
  this.useHeaders = useHeaders;
46
48
  this.headers = buildSSEHeaders(settings);
49
+ this.options = getOptions && getOptions(settings);
47
50
  }
48
51
  SSEClient.prototype.setEventHandler = function (handler) {
49
52
  this.handler = handler;
@@ -65,8 +68,8 @@ var SSEClient = /** @class */ (function () {
65
68
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
66
69
  // because native EventSource implementations for browser doesn't support headers.
67
70
  this.useHeaders ? url : url + ("&SplitSDKVersion=" + this.headers.SplitSDKVersion + "&SplitSDKClientKey=" + this.headers.SplitSDKClientKey),
68
- // @ts-ignore. For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
69
- this.useHeaders ? { headers: this.headers } : undefined);
71
+ // For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
72
+ (0, objectAssign_1.objectAssign)(this.useHeaders ? { headers: this.headers } : {}, this.options));
70
73
  if (this.handler) { // no need to check if SSEClient is used only by PushManager
71
74
  this.connection.addEventListener('open', this.handler.handleOpen);
72
75
  this.connection.addEventListener('message', this.handler.handleMessage);
@@ -32,7 +32,7 @@ function pushManagerFactory(params, pollingManager) {
32
32
  var sseClient;
33
33
  try {
34
34
  // `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native).
35
- sseClient = new SSEClient_1.SSEClient(settings, userKey ? false : true, platform.getEventSource);
35
+ sseClient = new SSEClient_1.SSEClient(settings, userKey ? false : true, platform);
36
36
  }
37
37
  catch (e) {
38
38
  log.warn(constants_2.STREAMING_FALLBACK, [e]);
@@ -162,5 +162,6 @@ export function clientFactory(params) {
162
162
  getTreatmentsByFlagSet: getTreatmentsByFlagSet,
163
163
  getTreatmentsWithConfigByFlagSet: getTreatmentsWithConfigByFlagSet,
164
164
  track: track,
165
+ isClientSide: false
165
166
  };
166
167
  }
@@ -18,7 +18,7 @@ export function splitApiFactory(settings, platform, telemetryTracker) {
18
18
  var filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
19
19
  var SplitSDKImpressionsMode = settings.sync.impressionsMode;
20
20
  var flagSpecVersion = settings.sync.flagSpecVersion;
21
- var splitHttpClient = splitHttpClientFactory(settings, platform.getFetch);
21
+ var splitHttpClient = splitHttpClientFactory(settings, platform);
22
22
  return {
23
23
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
24
24
  getSdkAPIHealthCheck: function () {
@@ -5,11 +5,13 @@ var messageNoFetch = 'Global fetch API is not available.';
5
5
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
6
6
  *
7
7
  * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
8
- * @param getFetch retrieves the Fetch API for HTTP requests
8
+ * @param platform object containing environment-specific dependencies
9
9
  */
10
- export function splitHttpClientFactory(settings, getFetch) {
11
- var log = settings.log, authorizationKey = settings.core.authorizationKey, version = settings.version, _a = settings.runtime, ip = _a.ip, hostname = _a.hostname;
12
- var fetch = getFetch && getFetch();
10
+ export function splitHttpClientFactory(settings, _a) {
11
+ var getOptions = _a.getOptions, getFetch = _a.getFetch;
12
+ var log = settings.log, authorizationKey = settings.core.authorizationKey, version = settings.version, _b = settings.runtime, ip = _b.ip, hostname = _b.hostname;
13
+ var options = getOptions && getOptions(settings);
14
+ var fetch = getFetch && getFetch(settings);
13
15
  // if fetch is not available, log Error
14
16
  if (!fetch)
15
17
  log.error(ERROR_CLIENT_CANNOT_GET_READY, [messageNoFetch]);
@@ -27,11 +29,11 @@ export function splitHttpClientFactory(settings, getFetch) {
27
29
  if (reqOpts === void 0) { reqOpts = {}; }
28
30
  if (latencyTracker === void 0) { latencyTracker = function () { }; }
29
31
  if (logErrorsAsInfo === void 0) { logErrorsAsInfo = false; }
30
- var request = {
32
+ var request = objectAssign({
31
33
  headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers,
32
34
  method: reqOpts.method || 'GET',
33
35
  body: reqOpts.body
34
- };
36
+ }, options);
35
37
  // using `fetch(url, options)` signature to work with unfetch, a lightweight ponyfill of fetch API.
36
38
  return fetch ? fetch(url, request)
37
39
  // https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Checking_that_the_fetch_was_successful
@@ -1,4 +1,3 @@
1
- import { RedisAdapter } from './RedisAdapter';
2
1
  import { validatePrefix } from '../KeyBuilder';
3
2
  import { KeyBuilderSS } from '../KeyBuilderSS';
4
3
  import { SplitsCacheInRedis } from './SplitsCacheInRedis';
@@ -16,12 +15,15 @@ import { metadataBuilder } from '../utils';
16
15
  */
17
16
  export function InRedisStorage(options) {
18
17
  if (options === void 0) { options = {}; }
18
+ // Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
19
+ // Redis storage is not supported with .mjs files.
20
+ var RD = require('./RedisAdapter').RedisAdapter;
19
21
  var prefix = validatePrefix(options.prefix);
20
22
  function InRedisStorageFactory(params) {
21
23
  var onReadyCb = params.onReadyCb, settings = params.settings, _a = params.settings, log = _a.log, impressionsMode = _a.sync.impressionsMode;
22
24
  var metadata = metadataBuilder(settings);
23
25
  var keys = new KeyBuilderSS(prefix, metadata);
24
- var redisClient = new RedisAdapter(log, options.options || {});
26
+ var redisClient = new RD(log, options.options || {});
25
27
  var telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
26
28
  var impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
27
29
  var uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
@@ -1,4 +1,5 @@
1
1
  import { isString } from '../../../utils/lang';
2
+ import { objectAssign } from '../../../utils/lang/objectAssign';
2
3
  var ABLY_API_VERSION = '1.1';
3
4
  var CONTROL_CHANNEL_REGEX = /^control_/;
4
5
  /**
@@ -29,18 +30,20 @@ var SSEClient = /** @class */ (function () {
29
30
  *
30
31
  * @param settings Validated settings.
31
32
  * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
32
- * @param getEventSource Function to get the EventSource constructor.
33
- * @throws 'EventSource API is not available. ' if EventSource is not available.
33
+ * @param platform object containing environment-specific dependencies
34
+ * @throws 'EventSource API is not available.' if EventSource is not available.
34
35
  */
35
- function SSEClient(settings, useHeaders, getEventSource) {
36
- this.eventSource = getEventSource && getEventSource();
36
+ function SSEClient(settings, useHeaders, _a) {
37
+ var getEventSource = _a.getEventSource, getOptions = _a.getOptions;
38
+ this.eventSource = getEventSource && getEventSource(settings);
37
39
  // if eventSource is not available, throw an exception
38
40
  if (!this.eventSource)
39
- throw new Error('EventSource API is not available. ');
41
+ throw new Error('EventSource API is not available.');
40
42
  this.streamingUrl = settings.urls.streaming + '/sse';
41
43
  // @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
42
44
  this.useHeaders = useHeaders;
43
45
  this.headers = buildSSEHeaders(settings);
46
+ this.options = getOptions && getOptions(settings);
44
47
  }
45
48
  SSEClient.prototype.setEventHandler = function (handler) {
46
49
  this.handler = handler;
@@ -62,8 +65,8 @@ var SSEClient = /** @class */ (function () {
62
65
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
63
66
  // because native EventSource implementations for browser doesn't support headers.
64
67
  this.useHeaders ? url : url + ("&SplitSDKVersion=" + this.headers.SplitSDKVersion + "&SplitSDKClientKey=" + this.headers.SplitSDKClientKey),
65
- // @ts-ignore. For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
66
- this.useHeaders ? { headers: this.headers } : undefined);
68
+ // For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
69
+ objectAssign(this.useHeaders ? { headers: this.headers } : {}, this.options));
67
70
  if (this.handler) { // no need to check if SSEClient is used only by PushManager
68
71
  this.connection.addEventListener('open', this.handler.handleOpen);
69
72
  this.connection.addEventListener('message', this.handler.handleMessage);
@@ -29,7 +29,7 @@ export function pushManagerFactory(params, pollingManager) {
29
29
  var sseClient;
30
30
  try {
31
31
  // `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native).
32
- sseClient = new SSEClient(settings, userKey ? false : true, platform.getEventSource);
32
+ sseClient = new SSEClient(settings, userKey ? false : true, platform);
33
33
  }
34
34
  catch (e) {
35
35
  log.warn(STREAMING_FALLBACK, [e]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@splitsoftware/splitio-commons",
3
- "version": "1.15.1-rc.0",
3
+ "version": "1.15.1-rc.2",
4
4
  "description": "Split JavaScript SDK common components",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -199,5 +199,6 @@ export function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | Spl
199
199
  getTreatmentsByFlagSet,
200
200
  getTreatmentsWithConfigByFlagSet,
201
201
  track,
202
+ isClientSide: false
202
203
  } as SplitIO.IClient | SplitIO.IAsyncClient;
203
204
  }
@@ -17,11 +17,15 @@ export interface IPlatform {
17
17
  /**
18
18
  * If provided, it is used to retrieve the Fetch API for HTTP requests. Otherwise, the global fetch is used.
19
19
  */
20
- getFetch?: () => (IFetch | undefined)
20
+ getFetch?: (settings: ISettings) => (IFetch | undefined)
21
+ /**
22
+ * If provided, it is used to pass additional options to fetch and eventsource calls.
23
+ */
24
+ getOptions?: (settings: ISettings) => object
21
25
  /**
22
26
  * If provided, it is used to retrieve the EventSource constructor for streaming support.
23
27
  */
24
- getEventSource?: () => (IEventSourceConstructor | undefined)
28
+ getEventSource?: (settings: ISettings) => (IEventSourceConstructor | undefined)
25
29
  /**
26
30
  * EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
27
31
  */
@@ -22,7 +22,7 @@ function userKeyToQueryParam(userKey: string) {
22
22
  */
23
23
  export function splitApiFactory(
24
24
  settings: ISettings,
25
- platform: Pick<IPlatform, 'getFetch'>,
25
+ platform: IPlatform,
26
26
  telemetryTracker: ITelemetryTracker
27
27
  ): ISplitApi {
28
28
 
@@ -30,7 +30,7 @@ export function splitApiFactory(
30
30
  const filterQueryString = settings.sync.__splitFiltersValidation && settings.sync.__splitFiltersValidation.queryString;
31
31
  const SplitSDKImpressionsMode = settings.sync.impressionsMode;
32
32
  const flagSpecVersion = settings.sync.flagSpecVersion;
33
- const splitHttpClient = splitHttpClientFactory(settings, platform.getFetch);
33
+ const splitHttpClient = splitHttpClientFactory(settings, platform);
34
34
 
35
35
  return {
36
36
  // @TODO throw errors if health check requests fail, to log them in the Synchronizer
@@ -10,12 +10,13 @@ const messageNoFetch = 'Global fetch API is not available.';
10
10
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
11
11
  *
12
12
  * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
13
- * @param getFetch retrieves the Fetch API for HTTP requests
13
+ * @param platform object containing environment-specific dependencies
14
14
  */
15
- export function splitHttpClientFactory(settings: ISettings, getFetch?: IPlatform['getFetch']): ISplitHttpClient {
15
+ export function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: IPlatform): ISplitHttpClient {
16
16
 
17
17
  const { log, core: { authorizationKey }, version, runtime: { ip, hostname } } = settings;
18
- const fetch = getFetch && getFetch();
18
+ const options = getOptions && getOptions(settings);
19
+ const fetch = getFetch && getFetch(settings);
19
20
 
20
21
  // if fetch is not available, log Error
21
22
  if (!fetch) log.error(ERROR_CLIENT_CANNOT_GET_READY, [messageNoFetch]);
@@ -32,11 +33,11 @@ export function splitHttpClientFactory(settings: ISettings, getFetch?: IPlatform
32
33
 
33
34
  return function httpClient(url: string, reqOpts: IRequestOptions = {}, latencyTracker: (error?: NetworkError) => void = () => { }, logErrorsAsInfo: boolean = false): Promise<IResponse> {
34
35
 
35
- const request = {
36
+ const request = objectAssign({
36
37
  headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers,
37
38
  method: reqOpts.method || 'GET',
38
39
  body: reqOpts.body
39
- };
40
+ }, options);
40
41
 
41
42
  // using `fetch(url, options)` signature to work with unfetch, a lightweight ponyfill of fetch API.
42
43
  return fetch ? fetch(url, request)
@@ -1,4 +1,4 @@
1
- import { RedisAdapter } from './RedisAdapter';
1
+ import type { RedisAdapter } from './RedisAdapter';
2
2
  import { IStorageAsync, IStorageAsyncFactory, IStorageFactoryParams } from '../types';
3
3
  import { validatePrefix } from '../KeyBuilder';
4
4
  import { KeyBuilderSS } from '../KeyBuilderSS';
@@ -23,13 +23,17 @@ export interface InRedisStorageOptions {
23
23
  */
24
24
  export function InRedisStorage(options: InRedisStorageOptions = {}): IStorageAsyncFactory {
25
25
 
26
+ // Lazy loading to prevent error when bundling or importing the SDK in a .mjs file, since ioredis is a CommonJS module.
27
+ // Redis storage is not supported with .mjs files.
28
+ const RD = require('./RedisAdapter').RedisAdapter;
29
+
26
30
  const prefix = validatePrefix(options.prefix);
27
31
 
28
32
  function InRedisStorageFactory(params: IStorageFactoryParams): IStorageAsync {
29
33
  const { onReadyCb, settings, settings: { log, sync: { impressionsMode } } } = params;
30
34
  const metadata = metadataBuilder(settings);
31
35
  const keys = new KeyBuilderSS(prefix, metadata);
32
- const redisClient = new RedisAdapter(log, options.options || {});
36
+ const redisClient: RedisAdapter = new RD(log, options.options || {});
33
37
  const telemetry = new TelemetryCacheInRedis(log, keys, redisClient);
34
38
  const impressionCountsCache = impressionsMode !== DEBUG ? new ImpressionCountsCacheInRedis(log, keys.buildImpressionsCountKey(), redisClient) : undefined;
35
39
  const uniqueKeysCache = impressionsMode === NONE ? new UniqueKeysCacheInRedis(log, keys.buildUniqueKeysKey(), redisClient) : undefined;
@@ -1,6 +1,8 @@
1
+ import { IPlatform } from '../../../sdkFactory/types';
1
2
  import { IEventSourceConstructor } from '../../../services/types';
2
3
  import { ISettings } from '../../../types';
3
4
  import { isString } from '../../../utils/lang';
5
+ import { objectAssign } from '../../../utils/lang/objectAssign';
4
6
  import { IAuthTokenPushEnabled } from '../AuthClient/types';
5
7
  import { ISSEClient, ISseEventHandler } from './types';
6
8
 
@@ -39,24 +41,26 @@ export class SSEClient implements ISSEClient {
39
41
  handler?: ISseEventHandler;
40
42
  useHeaders?: boolean;
41
43
  headers: Record<string, string>;
44
+ options?: object;
42
45
 
43
46
  /**
44
47
  * SSEClient constructor.
45
48
  *
46
49
  * @param settings Validated settings.
47
50
  * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
48
- * @param getEventSource Function to get the EventSource constructor.
49
- * @throws 'EventSource API is not available. ' if EventSource is not available.
51
+ * @param platform object containing environment-specific dependencies
52
+ * @throws 'EventSource API is not available.' if EventSource is not available.
50
53
  */
51
- constructor(settings: ISettings, useHeaders?: boolean, getEventSource?: () => (IEventSourceConstructor | undefined)) {
52
- this.eventSource = getEventSource && getEventSource();
54
+ constructor(settings: ISettings, useHeaders: boolean, { getEventSource, getOptions }: IPlatform) {
55
+ this.eventSource = getEventSource && getEventSource(settings);
53
56
  // if eventSource is not available, throw an exception
54
- if (!this.eventSource) throw new Error('EventSource API is not available. ');
57
+ if (!this.eventSource) throw new Error('EventSource API is not available.');
55
58
 
56
59
  this.streamingUrl = settings.urls.streaming + '/sse';
57
60
  // @TODO get `useHeaders` flag from `getEventSource`, to use EventSource headers on client-side SDKs when possible.
58
61
  this.useHeaders = useHeaders;
59
62
  this.headers = buildSSEHeaders(settings);
63
+ this.options = getOptions && getOptions(settings);
60
64
  }
61
65
 
62
66
  setEventHandler(handler: ISseEventHandler) {
@@ -84,8 +88,8 @@ export class SSEClient implements ISSEClient {
84
88
  // For client-side SDKs, SplitSDKClientKey and SplitSDKClientKey metadata is passed as query params,
85
89
  // because native EventSource implementations for browser doesn't support headers.
86
90
  this.useHeaders ? url : url + `&SplitSDKVersion=${this.headers.SplitSDKVersion}&SplitSDKClientKey=${this.headers.SplitSDKClientKey}`,
87
- // @ts-ignore. For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
88
- this.useHeaders ? { headers: this.headers } : undefined
91
+ // For server-side SDKs, metadata is passed via headers. EventSource must support headers, like 'eventsource' package for Node.
92
+ objectAssign(this.useHeaders ? { headers: this.headers } : {}, this.options)
89
93
  );
90
94
 
91
95
  if (this.handler) { // no need to check if SSEClient is used only by PushManager
@@ -42,7 +42,7 @@ export function pushManagerFactory(
42
42
  let sseClient: ISSEClient;
43
43
  try {
44
44
  // `useHeaders` false for client-side, even if the platform EventSource supports headers (e.g., React Native).
45
- sseClient = new SSEClient(settings, userKey ? false : true, platform.getEventSource);
45
+ sseClient = new SSEClient(settings, userKey ? false : true, platform);
46
46
  } catch (e) {
47
47
  log.warn(STREAMING_FALLBACK, [e]);
48
48
  return;
@@ -16,11 +16,15 @@ export interface IPlatform {
16
16
  /**
17
17
  * If provided, it is used to retrieve the Fetch API for HTTP requests. Otherwise, the global fetch is used.
18
18
  */
19
- getFetch?: () => (IFetch | undefined);
19
+ getFetch?: (settings: ISettings) => (IFetch | undefined);
20
+ /**
21
+ * If provided, it is used to pass additional options to fetch and eventsource calls.
22
+ */
23
+ getOptions?: (settings: ISettings) => object;
20
24
  /**
21
25
  * If provided, it is used to retrieve the EventSource constructor for streaming support.
22
26
  */
23
- getEventSource?: () => (IEventSourceConstructor | undefined);
27
+ getEventSource?: (settings: ISettings) => (IEventSourceConstructor | undefined);
24
28
  /**
25
29
  * EventEmitter constructor, like NodeJS.EventEmitter or a polyfill.
26
30
  */
@@ -9,4 +9,4 @@ import { ITelemetryTracker } from '../trackers/types';
9
9
  * @param platform object containing environment-specific dependencies
10
10
  * @param telemetryTracker telemetry tracker
11
11
  */
12
- export declare function splitApiFactory(settings: ISettings, platform: Pick<IPlatform, 'getFetch'>, telemetryTracker: ITelemetryTracker): ISplitApi;
12
+ export declare function splitApiFactory(settings: ISettings, platform: IPlatform, telemetryTracker: ITelemetryTracker): ISplitApi;
@@ -5,6 +5,6 @@ import { IPlatform } from '../sdkFactory/types';
5
5
  * Factory of Split HTTP clients, which are HTTP clients with predefined headers for Split endpoints.
6
6
  *
7
7
  * @param settings SDK settings, used to access authorizationKey, logger instance and metadata (SDK version, ip and hostname) to set additional headers
8
- * @param getFetch retrieves the Fetch API for HTTP requests
8
+ * @param platform object containing environment-specific dependencies
9
9
  */
10
- export declare function splitHttpClientFactory(settings: ISettings, getFetch?: IPlatform['getFetch']): ISplitHttpClient;
10
+ export declare function splitHttpClientFactory(settings: ISettings, { getOptions, getFetch }: IPlatform): ISplitHttpClient;
@@ -1,3 +1,4 @@
1
+ import { IPlatform } from '../../../sdkFactory/types';
1
2
  import { IEventSourceConstructor } from '../../../services/types';
2
3
  import { ISettings } from '../../../types';
3
4
  import { IAuthTokenPushEnabled } from '../AuthClient/types';
@@ -12,15 +13,16 @@ export declare class SSEClient implements ISSEClient {
12
13
  handler?: ISseEventHandler;
13
14
  useHeaders?: boolean;
14
15
  headers: Record<string, string>;
16
+ options?: object;
15
17
  /**
16
18
  * SSEClient constructor.
17
19
  *
18
20
  * @param settings Validated settings.
19
21
  * @param useHeaders True to send metadata as headers or false to send as query params. If `true`, the provided EventSource must support headers.
20
- * @param getEventSource Function to get the EventSource constructor.
21
- * @throws 'EventSource API is not available. ' if EventSource is not available.
22
+ * @param platform object containing environment-specific dependencies
23
+ * @throws 'EventSource API is not available.' if EventSource is not available.
22
24
  */
23
- constructor(settings: ISettings, useHeaders?: boolean, getEventSource?: () => (IEventSourceConstructor | undefined));
25
+ constructor(settings: ISettings, useHeaders: boolean, { getEventSource, getOptions }: IPlatform);
24
26
  setEventHandler(handler: ISseEventHandler): void;
25
27
  /**
26
28
  * Open the connection with a given authToken