@splitsoftware/splitio-commons 1.2.1-rc.2 → 1.2.1-rc.5
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/cjs/integrations/ga/GoogleAnalyticsToSplit.js +4 -2
- package/cjs/integrations/ga/SplitToGoogleAnalytics.js +4 -2
- package/cjs/listeners/browser.js +14 -10
- package/cjs/logger/constants.js +6 -4
- package/cjs/logger/messages/error.js +3 -2
- package/cjs/logger/messages/info.js +3 -2
- package/cjs/sdkClient/client.js +10 -4
- package/cjs/sdkFactory/index.js +6 -4
- package/cjs/sdkFactory/userConsentProps.js +34 -0
- package/cjs/storages/KeyBuilderCS.js +11 -1
- package/cjs/storages/inLocalStorage/MySegmentsCacheInLocal.js +23 -3
- package/cjs/storages/inLocalStorage/index.js +1 -1
- package/cjs/storages/inMemory/ImpressionsCacheInMemory.js +15 -1
- package/cjs/storages/inMemory/InMemoryStorage.js +1 -1
- package/cjs/storages/inMemory/InMemoryStorageCS.js +1 -1
- package/cjs/storages/pluggable/index.js +2 -2
- package/cjs/sync/streaming/pushManager.js +9 -2
- package/cjs/sync/submitters/eventsSyncTask.js +9 -4
- package/cjs/sync/submitters/impressionsSyncTask.js +13 -1
- package/cjs/sync/syncManagerOnline.js +11 -7
- package/cjs/utils/consent.js +10 -0
- package/cjs/utils/constants/index.js +5 -1
- package/cjs/utils/settingsValidation/consent.js +16 -0
- package/cjs/utils/settingsValidation/impressionsMode.js +6 -6
- package/cjs/utils/settingsValidation/index.js +6 -1
- package/cjs/utils/settingsValidation/{runtime/browser.js → runtime.js} +1 -0
- package/esm/integrations/ga/GoogleAnalyticsToSplit.js +4 -2
- package/esm/integrations/ga/SplitToGoogleAnalytics.js +4 -2
- package/esm/listeners/browser.js +14 -10
- package/esm/logger/constants.js +4 -2
- package/esm/logger/messages/error.js +3 -2
- package/esm/logger/messages/info.js +3 -2
- package/esm/sdkClient/client.js +11 -5
- package/esm/sdkFactory/index.js +6 -4
- package/esm/sdkFactory/userConsentProps.js +30 -0
- package/esm/storages/KeyBuilderCS.js +11 -1
- package/esm/storages/inLocalStorage/MySegmentsCacheInLocal.js +23 -3
- package/esm/storages/inLocalStorage/index.js +1 -1
- package/esm/storages/inMemory/ImpressionsCacheInMemory.js +15 -1
- package/esm/storages/inMemory/InMemoryStorage.js +1 -1
- package/esm/storages/inMemory/InMemoryStorageCS.js +1 -1
- package/esm/storages/pluggable/index.js +2 -2
- package/esm/sync/streaming/pushManager.js +9 -2
- package/esm/sync/submitters/eventsSyncTask.js +10 -5
- package/esm/sync/submitters/impressionsSyncTask.js +13 -1
- package/esm/sync/syncManagerOnline.js +11 -7
- package/esm/utils/consent.js +6 -0
- package/esm/utils/constants/index.js +4 -0
- package/esm/utils/settingsValidation/consent.js +12 -0
- package/esm/utils/settingsValidation/impressionsMode.js +7 -7
- package/esm/utils/settingsValidation/index.js +6 -1
- package/esm/utils/settingsValidation/{runtime/browser.js → runtime.js} +1 -0
- package/package.json +1 -2
- package/src/integrations/ga/GoogleAnalyticsToSplit.ts +7 -4
- package/src/integrations/ga/SplitToGoogleAnalytics.ts +7 -4
- package/src/integrations/types.ts +5 -0
- package/src/listeners/browser.ts +13 -9
- package/src/logger/constants.ts +4 -2
- package/src/logger/messages/error.ts +3 -2
- package/src/logger/messages/info.ts +3 -2
- package/src/logger/types.ts +4 -4
- package/src/sdkClient/client.ts +7 -5
- package/src/sdkFactory/index.ts +6 -4
- package/src/sdkFactory/types.ts +2 -0
- package/src/sdkFactory/userConsentProps.ts +37 -0
- package/src/storages/KeyBuilderCS.ts +13 -1
- package/src/storages/inLocalStorage/MySegmentsCacheInLocal.ts +23 -3
- package/src/storages/inLocalStorage/index.ts +1 -1
- package/src/storages/inMemory/ImpressionsCacheInMemory.ts +22 -1
- package/src/storages/inMemory/InMemoryStorage.ts +1 -1
- package/src/storages/inMemory/InMemoryStorageCS.ts +1 -1
- package/src/storages/pluggable/index.ts +2 -2
- package/src/storages/types.ts +6 -2
- package/src/sync/streaming/pushManager.ts +11 -2
- package/src/sync/submitters/eventsSyncTask.ts +11 -5
- package/src/sync/submitters/impressionsSyncTask.ts +16 -1
- package/src/sync/syncManagerOnline.ts +13 -7
- package/src/sync/types.ts +4 -1
- package/src/types.ts +21 -0
- package/src/utils/consent.ts +8 -0
- package/src/utils/constants/index.ts +5 -0
- package/src/utils/settingsValidation/consent.ts +14 -0
- package/src/utils/settingsValidation/impressionsMode.ts +7 -8
- package/src/utils/settingsValidation/index.ts +7 -1
- package/src/utils/settingsValidation/runtime.ts +9 -0
- package/src/utils/settingsValidation/types.ts +2 -0
- package/types/integrations/ga/GoogleAnalyticsToSplit.d.ts +2 -2
- package/types/integrations/ga/SplitToGoogleAnalytics.d.ts +2 -3
- package/types/integrations/types.d.ts +4 -0
- package/types/logger/constants.d.ts +4 -2
- package/types/logger/types.d.ts +4 -4
- package/types/sdkFactory/types.d.ts +1 -0
- package/types/sdkFactory/userConsentProps.d.ts +6 -0
- package/types/storages/KeyBuilderCS.d.ts +2 -0
- package/types/storages/inMemory/ImpressionsCacheInMemory.d.ts +9 -0
- package/types/storages/types.d.ts +3 -1
- package/types/sync/types.d.ts +3 -0
- package/types/types.d.ts +21 -0
- package/types/utils/consent.d.ts +2 -0
- package/types/utils/constants/index.d.ts +3 -0
- package/types/utils/settingsValidation/consent.d.ts +5 -0
- package/types/utils/settingsValidation/impressionsMode.d.ts +1 -1
- package/types/utils/settingsValidation/runtime/browser.d.ts +2 -4
- package/types/utils/settingsValidation/runtime/node.d.ts +1 -4
- package/types/utils/settingsValidation/runtime.d.ts +2 -0
- package/types/utils/settingsValidation/types.d.ts +2 -0
- package/types/utils/settingsValidation/userConsent.d.ts +5 -0
- package/cjs/utils/settingsValidation/runtime/node.js +0 -22
- package/esm/utils/settingsValidation/runtime/node.js +0 -17
- package/src/utils/settingsValidation/runtime/browser.ts +0 -6
- package/src/utils/settingsValidation/runtime/node.ts +0 -22
package/src/storages/types.ts
CHANGED
|
@@ -298,7 +298,7 @@ export interface IRecorderCacheProducerSync<T> {
|
|
|
298
298
|
// @TODO names are inconsistent with spec
|
|
299
299
|
/* Checks if cache is empty. Returns true if the cache was just created or cleared */
|
|
300
300
|
isEmpty(): boolean
|
|
301
|
-
/*
|
|
301
|
+
/* Clears cache data */
|
|
302
302
|
clear(): void
|
|
303
303
|
/* Gets cache data */
|
|
304
304
|
state(): T
|
|
@@ -307,10 +307,13 @@ export interface IRecorderCacheProducerSync<T> {
|
|
|
307
307
|
|
|
308
308
|
export interface IImpressionsCacheSync extends IImpressionsCacheBase, IRecorderCacheProducerSync<ImpressionDTO[]> {
|
|
309
309
|
track(data: ImpressionDTO[]): void
|
|
310
|
+
/* Registers callback for full queue */
|
|
311
|
+
setOnFullQueueCb(cb: () => void): void
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
export interface IEventsCacheSync extends IEventsCacheBase, IRecorderCacheProducerSync<SplitIO.EventData[]> {
|
|
313
315
|
track(data: SplitIO.EventData, size?: number): boolean
|
|
316
|
+
/* Registers callback for full queue */
|
|
314
317
|
setOnFullQueueCb(cb: () => void): void
|
|
315
318
|
}
|
|
316
319
|
|
|
@@ -423,6 +426,7 @@ export type DataLoader = (storage: IStorageSync, matchingKey: string) => void
|
|
|
423
426
|
|
|
424
427
|
export interface IStorageFactoryParams {
|
|
425
428
|
log: ILogger,
|
|
429
|
+
impressionsQueueSize?: number,
|
|
426
430
|
eventsQueueSize?: number,
|
|
427
431
|
optimize?: boolean /* whether create the `impressionCounts` cache (OPTIMIZED impression mode) or not (DEBUG impression mode) */,
|
|
428
432
|
|
|
@@ -443,7 +447,7 @@ export interface IStorageFactoryParams {
|
|
|
443
447
|
export type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';
|
|
444
448
|
|
|
445
449
|
export type IStorageSyncFactory = {
|
|
446
|
-
type: StorageType,
|
|
450
|
+
readonly type: StorageType,
|
|
447
451
|
(params: IStorageFactoryParams): IStorageSync
|
|
448
452
|
}
|
|
449
453
|
|
|
@@ -71,6 +71,7 @@ export function pushManagerFactory(
|
|
|
71
71
|
// It is used to halt the `connectPush` process if it was in progress.
|
|
72
72
|
let disconnected: boolean | undefined;
|
|
73
73
|
// flag that indicates a PUSH_NONRETRYABLE_ERROR, condition with which starting pushManager again is ignored.
|
|
74
|
+
// true if STREAMING_DISABLED control event, or 'pushEnabled: false', or non-recoverable SSE or Auth errors.
|
|
74
75
|
let disabled: boolean | undefined; // `disabled` implies `disconnected === true`
|
|
75
76
|
|
|
76
77
|
/** PushManager functions related to initialization */
|
|
@@ -296,12 +297,15 @@ export function pushManagerFactory(
|
|
|
296
297
|
// Expose Event Emitter functionality and Event constants
|
|
297
298
|
Object.create(pushEmitter),
|
|
298
299
|
{
|
|
299
|
-
// Stop/pause push mode
|
|
300
|
+
// Stop/pause push mode.
|
|
301
|
+
// It doesn't emit events. Neither PUSH_SUBSYSTEM_DOWN to start polling.
|
|
300
302
|
stop() {
|
|
301
303
|
disconnectPush(); // `handleNonRetryableError` cannot be used as `stop`, because it emits PUSH_SUBSYSTEM_DOWN event, which starts polling.
|
|
302
304
|
if (userKey) this.remove(userKey); // Necessary to properly resume streaming in client-side (e.g., RN SDK transition to foreground).
|
|
303
305
|
},
|
|
304
|
-
|
|
306
|
+
|
|
307
|
+
// Start/resume push mode.
|
|
308
|
+
// It eventually emits PUSH_SUBSYSTEM_DOWN, that starts polling, or PUSH_SUBSYSTEM_UP, that executes a syncAll
|
|
305
309
|
start() {
|
|
306
310
|
// Guard condition to avoid calling `connectPush` again if the `start` method is called multiple times or if push has been disabled.
|
|
307
311
|
if (disabled || disconnected === false) return;
|
|
@@ -311,6 +315,11 @@ export function pushManagerFactory(
|
|
|
311
315
|
else setTimeout(connectPush); // server-side runs in next cycle as in client-side, for consistency with client-side
|
|
312
316
|
},
|
|
313
317
|
|
|
318
|
+
// true/false if start or stop was called last respectively
|
|
319
|
+
isRunning(){
|
|
320
|
+
return disconnected === false;
|
|
321
|
+
},
|
|
322
|
+
|
|
314
323
|
// [Only for client-side]
|
|
315
324
|
add(userKey: string, mySegmentsSyncTask: ISegmentsSyncTask) {
|
|
316
325
|
const hash = hashUserKey(userKey);
|
|
@@ -3,7 +3,9 @@ import { IPostEventsBulk } from '../../services/types';
|
|
|
3
3
|
import { ISyncTask, ITimeTracker } from '../types';
|
|
4
4
|
import { submitterSyncTaskFactory } from './submitterSyncTask';
|
|
5
5
|
import { ILogger } from '../../logger/types';
|
|
6
|
-
import {
|
|
6
|
+
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
7
|
+
|
|
8
|
+
const DATA_NAME = 'events';
|
|
7
9
|
|
|
8
10
|
/**
|
|
9
11
|
* Sync task that periodically posts tracked events
|
|
@@ -18,7 +20,7 @@ export function eventsSyncTaskFactory(
|
|
|
18
20
|
): ISyncTask {
|
|
19
21
|
|
|
20
22
|
// don't retry events.
|
|
21
|
-
const syncTask = submitterSyncTaskFactory(log, postEventsBulk, eventsCache, eventsPushRate,
|
|
23
|
+
const syncTask = submitterSyncTaskFactory(log, postEventsBulk, eventsCache, eventsPushRate, DATA_NAME, latencyTracker);
|
|
22
24
|
|
|
23
25
|
// Set a timer for the first push of events,
|
|
24
26
|
if (eventsFirstPushWindow > 0) {
|
|
@@ -34,10 +36,14 @@ export function eventsSyncTaskFactory(
|
|
|
34
36
|
};
|
|
35
37
|
}
|
|
36
38
|
|
|
37
|
-
// register
|
|
39
|
+
// register events submitter to be executed when events cache is full
|
|
38
40
|
eventsCache.setOnFullQueueCb(() => {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
if (syncTask.isRunning()) {
|
|
42
|
+
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
|
|
43
|
+
syncTask.execute();
|
|
44
|
+
}
|
|
45
|
+
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
|
|
46
|
+
// Data will be sent when submitter is resumed.
|
|
41
47
|
});
|
|
42
48
|
|
|
43
49
|
return syncTask;
|
|
@@ -6,6 +6,9 @@ import { ImpressionDTO } from '../../types';
|
|
|
6
6
|
import { submitterSyncTaskFactory } from './submitterSyncTask';
|
|
7
7
|
import { ImpressionsPayload } from './types';
|
|
8
8
|
import { ILogger } from '../../logger/types';
|
|
9
|
+
import { SUBMITTERS_PUSH_FULL_QUEUE } from '../../logger/constants';
|
|
10
|
+
|
|
11
|
+
const DATA_NAME = 'impressions';
|
|
9
12
|
|
|
10
13
|
/**
|
|
11
14
|
* Converts `impressions` data from cache into request payload.
|
|
@@ -50,5 +53,17 @@ export function impressionsSyncTaskFactory(
|
|
|
50
53
|
): ISyncTask {
|
|
51
54
|
|
|
52
55
|
// retry impressions only once.
|
|
53
|
-
|
|
56
|
+
const syncTask = submitterSyncTaskFactory(log, postTestImpressionsBulk, impressionsCache, impressionsRefreshRate, DATA_NAME, latencyTracker, fromImpressionsCollector.bind(undefined, sendLabels), 1);
|
|
57
|
+
|
|
58
|
+
// register impressions submitter to be executed when impressions cache is full
|
|
59
|
+
impressionsCache.setOnFullQueueCb(() => {
|
|
60
|
+
if (syncTask.isRunning()) {
|
|
61
|
+
log.info(SUBMITTERS_PUSH_FULL_QUEUE, [DATA_NAME]);
|
|
62
|
+
syncTask.execute();
|
|
63
|
+
}
|
|
64
|
+
// If submitter is stopped (e.g., user consent declined or unknown, or app state offline), we don't send the data.
|
|
65
|
+
// Data will be sent when submitter is resumed.
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
return syncTask;
|
|
54
69
|
}
|
|
@@ -6,6 +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 '../utils/consent';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Online SyncManager factory.
|
|
@@ -25,7 +26,7 @@ export function syncManagerOnlineFactory(
|
|
|
25
26
|
*/
|
|
26
27
|
return function (params: ISyncManagerFactoryParams): ISyncManagerCS {
|
|
27
28
|
|
|
28
|
-
const { log, streamingEnabled } = params
|
|
29
|
+
const { settings, settings: { log, streamingEnabled } } = params;
|
|
29
30
|
|
|
30
31
|
/** Polling Manager */
|
|
31
32
|
const pollingManager = pollingManagerFactory && pollingManagerFactory(params);
|
|
@@ -39,7 +40,6 @@ export function syncManagerOnlineFactory(
|
|
|
39
40
|
// It is not inyected as push and polling managers, because at the moment it is required
|
|
40
41
|
const submitter = submitterManagerFactory(params);
|
|
41
42
|
|
|
42
|
-
|
|
43
43
|
/** Sync Manager logic */
|
|
44
44
|
|
|
45
45
|
function startPolling() {
|
|
@@ -69,12 +69,18 @@ export function syncManagerOnlineFactory(
|
|
|
69
69
|
let startFirstTime = true; // flag to distinguish calling the `start` method for the first time, to support pausing and resuming the synchronization
|
|
70
70
|
|
|
71
71
|
return {
|
|
72
|
+
// Exposed for fine-grained control of synchronization.
|
|
73
|
+
// E.g.: user consent, app state changes (Page hide, Foreground/Background, Online/Offline).
|
|
74
|
+
pollingManager,
|
|
72
75
|
pushManager,
|
|
76
|
+
submitter,
|
|
73
77
|
|
|
74
78
|
/**
|
|
75
79
|
* Method used to start the syncManager for the first time, or resume it after being stopped.
|
|
76
80
|
*/
|
|
77
81
|
start() {
|
|
82
|
+
running = true;
|
|
83
|
+
|
|
78
84
|
// start syncing splits and segments
|
|
79
85
|
if (pollingManager) {
|
|
80
86
|
if (pushManager) {
|
|
@@ -90,21 +96,21 @@ export function syncManagerOnlineFactory(
|
|
|
90
96
|
}
|
|
91
97
|
|
|
92
98
|
// start periodic data recording (events, impressions, telemetry).
|
|
93
|
-
if (
|
|
94
|
-
running = true;
|
|
99
|
+
if (isConsentGranted(settings)) submitter.start();
|
|
95
100
|
},
|
|
96
101
|
|
|
97
102
|
/**
|
|
98
103
|
* Method used to stop/pause the syncManager.
|
|
99
104
|
*/
|
|
100
105
|
stop() {
|
|
106
|
+
running = false;
|
|
107
|
+
|
|
101
108
|
// stop syncing
|
|
102
109
|
if (pushManager) pushManager.stop();
|
|
103
110
|
if (pollingManager && pollingManager.isRunning()) pollingManager.stop();
|
|
104
111
|
|
|
105
112
|
// stop periodic data recording (events, impressions, telemetry).
|
|
106
|
-
|
|
107
|
-
running = false;
|
|
113
|
+
submitter.stop();
|
|
108
114
|
},
|
|
109
115
|
|
|
110
116
|
isRunning() {
|
|
@@ -112,7 +118,7 @@ export function syncManagerOnlineFactory(
|
|
|
112
118
|
},
|
|
113
119
|
|
|
114
120
|
flush() {
|
|
115
|
-
if (
|
|
121
|
+
if (isConsentGranted(settings)) return submitter.execute();
|
|
116
122
|
else return Promise.resolve();
|
|
117
123
|
},
|
|
118
124
|
|
package/src/sync/types.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { IPlatform } from '../sdkFactory/types';
|
|
|
3
3
|
import { ISplitApi } from '../services/types';
|
|
4
4
|
import { IStorageSync } from '../storages/types';
|
|
5
5
|
import { ISettings } from '../types';
|
|
6
|
+
import { IPollingManager } from './polling/types';
|
|
6
7
|
import { IPushManager } from './streaming/types';
|
|
7
8
|
|
|
8
9
|
export interface ITask<Input extends any[] = []> {
|
|
@@ -43,7 +44,9 @@ export interface ITimeTracker {
|
|
|
43
44
|
|
|
44
45
|
export interface ISyncManager extends ITask {
|
|
45
46
|
flush(): Promise<any>,
|
|
46
|
-
pushManager?: IPushManager
|
|
47
|
+
pushManager?: IPushManager,
|
|
48
|
+
pollingManager?: IPollingManager,
|
|
49
|
+
submitter?: ISyncTask
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
export interface ISyncManagerCS extends ISyncManager {
|
package/src/types.ts
CHANGED
|
@@ -54,6 +54,11 @@ type EventConsts = {
|
|
|
54
54
|
* @typedef {string} SDKMode
|
|
55
55
|
*/
|
|
56
56
|
export type SDKMode = 'standalone' | 'consumer' | 'localhost' | 'consumer_partial';
|
|
57
|
+
/**
|
|
58
|
+
* User consent status.
|
|
59
|
+
* @typedef {string} ConsentStatus
|
|
60
|
+
*/
|
|
61
|
+
export type ConsentStatus = 'GRANTED' | 'DECLINED' | 'UNKNOWN';
|
|
57
62
|
/**
|
|
58
63
|
* Settings interface. This is a representation of the settings the SDK expose, that's why
|
|
59
64
|
* most of it's props are readonly. Only features should be rewritten when localhost mode is active.
|
|
@@ -73,6 +78,7 @@ export interface ISettings {
|
|
|
73
78
|
readonly scheduler: {
|
|
74
79
|
featuresRefreshRate: number,
|
|
75
80
|
impressionsRefreshRate: number,
|
|
81
|
+
impressionsQueueSize: number,
|
|
76
82
|
metricsRefreshRate: number,
|
|
77
83
|
segmentsRefreshRate: number,
|
|
78
84
|
offlineRefreshRate: number,
|
|
@@ -110,6 +116,7 @@ export interface ISettings {
|
|
|
110
116
|
},
|
|
111
117
|
readonly log: ILogger
|
|
112
118
|
readonly impressionListener?: unknown
|
|
119
|
+
readonly userConsent?: ConsentStatus
|
|
113
120
|
}
|
|
114
121
|
/**
|
|
115
122
|
* Log levels.
|
|
@@ -255,6 +262,13 @@ interface INodeBasicSettings extends ISharedSettings {
|
|
|
255
262
|
* @default 300
|
|
256
263
|
*/
|
|
257
264
|
impressionsRefreshRate?: number,
|
|
265
|
+
/**
|
|
266
|
+
* The maximum number of impression items we want to queue. If we queue more values, it will trigger a flush and reset the timer.
|
|
267
|
+
* If you use a 0 here, the queue will have no maximum size.
|
|
268
|
+
* @property {number} impressionsQueueSize
|
|
269
|
+
* @default 30000
|
|
270
|
+
*/
|
|
271
|
+
impressionsQueueSize?: number,
|
|
258
272
|
/**
|
|
259
273
|
* The SDK sends diagnostic metrics to Split servers. This parameters controls this metric flush period in seconds.
|
|
260
274
|
* @property {number} metricsRefreshRate
|
|
@@ -769,6 +783,13 @@ export namespace SplitIO {
|
|
|
769
783
|
* @default 60
|
|
770
784
|
*/
|
|
771
785
|
impressionsRefreshRate?: number,
|
|
786
|
+
/**
|
|
787
|
+
* The maximum number of impression items we want to queue. If we queue more values, it will trigger a flush and reset the timer.
|
|
788
|
+
* If you use a 0 here, the queue will have no maximum size.
|
|
789
|
+
* @property {number} impressionsQueueSize
|
|
790
|
+
* @default 30000
|
|
791
|
+
*/
|
|
792
|
+
impressionsQueueSize?: number,
|
|
772
793
|
/**
|
|
773
794
|
* The SDK sends diagnostic metrics to Split servers. This parameters controls this metric flush period in seconds.
|
|
774
795
|
* @property {number} metricsRefreshRate
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ISettings } from '../types';
|
|
2
|
+
import { CONSENT_GRANTED } from './constants';
|
|
3
|
+
|
|
4
|
+
export function isConsentGranted(settings: ISettings) {
|
|
5
|
+
const userConsent = settings.userConsent;
|
|
6
|
+
// undefined userConsent is handled as granted (default)
|
|
7
|
+
return !userConsent || userConsent === CONSENT_GRANTED;
|
|
8
|
+
}
|
|
@@ -32,3 +32,8 @@ export const STORAGE_MEMORY: StorageType = 'MEMORY';
|
|
|
32
32
|
export const STORAGE_LOCALSTORAGE: StorageType = 'LOCALSTORAGE';
|
|
33
33
|
export const STORAGE_REDIS: StorageType = 'REDIS';
|
|
34
34
|
export const STORAGE_PLUGGABLE: StorageType = 'PLUGGABLE';
|
|
35
|
+
|
|
36
|
+
// User consent
|
|
37
|
+
export const CONSENT_GRANTED = 'GRANTED'; // The user has granted consent for tracking events and impressions
|
|
38
|
+
export const CONSENT_DECLINED = 'DECLINED'; // The user has declined consent for tracking events and impressions
|
|
39
|
+
export const CONSENT_UNKNOWN = 'UNKNOWN'; // The user has neither granted nor declined consent for tracking events and impressions
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ERROR_INVALID_CONFIG_PARAM } from '../../logger/constants';
|
|
2
|
+
import { ILogger } from '../../logger/types';
|
|
3
|
+
import { CONSENT_DECLINED, CONSENT_GRANTED, CONSENT_UNKNOWN } from '../constants';
|
|
4
|
+
|
|
5
|
+
const userConsentValues = [CONSENT_DECLINED, CONSENT_GRANTED, CONSENT_UNKNOWN];
|
|
6
|
+
|
|
7
|
+
export function validateConsent({ userConsent, log }: { userConsent: any, log: ILogger }) {
|
|
8
|
+
if (typeof userConsent === 'string') userConsent = userConsent.toUpperCase();
|
|
9
|
+
|
|
10
|
+
if (userConsentValues.indexOf(userConsent) > -1) return userConsent;
|
|
11
|
+
|
|
12
|
+
log.error(ERROR_INVALID_CONFIG_PARAM, ['userConsent', userConsentValues, CONSENT_GRANTED]);
|
|
13
|
+
return CONSENT_GRANTED;
|
|
14
|
+
}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ERROR_INVALID_CONFIG_PARAM } from '../../logger/constants';
|
|
2
2
|
import { ILogger } from '../../logger/types';
|
|
3
3
|
import { SplitIO } from '../../types';
|
|
4
4
|
import { DEBUG, OPTIMIZED } from '../constants';
|
|
5
5
|
|
|
6
|
-
export function validImpressionsMode(log: ILogger, impressionsMode:
|
|
7
|
-
impressionsMode = impressionsMode.toUpperCase();
|
|
8
|
-
if ([DEBUG, OPTIMIZED].indexOf(impressionsMode) === -1) {
|
|
9
|
-
log.error(ERROR_INVALID_IMPRESSIONS_MODE, [[DEBUG, OPTIMIZED], OPTIMIZED]);
|
|
10
|
-
impressionsMode = OPTIMIZED;
|
|
11
|
-
}
|
|
6
|
+
export function validImpressionsMode(log: ILogger, impressionsMode: any): SplitIO.ImpressionsMode {
|
|
7
|
+
if (typeof impressionsMode === 'string') impressionsMode = impressionsMode.toUpperCase();
|
|
12
8
|
|
|
13
|
-
|
|
9
|
+
if ([DEBUG, OPTIMIZED].indexOf(impressionsMode) > -1) return impressionsMode;
|
|
10
|
+
|
|
11
|
+
log.error(ERROR_INVALID_CONFIG_PARAM, ['impressionsMode', [DEBUG, OPTIMIZED], OPTIMIZED]);
|
|
12
|
+
return OPTIMIZED;
|
|
14
13
|
}
|
|
@@ -38,6 +38,8 @@ const base = {
|
|
|
38
38
|
eventsPushRate: 60,
|
|
39
39
|
// how many events will be queued before flushing
|
|
40
40
|
eventsQueueSize: 500,
|
|
41
|
+
// how many impressions will be queued before flushing
|
|
42
|
+
impressionsQueueSize: 30000,
|
|
41
43
|
// backoff base seconds to wait before re attempting to connect to push notifications
|
|
42
44
|
pushRetryBackoffBase: 1,
|
|
43
45
|
},
|
|
@@ -95,7 +97,7 @@ function fromSecondsToMillis(n: number) {
|
|
|
95
97
|
*/
|
|
96
98
|
export function settingsValidation(config: unknown, validationParams: ISettingsValidationParams) {
|
|
97
99
|
|
|
98
|
-
const { defaults, runtime, storage, integrations, logger, localhost } = validationParams;
|
|
100
|
+
const { defaults, runtime, storage, integrations, logger, localhost, consent } = validationParams;
|
|
99
101
|
|
|
100
102
|
// creates a settings object merging base, defaults and config objects.
|
|
101
103
|
const withDefaults = merge({}, base, defaults, config) as ISettings;
|
|
@@ -159,5 +161,9 @@ export function settingsValidation(config: unknown, validationParams: ISettingsV
|
|
|
159
161
|
// ensure a valid impressionsMode
|
|
160
162
|
withDefaults.sync.impressionsMode = validImpressionsMode(log, withDefaults.sync.impressionsMode);
|
|
161
163
|
|
|
164
|
+
// ensure a valid user consent value
|
|
165
|
+
// @ts-ignore, modify readonly prop
|
|
166
|
+
withDefaults.userConsent = consent(withDefaults);
|
|
167
|
+
|
|
162
168
|
return withDefaults;
|
|
163
169
|
}
|
|
@@ -20,4 +20,6 @@ export interface ISettingsValidationParams {
|
|
|
20
20
|
logger: (settings: ISettings) => ISettings['log'],
|
|
21
21
|
/** Localhost mode validator (`settings.sync.localhostMode`) */
|
|
22
22
|
localhost?: (settings: ISettings) => ISettings['sync']['localhostMode'],
|
|
23
|
+
/** User consent validator (`settings.userConsent`) */
|
|
24
|
+
consent: (settings: ISettings) => ISettings['userConsent'],
|
|
23
25
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { IntegrationFactory } from '../types';
|
|
2
2
|
import { GoogleAnalyticsToSplitOptions } from './types';
|
|
3
|
-
export declare function GoogleAnalyticsToSplit(options: GoogleAnalyticsToSplitOptions):
|
|
3
|
+
export declare function GoogleAnalyticsToSplit(options: GoogleAnalyticsToSplitOptions): IntegrationFactory;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SplitToGa } from './SplitToGa';
|
|
1
|
+
import { IntegrationFactory } from '../types';
|
|
3
2
|
import { SplitToGoogleAnalyticsOptions } from './types';
|
|
4
|
-
export declare function SplitToGoogleAnalytics(options?: SplitToGoogleAnalyticsOptions):
|
|
3
|
+
export declare function SplitToGoogleAnalytics(options?: SplitToGoogleAnalyticsOptions): IntegrationFactory;
|
|
@@ -60,13 +60,14 @@ export declare const STREAMING_RECONNECT = 111;
|
|
|
60
60
|
export declare const STREAMING_CONNECTING = 112;
|
|
61
61
|
export declare const STREAMING_DISABLED = 113;
|
|
62
62
|
export declare const STREAMING_DISCONNECTING = 114;
|
|
63
|
-
export declare const
|
|
63
|
+
export declare const SUBMITTERS_PUSH_FULL_QUEUE = 115;
|
|
64
64
|
export declare const SUBMITTERS_PUSH = 116;
|
|
65
65
|
export declare const SYNC_START_POLLING = 117;
|
|
66
66
|
export declare const SYNC_CONTINUE_POLLING = 118;
|
|
67
67
|
export declare const SYNC_STOP_POLLING = 119;
|
|
68
68
|
export declare const EVENTS_TRACKER_SUCCESS = 120;
|
|
69
69
|
export declare const IMPRESSIONS_TRACKER_SUCCESS = 121;
|
|
70
|
+
export declare const USER_CONSENT_UPDATED = 122;
|
|
70
71
|
export declare const ENGINE_VALUE_INVALID = 200;
|
|
71
72
|
export declare const ENGINE_VALUE_NO_ATTRIBUTES = 201;
|
|
72
73
|
export declare const CLIENT_NO_LISTENER = 202;
|
|
@@ -112,10 +113,11 @@ export declare const ERROR_INVALID_KEY_OBJECT = 317;
|
|
|
112
113
|
export declare const ERROR_INVALID = 318;
|
|
113
114
|
export declare const ERROR_EMPTY = 319;
|
|
114
115
|
export declare const ERROR_EMPTY_ARRAY = 320;
|
|
115
|
-
export declare const
|
|
116
|
+
export declare const ERROR_INVALID_CONFIG_PARAM = 321;
|
|
116
117
|
export declare const ERROR_HTTP = 322;
|
|
117
118
|
export declare const ERROR_LOCALHOST_MODULE_REQUIRED = 323;
|
|
118
119
|
export declare const ERROR_STORAGE_INVALID = 324;
|
|
120
|
+
export declare const ERROR_NOT_BOOLEAN = 325;
|
|
119
121
|
export declare const LOG_PREFIX_SETTINGS = "settings";
|
|
120
122
|
export declare const LOG_PREFIX_INSTANTIATION = "Factory instantiation";
|
|
121
123
|
export declare const LOG_PREFIX_ENGINE = "engine";
|
package/types/logger/types.d.ts
CHANGED
|
@@ -6,12 +6,12 @@ export interface ILoggerOptions {
|
|
|
6
6
|
}
|
|
7
7
|
export interface ILogger {
|
|
8
8
|
setLogLevel(logLevel: LogLevel): void;
|
|
9
|
-
debug(msg:
|
|
9
|
+
debug(msg: any): void;
|
|
10
10
|
debug(msg: string | number, args?: any[]): void;
|
|
11
|
-
info(msg:
|
|
11
|
+
info(msg: any): void;
|
|
12
12
|
info(msg: string | number, args?: any[]): void;
|
|
13
|
-
warn(msg:
|
|
13
|
+
warn(msg: any): void;
|
|
14
14
|
warn(msg: string | number, args?: any[]): void;
|
|
15
|
-
error(msg:
|
|
15
|
+
error(msg: any): void;
|
|
16
16
|
error(msg: string | number, args?: any[]): void;
|
|
17
17
|
}
|
|
@@ -39,4 +39,5 @@ export interface ISdkFactoryParams {
|
|
|
39
39
|
impressionListener?: SplitIO.IImpressionListener;
|
|
40
40
|
integrationsManagerFactory?: (params: IIntegrationFactoryParams) => IIntegrationManager | undefined;
|
|
41
41
|
impressionsObserverFactory?: () => IImpressionObserver;
|
|
42
|
+
extraProps?: (settings: ISettings, syncManager?: ISyncManager) => object;
|
|
42
43
|
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ISyncManager } from '../sync/types';
|
|
2
|
+
import { ISettings } from '../types';
|
|
3
|
+
export declare function userConsentProps(settings: ISettings, syncManager?: ISyncManager): {
|
|
4
|
+
setUserConsent(consent: unknown): boolean;
|
|
5
|
+
getUserConsent(): import("../types").ConsentStatus | undefined;
|
|
6
|
+
};
|
|
@@ -8,6 +8,8 @@ export declare class KeyBuilderCS extends KeyBuilder {
|
|
|
8
8
|
*/
|
|
9
9
|
buildSegmentNameKey(segmentName: string): string;
|
|
10
10
|
extractSegmentName(builtSegmentKeyName: string): string | undefined;
|
|
11
|
+
buildOldSegmentNameKey(segmentName: string): string;
|
|
12
|
+
extractOldSegmentKey(builtSegmentKeyName: string): string | undefined;
|
|
11
13
|
buildLastUpdatedKey(): string;
|
|
12
14
|
isSplitsCacheKey(key: string): boolean;
|
|
13
15
|
buildSplitsFilterQueryKey(): string;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { IImpressionsCacheSync } from '../types';
|
|
2
2
|
import { ImpressionDTO } from '../../types';
|
|
3
3
|
export declare class ImpressionsCacheInMemory implements IImpressionsCacheSync {
|
|
4
|
+
private onFullQueue?;
|
|
5
|
+
private readonly maxQueue;
|
|
4
6
|
private queue;
|
|
7
|
+
/**
|
|
8
|
+
*
|
|
9
|
+
* @param impressionsQueueSize number of queued impressions to call onFullQueueCb.
|
|
10
|
+
* Default value is 0, that means no maximum value, in case we want to avoid this being triggered.
|
|
11
|
+
*/
|
|
12
|
+
constructor(impressionsQueueSize?: number);
|
|
13
|
+
setOnFullQueueCb(cb: () => void): void;
|
|
5
14
|
/**
|
|
6
15
|
* Store impressions in sequential order
|
|
7
16
|
*/
|
|
@@ -269,6 +269,7 @@ export interface IRecorderCacheProducerSync<T> {
|
|
|
269
269
|
}
|
|
270
270
|
export interface IImpressionsCacheSync extends IImpressionsCacheBase, IRecorderCacheProducerSync<ImpressionDTO[]> {
|
|
271
271
|
track(data: ImpressionDTO[]): void;
|
|
272
|
+
setOnFullQueueCb(cb: () => void): void;
|
|
272
273
|
}
|
|
273
274
|
export interface IEventsCacheSync extends IEventsCacheBase, IRecorderCacheProducerSync<SplitIO.EventData[]> {
|
|
274
275
|
track(data: SplitIO.EventData, size?: number): boolean;
|
|
@@ -335,6 +336,7 @@ export declare type IStorageAsync = IStorageBase<ISplitsCacheAsync, ISegmentsCac
|
|
|
335
336
|
export declare type DataLoader = (storage: IStorageSync, matchingKey: string) => void;
|
|
336
337
|
export interface IStorageFactoryParams {
|
|
337
338
|
log: ILogger;
|
|
339
|
+
impressionsQueueSize?: number;
|
|
338
340
|
eventsQueueSize?: number;
|
|
339
341
|
optimize?: boolean;
|
|
340
342
|
matchingKey?: string;
|
|
@@ -345,7 +347,7 @@ export interface IStorageFactoryParams {
|
|
|
345
347
|
}
|
|
346
348
|
export declare type StorageType = 'MEMORY' | 'LOCALSTORAGE' | 'REDIS' | 'PLUGGABLE';
|
|
347
349
|
export declare type IStorageSyncFactory = {
|
|
348
|
-
type: StorageType;
|
|
350
|
+
readonly type: StorageType;
|
|
349
351
|
(params: IStorageFactoryParams): IStorageSync;
|
|
350
352
|
};
|
|
351
353
|
export declare type IStorageAsyncFactory = {
|
package/types/sync/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { IPlatform } from '../sdkFactory/types';
|
|
|
3
3
|
import { ISplitApi } from '../services/types';
|
|
4
4
|
import { IStorageSync } from '../storages/types';
|
|
5
5
|
import { ISettings } from '../types';
|
|
6
|
+
import { IPollingManager } from './polling/types';
|
|
6
7
|
import { IPushManager } from './streaming/types';
|
|
7
8
|
export interface ITask<Input extends any[] = []> {
|
|
8
9
|
/**
|
|
@@ -39,6 +40,8 @@ export interface ITimeTracker {
|
|
|
39
40
|
export interface ISyncManager extends ITask {
|
|
40
41
|
flush(): Promise<any>;
|
|
41
42
|
pushManager?: IPushManager;
|
|
43
|
+
pollingManager?: IPollingManager;
|
|
44
|
+
submitter?: ISyncTask;
|
|
42
45
|
}
|
|
43
46
|
export interface ISyncManagerCS extends ISyncManager {
|
|
44
47
|
shared(matchingKey: string, readinessManager: IReadinessManager, storage: IStorageSync): ISyncManager | undefined;
|
package/types/types.d.ts
CHANGED
|
@@ -48,6 +48,11 @@ declare type EventConsts = {
|
|
|
48
48
|
* @typedef {string} SDKMode
|
|
49
49
|
*/
|
|
50
50
|
export declare type SDKMode = 'standalone' | 'consumer' | 'localhost' | 'consumer_partial';
|
|
51
|
+
/**
|
|
52
|
+
* User consent status.
|
|
53
|
+
* @typedef {string} ConsentStatus
|
|
54
|
+
*/
|
|
55
|
+
export declare type ConsentStatus = 'GRANTED' | 'DECLINED' | 'UNKNOWN';
|
|
51
56
|
/**
|
|
52
57
|
* Settings interface. This is a representation of the settings the SDK expose, that's why
|
|
53
58
|
* most of it's props are readonly. Only features should be rewritten when localhost mode is active.
|
|
@@ -67,6 +72,7 @@ export interface ISettings {
|
|
|
67
72
|
readonly scheduler: {
|
|
68
73
|
featuresRefreshRate: number;
|
|
69
74
|
impressionsRefreshRate: number;
|
|
75
|
+
impressionsQueueSize: number;
|
|
70
76
|
metricsRefreshRate: number;
|
|
71
77
|
segmentsRefreshRate: number;
|
|
72
78
|
offlineRefreshRate: number;
|
|
@@ -104,6 +110,7 @@ export interface ISettings {
|
|
|
104
110
|
};
|
|
105
111
|
readonly log: ILogger;
|
|
106
112
|
readonly impressionListener?: unknown;
|
|
113
|
+
readonly userConsent?: ConsentStatus;
|
|
107
114
|
}
|
|
108
115
|
/**
|
|
109
116
|
* Log levels.
|
|
@@ -249,6 +256,13 @@ interface INodeBasicSettings extends ISharedSettings {
|
|
|
249
256
|
* @default 300
|
|
250
257
|
*/
|
|
251
258
|
impressionsRefreshRate?: number;
|
|
259
|
+
/**
|
|
260
|
+
* The maximum number of impression items we want to queue. If we queue more values, it will trigger a flush and reset the timer.
|
|
261
|
+
* If you use a 0 here, the queue will have no maximum size.
|
|
262
|
+
* @property {number} impressionsQueueSize
|
|
263
|
+
* @default 30000
|
|
264
|
+
*/
|
|
265
|
+
impressionsQueueSize?: number;
|
|
252
266
|
/**
|
|
253
267
|
* The SDK sends diagnostic metrics to Split servers. This parameters controls this metric flush period in seconds.
|
|
254
268
|
* @property {number} metricsRefreshRate
|
|
@@ -766,6 +780,13 @@ export declare namespace SplitIO {
|
|
|
766
780
|
* @default 60
|
|
767
781
|
*/
|
|
768
782
|
impressionsRefreshRate?: number;
|
|
783
|
+
/**
|
|
784
|
+
* The maximum number of impression items we want to queue. If we queue more values, it will trigger a flush and reset the timer.
|
|
785
|
+
* If you use a 0 here, the queue will have no maximum size.
|
|
786
|
+
* @property {number} impressionsQueueSize
|
|
787
|
+
* @default 30000
|
|
788
|
+
*/
|
|
789
|
+
impressionsQueueSize?: number;
|
|
769
790
|
/**
|
|
770
791
|
* The SDK sends diagnostic metrics to Split servers. This parameters controls this metric flush period in seconds.
|
|
771
792
|
* @property {number} metricsRefreshRate
|
|
@@ -20,3 +20,6 @@ export declare const STORAGE_MEMORY: StorageType;
|
|
|
20
20
|
export declare const STORAGE_LOCALSTORAGE: StorageType;
|
|
21
21
|
export declare const STORAGE_REDIS: StorageType;
|
|
22
22
|
export declare const STORAGE_PLUGGABLE: StorageType;
|
|
23
|
+
export declare const CONSENT_GRANTED = "GRANTED";
|
|
24
|
+
export declare const CONSENT_DECLINED = "DECLINED";
|
|
25
|
+
export declare const CONSENT_UNKNOWN = "UNKNOWN";
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ILogger } from '../../logger/types';
|
|
2
2
|
import { SplitIO } from '../../types';
|
|
3
|
-
export declare function validImpressionsMode(log: ILogger, impressionsMode:
|
|
3
|
+
export declare function validImpressionsMode(log: ILogger, impressionsMode: any): SplitIO.ImpressionsMode;
|