@splitsoftware/splitio-commons 1.2.1-rc.8 → 1.3.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 +17 -0
- package/cjs/{utils/consent.js → consent/index.js} +1 -1
- package/cjs/consent/sdkUserConsent.js +58 -0
- package/cjs/listeners/browser.js +1 -1
- package/cjs/logger/constants.js +3 -2
- package/cjs/logger/messages/info.js +1 -0
- package/cjs/readiness/sdkReadinessManager.js +5 -3
- package/cjs/sdkClient/client.js +1 -1
- package/cjs/sdkClient/clientCS.js +1 -1
- package/cjs/sdkClient/sdkClient.js +3 -3
- package/cjs/sdkClient/sdkClientMethodCS.js +3 -9
- package/cjs/sdkClient/sdkClientMethodCSWithTT.js +3 -13
- package/cjs/sdkFactory/index.js +3 -2
- package/cjs/services/splitHttpClient.js +12 -11
- package/cjs/storages/inRedis/RedisAdapter.js +9 -2
- package/cjs/sync/syncManagerOnline.js +1 -1
- package/cjs/trackers/impressionsTracker.js +2 -2
- package/cjs/utils/inputValidation/attributes.js +1 -1
- package/cjs/utils/lang/index.js +4 -2
- package/cjs/utils/lang/maps.js +16 -2
- package/cjs/utils/settingsValidation/index.js +21 -3
- package/esm/{utils/consent.js → consent/index.js} +1 -1
- package/esm/consent/sdkUserConsent.js +54 -0
- package/esm/listeners/browser.js +1 -1
- package/esm/logger/constants.js +1 -0
- package/esm/logger/messages/info.js +1 -0
- package/esm/readiness/sdkReadinessManager.js +5 -3
- package/esm/sdkClient/client.js +1 -1
- package/esm/sdkClient/clientCS.js +1 -1
- package/esm/sdkClient/sdkClient.js +3 -3
- package/esm/sdkClient/sdkClientMethodCS.js +3 -9
- package/esm/sdkClient/sdkClientMethodCSWithTT.js +3 -13
- package/esm/sdkFactory/index.js +3 -2
- package/esm/services/splitHttpClient.js +12 -11
- package/esm/storages/inRedis/RedisAdapter.js +9 -2
- package/esm/sync/syncManagerOnline.js +1 -1
- package/esm/trackers/impressionsTracker.js +2 -2
- package/esm/utils/inputValidation/attributes.js +1 -1
- package/esm/utils/lang/index.js +4 -2
- package/esm/utils/lang/maps.js +14 -1
- package/esm/utils/settingsValidation/index.js +21 -3
- package/package.json +14 -2
- package/src/{utils/consent.ts → consent/index.ts} +1 -1
- package/src/consent/sdkUserConsent.ts +58 -0
- package/src/evaluator/parser/index.ts +1 -1
- package/src/evaluator/types.ts +2 -2
- package/src/evaluator/value/index.ts +2 -2
- package/src/evaluator/value/sanitize.ts +2 -2
- package/src/integrations/pluggable.ts +2 -2
- package/src/listeners/browser.ts +1 -1
- package/src/logger/constants.ts +1 -0
- package/src/logger/messages/info.ts +1 -0
- package/src/readiness/sdkReadinessManager.ts +7 -5
- package/src/sdkClient/client.ts +3 -4
- package/src/sdkClient/clientCS.ts +1 -1
- package/src/sdkClient/sdkClient.ts +4 -4
- package/src/sdkClient/sdkClientMethod.ts +2 -2
- package/src/sdkClient/sdkClientMethodCS.ts +5 -11
- package/src/sdkClient/sdkClientMethodCSWithTT.ts +6 -16
- package/src/sdkFactory/index.ts +3 -2
- package/src/sdkFactory/types.ts +13 -3
- package/src/services/splitHttpClient.ts +12 -10
- package/src/storages/inRedis/RedisAdapter.ts +8 -2
- package/src/sync/syncManagerOnline.ts +1 -1
- package/src/trackers/impressionsTracker.ts +4 -4
- package/src/types.ts +3 -3
- package/src/utils/inputValidation/attributes.ts +1 -2
- package/src/utils/lang/index.ts +7 -3
- package/src/utils/lang/maps.ts +15 -1
- package/src/utils/settingsValidation/index.ts +21 -3
- package/src/utils/settingsValidation/types.ts +5 -1
- package/types/consent/index.d.ts +2 -0
- package/types/consent/sdkUserConsent.d.ts +13 -0
- package/types/evaluator/types.d.ts +2 -2
- package/types/evaluator/value/index.d.ts +1 -1
- package/types/evaluator/value/sanitize.d.ts +1 -1
- package/types/logger/constants.d.ts +1 -0
- package/types/sdkClient/client.d.ts +2 -2
- package/types/sdkClient/sdkClient.d.ts +2 -2
- package/types/sdkClient/sdkClientMethod.d.ts +2 -2
- package/types/sdkClient/sdkClientMethodCS.d.ts +2 -2
- package/types/sdkClient/sdkClientMethodCSWithTT.d.ts +2 -2
- package/types/sdkFactory/types.d.ts +12 -3
- package/types/storages/inMemory/TelemetryCacheInMemory.d.ts +8 -10
- package/types/storages/inRedis/RedisAdapter.d.ts +1 -1
- package/types/storages/inRedis/TelemetryCacheInRedis.d.ts +21 -0
- package/types/storages/pluggable/TelemetryCachePluggable.d.ts +19 -1
- package/types/sync/submitters/telemetrySyncTask.d.ts +16 -6
- package/types/types.d.ts +3 -3
- package/types/utils/lang/index.d.ts +2 -1
- package/types/utils/lang/maps.d.ts +7 -0
- package/types/utils/settingsValidation/types.d.ts +5 -1
- package/cjs/sdkClient/types.js +0 -2
- package/cjs/sdkFactory/userConsentProps.js +0 -37
- package/esm/sdkClient/types.js +0 -1
- package/esm/sdkFactory/userConsentProps.js +0 -33
- package/src/sdkClient/types.ts +0 -21
- package/src/sdkFactory/userConsentProps.ts +0 -40
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { clientCSDecorator } from './clientCS';
|
|
2
|
-
import { ISdkClientFactoryParams } from './types';
|
|
3
2
|
import { SplitIO } from '../types';
|
|
4
3
|
import { validateKey } from '../utils/inputValidation/key';
|
|
5
4
|
import { getMatching, keyParser } from '../utils/key';
|
|
@@ -8,6 +7,7 @@ import { ISyncManagerCS } from '../sync/types';
|
|
|
8
7
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
9
8
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
10
9
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
10
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
11
11
|
|
|
12
12
|
function buildInstanceId(key: SplitIO.SplitKey) {
|
|
13
13
|
// @ts-ignore
|
|
@@ -20,18 +20,13 @@ const method = 'Client instantiation';
|
|
|
20
20
|
* Factory of client method for the client-side API variant where TT is ignored and thus
|
|
21
21
|
* clients don't have a binded TT for the track method.
|
|
22
22
|
*/
|
|
23
|
-
export function sdkClientMethodCSFactory(params:
|
|
23
|
+
export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient {
|
|
24
24
|
const { storage, syncManager, sdkReadinessManager, settings: { core: { key }, startup: { readyTimeout }, log } } = params;
|
|
25
25
|
|
|
26
|
-
// Keeping similar behaviour as in the isomorphic JS SDK: if settings key is invalid,
|
|
27
|
-
// `false` value is used as binded key of the default client, but trafficType is ignored
|
|
28
|
-
// @TODO handle as a non-recoverable error
|
|
29
|
-
const validKey = validateKey(log, key, method);
|
|
30
|
-
|
|
31
26
|
const mainClientInstance = clientCSDecorator(
|
|
32
27
|
log,
|
|
33
|
-
sdkClientFactory(params) as SplitIO.IClient,
|
|
34
|
-
|
|
28
|
+
sdkClientFactory(params) as SplitIO.IClient,
|
|
29
|
+
key
|
|
35
30
|
);
|
|
36
31
|
|
|
37
32
|
const parsedDefaultKey = keyParser(key);
|
|
@@ -81,8 +76,7 @@ export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key?
|
|
|
81
76
|
storage: sharedStorage || storage,
|
|
82
77
|
syncManager: sharedSyncManager,
|
|
83
78
|
signalListener: undefined, // only the main client "destroy" method stops the signal listener
|
|
84
|
-
|
|
85
|
-
})) as SplitIO.IClient,
|
|
79
|
+
}), true) as SplitIO.IClient,
|
|
86
80
|
validKey
|
|
87
81
|
);
|
|
88
82
|
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { clientCSDecorator } from './clientCS';
|
|
2
|
-
import { ISdkClientFactoryParams } from './types';
|
|
3
2
|
import { SplitIO } from '../types';
|
|
4
3
|
import { validateKey } from '../utils/inputValidation/key';
|
|
5
4
|
import { validateTrafficType } from '../utils/inputValidation/trafficType';
|
|
@@ -9,6 +8,7 @@ import { ISyncManagerCS } from '../sync/types';
|
|
|
9
8
|
import { objectAssign } from '../utils/lang/objectAssign';
|
|
10
9
|
import { RETRIEVE_CLIENT_DEFAULT, NEW_SHARED_CLIENT, RETRIEVE_CLIENT_EXISTING } from '../logger/constants';
|
|
11
10
|
import { SDK_SEGMENTS_ARRIVED } from '../readiness/constants';
|
|
11
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
12
12
|
|
|
13
13
|
function buildInstanceId(key: SplitIO.SplitKey, trafficType?: string) {
|
|
14
14
|
// @ts-ignore
|
|
@@ -22,23 +22,14 @@ const method = 'Client instantiation';
|
|
|
22
22
|
* where clients can have a binded TT for the track method, which is provided via the settings
|
|
23
23
|
* (default client) or the client method (shared clients).
|
|
24
24
|
*/
|
|
25
|
-
export function sdkClientMethodCSFactory(params:
|
|
25
|
+
export function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient {
|
|
26
26
|
const { storage, syncManager, sdkReadinessManager, settings: { core: { key, trafficType }, startup: { readyTimeout }, log } } = params;
|
|
27
27
|
|
|
28
|
-
// Keeping the behaviour as in the isomorphic JS SDK: if settings key or TT are invalid,
|
|
29
|
-
// `false` value is used as binded key/TT of the default client, which leads to several issues.
|
|
30
|
-
// @TODO update when supporting non-recoverable errors
|
|
31
|
-
const validKey = validateKey(log, key, method);
|
|
32
|
-
let validTrafficType;
|
|
33
|
-
if (trafficType !== undefined) {
|
|
34
|
-
validTrafficType = validateTrafficType(log, trafficType, method);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
28
|
const mainClientInstance = clientCSDecorator(
|
|
38
29
|
log,
|
|
39
|
-
sdkClientFactory(params) as SplitIO.IClient,
|
|
40
|
-
|
|
41
|
-
|
|
30
|
+
sdkClientFactory(params) as SplitIO.IClient,
|
|
31
|
+
key,
|
|
32
|
+
trafficType
|
|
42
33
|
);
|
|
43
34
|
|
|
44
35
|
const parsedDefaultKey = keyParser(key);
|
|
@@ -95,8 +86,7 @@ export function sdkClientMethodCSFactory(params: ISdkClientFactoryParams): (key?
|
|
|
95
86
|
storage: sharedStorage || storage,
|
|
96
87
|
syncManager: sharedSyncManager,
|
|
97
88
|
signalListener: undefined, // only the main client "destroy" method stops the signal listener
|
|
98
|
-
|
|
99
|
-
})) as SplitIO.IClient,
|
|
89
|
+
}), true) as SplitIO.IClient,
|
|
100
90
|
validKey,
|
|
101
91
|
validTrafficType
|
|
102
92
|
);
|
package/src/sdkFactory/index.ts
CHANGED
|
@@ -81,7 +81,8 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
81
81
|
const signalListener = SignalListener && new SignalListener(syncManager, settings, storage, splitApi);
|
|
82
82
|
|
|
83
83
|
// Sdk client and manager
|
|
84
|
-
const
|
|
84
|
+
const ctx = { eventTracker, impressionsTracker, sdkReadinessManager, settings, storage, syncManager, signalListener };
|
|
85
|
+
const clientMethod = sdkClientMethodFactory(ctx);
|
|
85
86
|
const managerInstance = sdkManagerFactory(log, storage.splits, sdkReadinessManager);
|
|
86
87
|
|
|
87
88
|
syncManager && syncManager.start();
|
|
@@ -104,5 +105,5 @@ export function sdkFactory(params: ISdkFactoryParams): SplitIO.ICsSDK | SplitIO.
|
|
|
104
105
|
Logger: createLoggerAPI(settings.log),
|
|
105
106
|
|
|
106
107
|
settings,
|
|
107
|
-
}, extraProps && extraProps(
|
|
108
|
+
}, extraProps && extraProps(ctx));
|
|
108
109
|
}
|
package/src/sdkFactory/types.ts
CHANGED
|
@@ -2,13 +2,23 @@ import { IIntegrationManager, IIntegrationFactoryParams } from '../integrations/
|
|
|
2
2
|
import { ISignalListener } from '../listeners/types';
|
|
3
3
|
import { ILogger } from '../logger/types';
|
|
4
4
|
import { ISdkReadinessManager } from '../readiness/types';
|
|
5
|
-
import { ISdkClientFactoryParams } from '../sdkClient/types';
|
|
6
5
|
import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
|
|
7
6
|
import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types';
|
|
8
7
|
import { ISyncManager, ISyncManagerFactoryParams } from '../sync/types';
|
|
9
8
|
import { IImpressionObserver } from '../trackers/impressionObserver/types';
|
|
9
|
+
import { IImpressionsTracker, IEventTracker } from '../trackers/types';
|
|
10
10
|
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
11
11
|
|
|
12
|
+
export interface ISdkFactoryContext {
|
|
13
|
+
storage: IStorageSync | IStorageAsync,
|
|
14
|
+
sdkReadinessManager: ISdkReadinessManager,
|
|
15
|
+
settings: ISettings
|
|
16
|
+
impressionsTracker: IImpressionsTracker,
|
|
17
|
+
eventTracker: IEventTracker,
|
|
18
|
+
signalListener?: ISignalListener
|
|
19
|
+
syncManager?: ISyncManager,
|
|
20
|
+
}
|
|
21
|
+
|
|
12
22
|
/**
|
|
13
23
|
* Environment related dependencies.
|
|
14
24
|
* These getters are called a fixed number of times per factory instantiation.
|
|
@@ -53,7 +63,7 @@ export interface ISdkFactoryParams {
|
|
|
53
63
|
|
|
54
64
|
// Sdk client method factory (ISDK::client method).
|
|
55
65
|
// It Allows to distinguish SDK clients with the client-side API (`ICsSDK`) or server-side API (`ISDK` or `IAsyncSDK`).
|
|
56
|
-
sdkClientMethodFactory: (params:
|
|
66
|
+
sdkClientMethodFactory: (params: ISdkFactoryContext) => ({ (): SplitIO.ICsClient; (key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient; } | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient))
|
|
57
67
|
|
|
58
68
|
// Optional signal listener constructor. Used to handle special app states, like shutdown, app paused or resumed.
|
|
59
69
|
// Pass only if `syncManager` (used by Node listener) and `splitApi` (used by Browser listener) are passed.
|
|
@@ -70,5 +80,5 @@ export interface ISdkFactoryParams {
|
|
|
70
80
|
impressionsObserverFactory?: () => IImpressionObserver
|
|
71
81
|
|
|
72
82
|
// Optional function to assign additional properties to the factory instance
|
|
73
|
-
extraProps?: (
|
|
83
|
+
extraProps?: (params: ISdkFactoryContext) => object
|
|
74
84
|
}
|
|
@@ -14,24 +14,26 @@ const messageNoFetch = 'Global fetch API is not available.';
|
|
|
14
14
|
*/
|
|
15
15
|
export function splitHttpClientFactory(settings: Pick<ISettings, 'log' | 'version' | 'runtime' | 'core'>, getFetch?: () => (IFetch | undefined), getOptions?: () => object): ISplitHttpClient {
|
|
16
16
|
|
|
17
|
-
const
|
|
17
|
+
const log = settings.log;
|
|
18
18
|
const options = getOptions && getOptions();
|
|
19
19
|
const fetch = getFetch && getFetch();
|
|
20
20
|
|
|
21
21
|
// if fetch is not available, log Error
|
|
22
22
|
if (!fetch) log.error(ERROR_CLIENT_CANNOT_GET_READY, [messageNoFetch]);
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
'Accept': 'application/json',
|
|
26
|
-
'Content-Type': 'application/json',
|
|
27
|
-
'Authorization': `Bearer ${authorizationKey}`,
|
|
28
|
-
'SplitSDKVersion': version
|
|
29
|
-
};
|
|
24
|
+
return function httpClient(url: string, reqOpts: IRequestOptions = {}, logErrorsAsInfo: boolean = false): Promise<IResponse> {
|
|
30
25
|
|
|
31
|
-
|
|
32
|
-
if (hostname) headers['SplitSDKMachineName'] = hostname;
|
|
26
|
+
const { core: { authorizationKey }, version, runtime: { ip, hostname } } = settings;
|
|
33
27
|
|
|
34
|
-
|
|
28
|
+
const headers: Record<string, string> = {
|
|
29
|
+
'Accept': 'application/json',
|
|
30
|
+
'Content-Type': 'application/json',
|
|
31
|
+
'Authorization': `Bearer ${authorizationKey}`,
|
|
32
|
+
'SplitSDKVersion': version
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
if (ip) headers['SplitSDKMachineIP'] = ip;
|
|
36
|
+
if (hostname) headers['SplitSDKMachineName'] = hostname;
|
|
35
37
|
|
|
36
38
|
const request = objectAssign({
|
|
37
39
|
headers: reqOpts.headers ? objectAssign({}, headers, reqOpts.headers) : headers,
|
|
@@ -164,6 +164,12 @@ export class RedisAdapter extends ioredis {
|
|
|
164
164
|
} else { // If it IS the string URL, that'll be the first param for ioredis.
|
|
165
165
|
result.unshift(options.url);
|
|
166
166
|
}
|
|
167
|
+
if (options.connectionTimeout) {
|
|
168
|
+
merge(opts, { connectTimeout: options.connectionTimeout });
|
|
169
|
+
}
|
|
170
|
+
if (options.tls) {
|
|
171
|
+
merge(opts, { tls: options.tls });
|
|
172
|
+
}
|
|
167
173
|
|
|
168
174
|
return result;
|
|
169
175
|
}
|
|
@@ -171,9 +177,9 @@ export class RedisAdapter extends ioredis {
|
|
|
171
177
|
/**
|
|
172
178
|
* Parses the options into what we care about.
|
|
173
179
|
*/
|
|
174
|
-
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass }: Record<string, any>) {
|
|
180
|
+
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass, tls }: Record<string, any>) {
|
|
175
181
|
const parsedOptions = {
|
|
176
|
-
connectionTimeout, operationTimeout, url, host, port, db, pass
|
|
182
|
+
connectionTimeout, operationTimeout, url, host, port, db, pass, tls
|
|
177
183
|
};
|
|
178
184
|
|
|
179
185
|
return merge({}, DEFAULT_OPTIONS, parsedOptions);
|
|
@@ -6,7 +6,7 @@ import { IPushManager } from './streaming/types';
|
|
|
6
6
|
import { IPollingManager, IPollingManagerCS } from './polling/types';
|
|
7
7
|
import { PUSH_SUBSYSTEM_UP, PUSH_SUBSYSTEM_DOWN } from './streaming/constants';
|
|
8
8
|
import { SYNC_START_POLLING, SYNC_CONTINUE_POLLING, SYNC_STOP_POLLING } from '../logger/constants';
|
|
9
|
-
import { isConsentGranted } from '../
|
|
9
|
+
import { isConsentGranted } from '../consent';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Online SyncManager factory.
|
|
@@ -28,7 +28,7 @@ export function impressionsTrackerFactory(
|
|
|
28
28
|
countsCache?: IImpressionCountsCacheSync
|
|
29
29
|
): IImpressionsTracker {
|
|
30
30
|
|
|
31
|
-
const { log, impressionListener, runtime: { ip, hostname }
|
|
31
|
+
const { log, impressionListener, runtime: { ip, hostname } } = settings;
|
|
32
32
|
|
|
33
33
|
return {
|
|
34
34
|
track(impressions: ImpressionDTO[], attributes?: SplitIO.Attributes) {
|
|
@@ -74,9 +74,9 @@ export function impressionsTrackerFactory(
|
|
|
74
74
|
// copy of impression, to avoid unexpected behaviour if modified by integrations or impressionListener
|
|
75
75
|
impression: objectAssign({}, impressions[i]),
|
|
76
76
|
attributes,
|
|
77
|
-
ip
|
|
78
|
-
hostname
|
|
79
|
-
sdkLanguageVersion: version
|
|
77
|
+
ip,
|
|
78
|
+
hostname,
|
|
79
|
+
sdkLanguageVersion: settings.version
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
// Wrap in a timeout because we don't want it to be blocking.
|
package/src/types.ts
CHANGED
|
@@ -398,7 +398,7 @@ interface IBasicClient extends IStatusInterface {
|
|
|
398
398
|
|
|
399
399
|
// Whether the client implements the client-side API, i.e, with bound key, (true), or the server-side API (false).
|
|
400
400
|
// Exposed for internal purposes only. Not considered part of the public API, and might be renamed eventually.
|
|
401
|
-
|
|
401
|
+
isClientSide: boolean
|
|
402
402
|
}
|
|
403
403
|
/**
|
|
404
404
|
* Common definitions between SDK instances for different environments interface.
|
|
@@ -535,8 +535,8 @@ export namespace SplitIO {
|
|
|
535
535
|
export type ImpressionData = {
|
|
536
536
|
impression: ImpressionDTO,
|
|
537
537
|
attributes?: SplitIO.Attributes,
|
|
538
|
-
ip: string,
|
|
539
|
-
hostname: string,
|
|
538
|
+
ip: string| false,
|
|
539
|
+
hostname: string | false,
|
|
540
540
|
sdkLanguageVersion: string
|
|
541
541
|
};
|
|
542
542
|
/**
|
|
@@ -6,7 +6,7 @@ import { ERROR_NOT_PLAIN_OBJECT } from '../../logger/constants';
|
|
|
6
6
|
|
|
7
7
|
export function validateAttributes(log: ILogger, maybeAttrs: any, method: string): SplitIO.Attributes | undefined | false {
|
|
8
8
|
// Attributes are optional
|
|
9
|
-
if (
|
|
9
|
+
if (maybeAttrs == undefined || isObject(maybeAttrs)) // eslint-disable-line eqeqeq
|
|
10
10
|
return maybeAttrs;
|
|
11
11
|
|
|
12
12
|
log.error(ERROR_NOT_PLAIN_OBJECT, [method, 'attributes']);
|
|
@@ -23,5 +23,4 @@ export function validateAttributesDeep(log: ILogger, maybeAttributes: Record<str
|
|
|
23
23
|
});
|
|
24
24
|
|
|
25
25
|
return result;
|
|
26
|
-
|
|
27
26
|
}
|
package/src/utils/lang/index.ts
CHANGED
|
@@ -151,10 +151,14 @@ export function isNaNNumber(val: any): boolean {
|
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
/**
|
|
154
|
-
* Validates if a value is an object
|
|
154
|
+
* Validates if a value is an object created by the Object constructor (plain object).
|
|
155
|
+
* It checks `constructor.name` to avoid false negatives when validating values on a separate VM context, which has its own global built-ins.
|
|
155
156
|
*/
|
|
156
|
-
export function isObject(obj: any)
|
|
157
|
-
return obj !== null && typeof obj === 'object' &&
|
|
157
|
+
export function isObject(obj: any) {
|
|
158
|
+
return obj !== null && typeof obj === 'object' && (
|
|
159
|
+
obj.constructor === Object ||
|
|
160
|
+
(obj.constructor != null && obj.constructor.name === 'Object')
|
|
161
|
+
);
|
|
158
162
|
}
|
|
159
163
|
|
|
160
164
|
/**
|
package/src/utils/lang/maps.ts
CHANGED
|
@@ -79,4 +79,18 @@ interface IMapConstructor {
|
|
|
79
79
|
readonly prototype: IMap<any, any>;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
|
|
82
|
+
/**
|
|
83
|
+
* return the Map constructor to use. If native Map is not available or it doesn't support the required features (e.g., IE11),
|
|
84
|
+
* a ponyfill with minimal features is returned instead.
|
|
85
|
+
*
|
|
86
|
+
* Exported for testing purposes only.
|
|
87
|
+
*/
|
|
88
|
+
export function __getMapConstructor(): IMapConstructor {
|
|
89
|
+
// eslint-disable-next-line compat/compat
|
|
90
|
+
if (typeof Array.from === 'function' && typeof Map === 'function' && Map.prototype && Map.prototype.values) {
|
|
91
|
+
return Map;
|
|
92
|
+
}
|
|
93
|
+
return MapPoly;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const _Map = __getMapConstructor();
|
|
@@ -5,6 +5,8 @@ import { STANDALONE_MODE, OPTIMIZED, LOCALHOST_MODE } from '../constants';
|
|
|
5
5
|
import { validImpressionsMode } from './impressionsMode';
|
|
6
6
|
import { ISettingsValidationParams } from './types';
|
|
7
7
|
import { ISettings } from '../../types';
|
|
8
|
+
import { validateKey } from '../inputValidation/key';
|
|
9
|
+
import { validateTrafficType } from '../inputValidation/trafficType';
|
|
8
10
|
|
|
9
11
|
const base = {
|
|
10
12
|
// Define which kind of object you want to retrieve from SplitFactory
|
|
@@ -129,9 +131,25 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
129
131
|
// @ts-ignore, modify readonly prop
|
|
130
132
|
if (storage) withDefaults.storage = storage(withDefaults);
|
|
131
133
|
|
|
132
|
-
//
|
|
133
|
-
if (
|
|
134
|
-
withDefaults.core.key
|
|
134
|
+
// Validate key and TT (for client-side)
|
|
135
|
+
if (validationParams.acceptKey) {
|
|
136
|
+
const maybeKey = withDefaults.core.key;
|
|
137
|
+
// Although `key` is required in client-side, it can be omitted in LOCALHOST mode. In that case, the value `localhost_key` is used.
|
|
138
|
+
if (withDefaults.mode === LOCALHOST_MODE && maybeKey === undefined) {
|
|
139
|
+
withDefaults.core.key = 'localhost_key';
|
|
140
|
+
} else {
|
|
141
|
+
// Keeping same behaviour than JS SDK: if settings key or TT are invalid,
|
|
142
|
+
// `false` value is used as binded key/TT of the default client, which leads to some issues.
|
|
143
|
+
// @ts-ignore, @TODO handle invalid keys as a non-recoverable error?
|
|
144
|
+
withDefaults.core.key = validateKey(log, maybeKey, 'Client instantiation');
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
if (validationParams.acceptTT) {
|
|
148
|
+
const maybeTT = withDefaults.core.trafficType;
|
|
149
|
+
if (maybeTT !== undefined) { // @ts-ignore
|
|
150
|
+
withDefaults.core.trafficType = validateTrafficType(log, maybeTT, 'Client instantiation');
|
|
151
|
+
}
|
|
152
|
+
}
|
|
135
153
|
}
|
|
136
154
|
|
|
137
155
|
// Current ip/hostname information
|
|
@@ -10,7 +10,11 @@ export interface ISettingsValidationParams {
|
|
|
10
10
|
* Version and startup properties are required, because they are not defined in the base settings.
|
|
11
11
|
*/
|
|
12
12
|
defaults: Partial<ISettings> & { version: string } & { startup: ISettings['startup'] },
|
|
13
|
-
/**
|
|
13
|
+
/** If true, validates core.key */
|
|
14
|
+
acceptKey?: boolean,
|
|
15
|
+
/** If true, validates core.trafficType */
|
|
16
|
+
acceptTT?: boolean,
|
|
17
|
+
/** Define runtime values (`settings.runtime`) */
|
|
14
18
|
runtime: (settings: ISettings) => ISettings['runtime'],
|
|
15
19
|
/** Storage validator (`settings.storage`) */
|
|
16
20
|
storage?: (settings: ISettings) => ISettings['storage'],
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
2
|
+
/**
|
|
3
|
+
* The public user consent API exposed via SplitFactory, used to control if the SDK tracks and sends impressions and events or not.
|
|
4
|
+
*/
|
|
5
|
+
export declare function createUserConsentAPI(params: ISdkFactoryContext): {
|
|
6
|
+
setStatus(consent: unknown): boolean;
|
|
7
|
+
getStatus(): import("../types").ConsentStatus | undefined;
|
|
8
|
+
Status: {
|
|
9
|
+
GRANTED: string;
|
|
10
|
+
DECLINED: string;
|
|
11
|
+
UNKNOWN: string;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
@@ -5,7 +5,7 @@ import { SplitIO } from '../types';
|
|
|
5
5
|
import { ILogger } from '../logger/types';
|
|
6
6
|
export interface IDependencyMatcherValue {
|
|
7
7
|
key: SplitIO.SplitKey;
|
|
8
|
-
attributes
|
|
8
|
+
attributes?: SplitIO.Attributes;
|
|
9
9
|
}
|
|
10
10
|
export interface IMatcherDto {
|
|
11
11
|
type: number;
|
|
@@ -23,6 +23,6 @@ export interface IEvaluation {
|
|
|
23
23
|
export declare type IEvaluationResult = IEvaluation & {
|
|
24
24
|
treatment: string;
|
|
25
25
|
};
|
|
26
|
-
export declare type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>;
|
|
26
|
+
export declare type ISplitEvaluator = (log: ILogger, key: SplitIO.SplitKey, splitName: string, attributes: SplitIO.Attributes | undefined, storage: IStorageSync | IStorageAsync) => MaybeThenable<IEvaluation>;
|
|
27
27
|
export declare type IEvaluator = (key: SplitIO.SplitKey, seed: number, trafficAllocation?: number, trafficAllocationSeed?: number, attributes?: SplitIO.Attributes, splitEvaluator?: ISplitEvaluator) => MaybeThenable<IEvaluation | undefined>;
|
|
28
28
|
export declare type IMatcher = (...args: any) => MaybeThenable<boolean>;
|
|
@@ -4,4 +4,4 @@ import { ILogger } from '../../logger/types';
|
|
|
4
4
|
/**
|
|
5
5
|
* Defines value to be matched (key / attribute).
|
|
6
6
|
*/
|
|
7
|
-
export declare function sanitizeValue(log: ILogger, key: string, matcherDto: IMatcherDto, attributes
|
|
7
|
+
export declare function sanitizeValue(log: ILogger, key: string, matcherDto: IMatcherDto, attributes?: SplitIO.Attributes): string | number | boolean | (string | number)[] | import("../types").IDependencyMatcherValue | undefined;
|
|
@@ -4,4 +4,4 @@ import { ILogger } from '../../logger/types';
|
|
|
4
4
|
/**
|
|
5
5
|
* Sanitize matcher value
|
|
6
6
|
*/
|
|
7
|
-
export declare function sanitize(log: ILogger, matcherTypeID: number, value: string | number | boolean | Array<string | number> | undefined, dataType: string, attributes
|
|
7
|
+
export declare function sanitize(log: ILogger, matcherTypeID: number, value: string | number | boolean | Array<string | number> | undefined, dataType: string, attributes?: SplitIO.Attributes): string | number | boolean | (string | number)[] | IDependencyMatcherValue | undefined;
|
|
@@ -69,6 +69,7 @@ export declare const EVENTS_TRACKER_SUCCESS = 120;
|
|
|
69
69
|
export declare const IMPRESSIONS_TRACKER_SUCCESS = 121;
|
|
70
70
|
export declare const USER_CONSENT_UPDATED = 122;
|
|
71
71
|
export declare const USER_CONSENT_NOT_UPDATED = 123;
|
|
72
|
+
export declare const USER_CONSENT_INITIAL = 124;
|
|
72
73
|
export declare const ENGINE_VALUE_INVALID = 200;
|
|
73
74
|
export declare const ENGINE_VALUE_NO_ATTRIBUTES = 201;
|
|
74
75
|
export declare const CLIENT_NO_LISTENER = 202;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { IClientFactoryParams } from './types';
|
|
2
1
|
import { SplitIO } from '../types';
|
|
2
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
3
3
|
/**
|
|
4
4
|
* Creator of base client with getTreatments and track methods.
|
|
5
5
|
*/
|
|
6
|
-
export declare function clientFactory(params:
|
|
6
|
+
export declare function clientFactory(params: ISdkFactoryContext): SplitIO.IClient | SplitIO.IAsyncClient;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SplitIO } from '../types';
|
|
2
|
-
import {
|
|
2
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
3
3
|
/**
|
|
4
4
|
* Creates an Sdk client, i.e., a base client with status and destroy interface
|
|
5
5
|
*/
|
|
6
|
-
export declare function sdkClientFactory(params:
|
|
6
|
+
export declare function sdkClientFactory(params: ISdkFactoryContext, isSharedClient?: boolean): SplitIO.IClient | SplitIO.IAsyncClient;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ISdkClientFactoryParams } from './types';
|
|
2
1
|
import { SplitIO } from '../types';
|
|
2
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
3
3
|
/**
|
|
4
4
|
* Factory of client method for server-side SDKs (ISDK and IAsyncSDK)
|
|
5
5
|
*/
|
|
6
|
-
export declare function sdkClientMethodFactory(params:
|
|
6
|
+
export declare function sdkClientMethodFactory(params: ISdkFactoryContext): () => SplitIO.IClient | SplitIO.IAsyncClient;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { ISdkClientFactoryParams } from './types';
|
|
2
1
|
import { SplitIO } from '../types';
|
|
2
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
3
3
|
/**
|
|
4
4
|
* Factory of client method for the client-side API variant where TT is ignored and thus
|
|
5
5
|
* clients don't have a binded TT for the track method.
|
|
6
6
|
*/
|
|
7
|
-
export declare function sdkClientMethodCSFactory(params:
|
|
7
|
+
export declare function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey) => SplitIO.ICsClient;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { ISdkClientFactoryParams } from './types';
|
|
2
1
|
import { SplitIO } from '../types';
|
|
2
|
+
import { ISdkFactoryContext } from '../sdkFactory/types';
|
|
3
3
|
/**
|
|
4
4
|
* Factory of client method for the client-side (browser) variant of the Isomorphic JS SDK,
|
|
5
5
|
* where clients can have a binded TT for the track method, which is provided via the settings
|
|
6
6
|
* (default client) or the client method (shared clients).
|
|
7
7
|
*/
|
|
8
|
-
export declare function sdkClientMethodCSFactory(params:
|
|
8
|
+
export declare function sdkClientMethodCSFactory(params: ISdkFactoryContext): (key?: SplitIO.SplitKey, trafficType?: string) => SplitIO.ICsClient;
|
|
@@ -2,12 +2,21 @@ import { IIntegrationManager, IIntegrationFactoryParams } from '../integrations/
|
|
|
2
2
|
import { ISignalListener } from '../listeners/types';
|
|
3
3
|
import { ILogger } from '../logger/types';
|
|
4
4
|
import { ISdkReadinessManager } from '../readiness/types';
|
|
5
|
-
import { ISdkClientFactoryParams } from '../sdkClient/types';
|
|
6
5
|
import { IFetch, ISplitApi, IEventSourceConstructor } from '../services/types';
|
|
7
6
|
import { IStorageAsync, IStorageSync, ISplitsCacheSync, ISplitsCacheAsync, IStorageFactoryParams } from '../storages/types';
|
|
8
7
|
import { ISyncManager, ISyncManagerFactoryParams } from '../sync/types';
|
|
9
8
|
import { IImpressionObserver } from '../trackers/impressionObserver/types';
|
|
9
|
+
import { IImpressionsTracker, IEventTracker } from '../trackers/types';
|
|
10
10
|
import { SplitIO, ISettings, IEventEmitter } from '../types';
|
|
11
|
+
export interface ISdkFactoryContext {
|
|
12
|
+
storage: IStorageSync | IStorageAsync;
|
|
13
|
+
sdkReadinessManager: ISdkReadinessManager;
|
|
14
|
+
settings: ISettings;
|
|
15
|
+
impressionsTracker: IImpressionsTracker;
|
|
16
|
+
eventTracker: IEventTracker;
|
|
17
|
+
signalListener?: ISignalListener;
|
|
18
|
+
syncManager?: ISyncManager;
|
|
19
|
+
}
|
|
11
20
|
/**
|
|
12
21
|
* Environment related dependencies.
|
|
13
22
|
* These getters are called a fixed number of times per factory instantiation.
|
|
@@ -28,7 +37,7 @@ export interface ISdkFactoryParams {
|
|
|
28
37
|
splitApiFactory?: (settings: ISettings, platform: IPlatform) => ISplitApi;
|
|
29
38
|
syncManagerFactory?: (params: ISyncManagerFactoryParams) => ISyncManager;
|
|
30
39
|
sdkManagerFactory: (log: ILogger, splits: ISplitsCacheSync | ISplitsCacheAsync, sdkReadinessManager: ISdkReadinessManager) => SplitIO.IManager | SplitIO.IAsyncManager;
|
|
31
|
-
sdkClientMethodFactory: (params:
|
|
40
|
+
sdkClientMethodFactory: (params: ISdkFactoryContext) => ({
|
|
32
41
|
(): SplitIO.ICsClient;
|
|
33
42
|
(key: SplitIO.SplitKey, trafficType?: string | undefined): SplitIO.ICsClient;
|
|
34
43
|
} | (() => SplitIO.IClient) | (() => SplitIO.IAsyncClient));
|
|
@@ -38,5 +47,5 @@ export interface ISdkFactoryParams {
|
|
|
38
47
|
serviceApi: ISplitApi | undefined) => ISignalListener;
|
|
39
48
|
integrationsManagerFactory?: (params: IIntegrationFactoryParams) => IIntegrationManager | undefined;
|
|
40
49
|
impressionsObserverFactory?: () => IImpressionObserver;
|
|
41
|
-
extraProps?: (
|
|
50
|
+
extraProps?: (params: ISdkFactoryContext) => object;
|
|
42
51
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ImpressionDataType, EventDataType, StreamingEvent, Method, OperationType } from '../../sync/submitters/types';
|
|
1
|
+
import { ImpressionDataType, EventDataType, LastSync, HttpErrors, HttpLatencies, StreamingEvent, Method, OperationType, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
|
|
2
2
|
import { TelemetryCacheSync } from '../types';
|
|
3
3
|
export declare class TelemetryCacheInMemory implements TelemetryCacheSync {
|
|
4
4
|
private timeUntilReady?;
|
|
@@ -17,16 +17,14 @@ export declare class TelemetryCacheInMemory implements TelemetryCacheSync {
|
|
|
17
17
|
getEventStats(type: EventDataType): number;
|
|
18
18
|
recordEventStats(type: EventDataType, count: number): void;
|
|
19
19
|
private lastSync;
|
|
20
|
-
getLastSynchronization():
|
|
20
|
+
getLastSynchronization(): LastSync;
|
|
21
21
|
recordSuccessfulSync(resource: OperationType, timeMs: number): void;
|
|
22
22
|
private httpErrors;
|
|
23
|
-
popHttpErrors():
|
|
24
|
-
|
|
25
|
-
}>;
|
|
26
|
-
recordSyncError(resource: OperationType, status: number): void;
|
|
23
|
+
popHttpErrors(): HttpErrors;
|
|
24
|
+
recordHttpError(resource: OperationType, status: number): void;
|
|
27
25
|
private httpLatencies;
|
|
28
|
-
popHttpLatencies():
|
|
29
|
-
|
|
26
|
+
popHttpLatencies(): HttpLatencies;
|
|
27
|
+
recordHttpLatency(resource: OperationType, latencyMs: number): void;
|
|
30
28
|
private authRejections;
|
|
31
29
|
popAuthRejections(): number;
|
|
32
30
|
recordAuthRejections(): void;
|
|
@@ -43,9 +41,9 @@ export declare class TelemetryCacheInMemory implements TelemetryCacheSync {
|
|
|
43
41
|
getSessionLength(): number | undefined;
|
|
44
42
|
recordSessionLength(ms: number): void;
|
|
45
43
|
private exceptions;
|
|
46
|
-
popExceptions():
|
|
44
|
+
popExceptions(): MethodExceptions;
|
|
47
45
|
recordException(method: Method): void;
|
|
48
46
|
private latencies;
|
|
49
|
-
popLatencies():
|
|
47
|
+
popLatencies(): MethodLatencies;
|
|
50
48
|
recordLatency(method: Method, latencyMs: number): void;
|
|
51
49
|
}
|
|
@@ -20,5 +20,5 @@ export declare class RedisAdapter extends ioredis {
|
|
|
20
20
|
/**
|
|
21
21
|
* Parses the options into what we care about.
|
|
22
22
|
*/
|
|
23
|
-
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass }: Record<string, any>): object;
|
|
23
|
+
static _defineOptions({ connectionTimeout, operationTimeout, url, host, port, db, pass, tls }: Record<string, any>): object;
|
|
24
24
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { ILogger } from '../../logger/types';
|
|
2
|
+
import { Method, MethodExceptions, MethodLatencies } from '../../sync/submitters/types';
|
|
3
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
4
|
+
import { TelemetryCacheAsync } from '../types';
|
|
5
|
+
import { Redis } from 'ioredis';
|
|
6
|
+
export declare class TelemetryCacheInRedis implements TelemetryCacheAsync {
|
|
7
|
+
private readonly log;
|
|
8
|
+
private readonly keys;
|
|
9
|
+
private readonly redis;
|
|
10
|
+
/**
|
|
11
|
+
* Create a Telemetry cache that uses a storage wrapper.
|
|
12
|
+
* @param log Logger instance.
|
|
13
|
+
* @param keys Key builder.
|
|
14
|
+
* @param redis Redis client.
|
|
15
|
+
*/
|
|
16
|
+
constructor(log: ILogger, keys: KeyBuilderSS, redis: Redis);
|
|
17
|
+
recordLatency(method: Method, latencyMs: number): Promise<number>;
|
|
18
|
+
recordException(method: Method): Promise<number>;
|
|
19
|
+
popExceptions(): Promise<MethodExceptions>;
|
|
20
|
+
popLatencies(): Promise<MethodLatencies>;
|
|
21
|
+
}
|
|
@@ -1,2 +1,20 @@
|
|
|
1
|
-
|
|
1
|
+
import { ILogger } from '../../logger/types';
|
|
2
|
+
import { Method } from '../../sync/submitters/types';
|
|
3
|
+
import { KeyBuilderSS } from '../KeyBuilderSS';
|
|
4
|
+
import { IPluggableStorageWrapper, TelemetryCacheAsync } from '../types';
|
|
5
|
+
export declare class TelemetryCachePluggable implements TelemetryCacheAsync {
|
|
6
|
+
private readonly log;
|
|
7
|
+
private readonly keys;
|
|
8
|
+
private readonly wrapper;
|
|
9
|
+
/**
|
|
10
|
+
* Create a Telemetry cache that uses a storage wrapper.
|
|
11
|
+
* @param log Logger instance.
|
|
12
|
+
* @param keys Key builder.
|
|
13
|
+
* @param wrapper Adapted wrapper storage.
|
|
14
|
+
*/
|
|
15
|
+
constructor(log: ILogger, keys: KeyBuilderSS, wrapper: IPluggableStorageWrapper);
|
|
16
|
+
recordLatency(method: Method, latencyMs: number): Promise<number>;
|
|
17
|
+
recordException(method: Method): Promise<number>;
|
|
18
|
+
popExceptions(): void;
|
|
19
|
+
popLatencies(): void;
|
|
2
20
|
}
|