@splitsoftware/splitio-commons 1.4.2-rc.4 → 1.4.2-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/CHANGES.txt +7 -4
- package/cjs/integrations/ga/GaToSplit.js +12 -11
- package/cjs/listeners/browser.js +11 -26
- package/esm/integrations/ga/GaToSplit.js +12 -11
- package/esm/listeners/browser.js +11 -26
- package/package.json +1 -1
- package/src/integrations/ga/GaToSplit.ts +14 -8
- package/src/integrations/ga/autoRequire.js +33 -0
- package/src/integrations/ga/types.ts +13 -2
- package/src/listeners/browser.ts +10 -26
- package/types/integrations/ga/types.d.ts +13 -2
- package/types/listeners/browser.d.ts +5 -5
package/CHANGES.txt
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
1.
|
|
2
|
-
- Added `
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
1.6.0 (June XX, 2022)
|
|
2
|
+
- Added `autoRequire` configuration option to the Google Analytics to Split integration (See https://help.split.io/hc/en-us/articles/360040838752#set-up-with-gtm-and-gtag.js).
|
|
3
|
+
|
|
4
|
+
1.5.0 (June 24, 2022)
|
|
5
|
+
- Added a new config option to control the tasks that listen or poll for updates on feature flags and segments, via the new config sync.enabled . Running online Split will always pull the most recent updates upon initialization, this only affects updates fetching on a running instance. Useful when a consistent session experience is a must or to save resources when updates are not being used.
|
|
6
|
+
- Updated telemetry logic to track the anonymous config for user consent flag set to declined or unknown.
|
|
7
|
+
- Updated submitters logic, to avoid duplicating the post of impressions to Split cloud when the SDK is destroyed while its periodic post of impressions is running.
|
|
5
8
|
|
|
6
9
|
1.4.1 (June 13, 2022)
|
|
7
10
|
- Bugfixing - Updated submitters logic, to avoid dropping impressions and events that are being tracked while POST request is pending.
|
|
@@ -10,23 +10,24 @@ var logNameMapper = 'ga-to-split:mapper';
|
|
|
10
10
|
/**
|
|
11
11
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
12
12
|
* that the global command queue has been renamed or not yet defined.
|
|
13
|
-
* @param
|
|
14
|
-
* @param
|
|
13
|
+
* @param window Reference to global object.
|
|
14
|
+
* @param pluginName The plugin name identifier.
|
|
15
|
+
* @param pluginConstructor The plugin constructor function.
|
|
16
|
+
* @param log Logger instance.
|
|
17
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
15
18
|
*/
|
|
16
|
-
function providePlugin(pluginName, pluginConstructor) {
|
|
19
|
+
function providePlugin(window, pluginName, pluginConstructor, log, autoRequire) {
|
|
17
20
|
// get reference to global command queue. Init it if not defined yet.
|
|
18
|
-
// @ts-expect-error
|
|
19
21
|
var gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
20
22
|
window[gaAlias] = window[gaAlias] || function () {
|
|
21
|
-
|
|
22
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
23
|
-
args[_i] = arguments[_i];
|
|
24
|
-
}
|
|
25
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(args);
|
|
23
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
26
24
|
};
|
|
27
25
|
// provides the plugin for use with analytics.js.
|
|
28
|
-
// @ts-expect-error
|
|
29
26
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
27
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
28
|
+
// Expecting spy on ga.q push method but not found
|
|
29
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run.');
|
|
30
|
+
}
|
|
30
31
|
}
|
|
31
32
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
32
33
|
var defaultMapping = {
|
|
@@ -246,6 +247,6 @@ function GaToSplit(sdkOptions, params) {
|
|
|
246
247
|
return SplitTracker;
|
|
247
248
|
}());
|
|
248
249
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
249
|
-
providePlugin('splitTracker', SplitTracker);
|
|
250
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
250
251
|
}
|
|
251
252
|
exports.GaToSplit = GaToSplit;
|
package/cjs/listeners/browser.js
CHANGED
|
@@ -8,12 +8,11 @@ var objectAssign_1 = require("../utils/lang/objectAssign");
|
|
|
8
8
|
var constants_2 = require("../logger/constants");
|
|
9
9
|
var consent_1 = require("../consent");
|
|
10
10
|
var telemetrySubmitter_1 = require("../sync/submitters/telemetrySubmitter");
|
|
11
|
-
|
|
12
|
-
var PAGEHIDE_EVENT = 'pagehide';
|
|
11
|
+
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
13
12
|
var UNLOAD_DOM_EVENT = 'unload';
|
|
14
13
|
var EVENT_NAME = 'for unload page event.';
|
|
15
14
|
/**
|
|
16
|
-
* We'll listen for
|
|
15
|
+
* We'll listen for 'unload' event over the window object, since it's the standard way to listen page reload and close.
|
|
17
16
|
*/
|
|
18
17
|
var BrowserSignalListener = /** @class */ (function () {
|
|
19
18
|
function BrowserSignalListener(syncManager, settings, storage, serviceApi) {
|
|
@@ -22,43 +21,30 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
22
21
|
this.storage = storage;
|
|
23
22
|
this.serviceApi = serviceApi;
|
|
24
23
|
this.flushData = this.flushData.bind(this);
|
|
25
|
-
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
26
|
-
this.stopSync = this.stopSync.bind(this);
|
|
27
24
|
this.fromImpressionsCollector = impressionsSubmitter_1.fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
28
25
|
}
|
|
29
26
|
/**
|
|
30
27
|
* start method.
|
|
31
|
-
* Called when SplitFactory is initialized
|
|
28
|
+
* Called when SplitFactory is initialized.
|
|
29
|
+
* We add a handler on unload events. The handler flushes remaining impressions and events to the backend.
|
|
32
30
|
*/
|
|
33
31
|
BrowserSignalListener.prototype.start = function () {
|
|
34
32
|
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
35
33
|
this.settings.log.debug(constants_2.CLEANUP_REGISTERING, [EVENT_NAME]);
|
|
36
|
-
|
|
37
|
-
window.addEventListener(VISIBILITYCHANGE_EVENT, this.flushDataIfHidden);
|
|
38
|
-
// Some browsers like Safari does not fire the `visibilitychange` event when the page is being unloaded. So we also flush data in the `pagehide` event.
|
|
39
|
-
// If both events are triggered, the last one will find the storage empty, so no duplicated data will be submitted.
|
|
40
|
-
window.addEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
41
|
-
// Stop streaming on 'unload' event. Used instead of 'beforeunload', because 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
42
|
-
window.addEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
34
|
+
window.addEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
43
35
|
}
|
|
44
36
|
};
|
|
45
37
|
/**
|
|
46
38
|
* stop method.
|
|
47
|
-
* Called when client is destroyed
|
|
39
|
+
* Called when client is destroyed.
|
|
40
|
+
* We need to remove the handler for unload events, since it can break if called when Split context was destroyed.
|
|
48
41
|
*/
|
|
49
42
|
BrowserSignalListener.prototype.stop = function () {
|
|
50
43
|
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
51
44
|
this.settings.log.debug(constants_2.CLEANUP_DEREGISTERING, [EVENT_NAME]);
|
|
52
|
-
window.removeEventListener(
|
|
53
|
-
window.removeEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
54
|
-
window.removeEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
45
|
+
window.removeEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
55
46
|
}
|
|
56
47
|
};
|
|
57
|
-
BrowserSignalListener.prototype.stopSync = function () {
|
|
58
|
-
// Close streaming connection
|
|
59
|
-
if (this.syncManager && this.syncManager.pushManager)
|
|
60
|
-
this.syncManager.pushManager.stop();
|
|
61
|
-
};
|
|
62
48
|
/**
|
|
63
49
|
* flushData method.
|
|
64
50
|
* Called when unload event is triggered. It flushed remaining impressions and events to the backend,
|
|
@@ -85,10 +71,9 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
85
71
|
var telemetryCacheAdapter = (0, telemetrySubmitter_1.telemetryCacheStatsAdapter)(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
86
72
|
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
87
73
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
this.flushData(); // On a 'visibilitychange' event, flush data if state is hidden
|
|
74
|
+
// Close streaming connection
|
|
75
|
+
if (this.syncManager.pushManager)
|
|
76
|
+
this.syncManager.pushManager.stop();
|
|
92
77
|
};
|
|
93
78
|
BrowserSignalListener.prototype._flushData = function (url, cache, postService, fromCacheToPayload, extraMetadata) {
|
|
94
79
|
// if there is data in cache, send it to backend
|
|
@@ -7,23 +7,24 @@ var logNameMapper = 'ga-to-split:mapper';
|
|
|
7
7
|
/**
|
|
8
8
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
9
9
|
* that the global command queue has been renamed or not yet defined.
|
|
10
|
-
* @param
|
|
11
|
-
* @param
|
|
10
|
+
* @param window Reference to global object.
|
|
11
|
+
* @param pluginName The plugin name identifier.
|
|
12
|
+
* @param pluginConstructor The plugin constructor function.
|
|
13
|
+
* @param log Logger instance.
|
|
14
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
12
15
|
*/
|
|
13
|
-
function providePlugin(pluginName, pluginConstructor) {
|
|
16
|
+
function providePlugin(window, pluginName, pluginConstructor, log, autoRequire) {
|
|
14
17
|
// get reference to global command queue. Init it if not defined yet.
|
|
15
|
-
// @ts-expect-error
|
|
16
18
|
var gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
17
19
|
window[gaAlias] = window[gaAlias] || function () {
|
|
18
|
-
|
|
19
|
-
for (var _i = 0; _i < arguments.length; _i++) {
|
|
20
|
-
args[_i] = arguments[_i];
|
|
21
|
-
}
|
|
22
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(args);
|
|
20
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
23
21
|
};
|
|
24
22
|
// provides the plugin for use with analytics.js.
|
|
25
|
-
// @ts-expect-error
|
|
26
23
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
24
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
25
|
+
// Expecting spy on ga.q push method but not found
|
|
26
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run.');
|
|
27
|
+
}
|
|
27
28
|
}
|
|
28
29
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
29
30
|
var defaultMapping = {
|
|
@@ -240,5 +241,5 @@ export function GaToSplit(sdkOptions, params) {
|
|
|
240
241
|
return SplitTracker;
|
|
241
242
|
}());
|
|
242
243
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
243
|
-
providePlugin('splitTracker', SplitTracker);
|
|
244
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
244
245
|
}
|
package/esm/listeners/browser.js
CHANGED
|
@@ -5,12 +5,11 @@ import { objectAssign } from '../utils/lang/objectAssign';
|
|
|
5
5
|
import { CLEANUP_REGISTERING, CLEANUP_DEREGISTERING } from '../logger/constants';
|
|
6
6
|
import { isConsentGranted } from '../consent';
|
|
7
7
|
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
|
|
8
|
-
|
|
9
|
-
var PAGEHIDE_EVENT = 'pagehide';
|
|
8
|
+
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
10
9
|
var UNLOAD_DOM_EVENT = 'unload';
|
|
11
10
|
var EVENT_NAME = 'for unload page event.';
|
|
12
11
|
/**
|
|
13
|
-
* We'll listen for
|
|
12
|
+
* We'll listen for 'unload' event over the window object, since it's the standard way to listen page reload and close.
|
|
14
13
|
*/
|
|
15
14
|
var BrowserSignalListener = /** @class */ (function () {
|
|
16
15
|
function BrowserSignalListener(syncManager, settings, storage, serviceApi) {
|
|
@@ -19,43 +18,30 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
19
18
|
this.storage = storage;
|
|
20
19
|
this.serviceApi = serviceApi;
|
|
21
20
|
this.flushData = this.flushData.bind(this);
|
|
22
|
-
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
23
|
-
this.stopSync = this.stopSync.bind(this);
|
|
24
21
|
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
25
22
|
}
|
|
26
23
|
/**
|
|
27
24
|
* start method.
|
|
28
|
-
* Called when SplitFactory is initialized
|
|
25
|
+
* Called when SplitFactory is initialized.
|
|
26
|
+
* We add a handler on unload events. The handler flushes remaining impressions and events to the backend.
|
|
29
27
|
*/
|
|
30
28
|
BrowserSignalListener.prototype.start = function () {
|
|
31
29
|
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
32
30
|
this.settings.log.debug(CLEANUP_REGISTERING, [EVENT_NAME]);
|
|
33
|
-
|
|
34
|
-
window.addEventListener(VISIBILITYCHANGE_EVENT, this.flushDataIfHidden);
|
|
35
|
-
// Some browsers like Safari does not fire the `visibilitychange` event when the page is being unloaded. So we also flush data in the `pagehide` event.
|
|
36
|
-
// If both events are triggered, the last one will find the storage empty, so no duplicated data will be submitted.
|
|
37
|
-
window.addEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
38
|
-
// Stop streaming on 'unload' event. Used instead of 'beforeunload', because 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
39
|
-
window.addEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
31
|
+
window.addEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
40
32
|
}
|
|
41
33
|
};
|
|
42
34
|
/**
|
|
43
35
|
* stop method.
|
|
44
|
-
* Called when client is destroyed
|
|
36
|
+
* Called when client is destroyed.
|
|
37
|
+
* We need to remove the handler for unload events, since it can break if called when Split context was destroyed.
|
|
45
38
|
*/
|
|
46
39
|
BrowserSignalListener.prototype.stop = function () {
|
|
47
40
|
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
48
41
|
this.settings.log.debug(CLEANUP_DEREGISTERING, [EVENT_NAME]);
|
|
49
|
-
window.removeEventListener(
|
|
50
|
-
window.removeEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
51
|
-
window.removeEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
42
|
+
window.removeEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
52
43
|
}
|
|
53
44
|
};
|
|
54
|
-
BrowserSignalListener.prototype.stopSync = function () {
|
|
55
|
-
// Close streaming connection
|
|
56
|
-
if (this.syncManager && this.syncManager.pushManager)
|
|
57
|
-
this.syncManager.pushManager.stop();
|
|
58
|
-
};
|
|
59
45
|
/**
|
|
60
46
|
* flushData method.
|
|
61
47
|
* Called when unload event is triggered. It flushed remaining impressions and events to the backend,
|
|
@@ -82,10 +68,9 @@ var BrowserSignalListener = /** @class */ (function () {
|
|
|
82
68
|
var telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
83
69
|
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
84
70
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
this.flushData(); // On a 'visibilitychange' event, flush data if state is hidden
|
|
71
|
+
// Close streaming connection
|
|
72
|
+
if (this.syncManager.pushManager)
|
|
73
|
+
this.syncManager.pushManager.stop();
|
|
89
74
|
};
|
|
90
75
|
BrowserSignalListener.prototype._flushData = function (url, cache, postService, fromCacheToPayload, extraMetadata) {
|
|
91
76
|
// if there is data in cache, send it to backend
|
package/package.json
CHANGED
|
@@ -19,20 +19,26 @@ const logNameMapper = 'ga-to-split:mapper';
|
|
|
19
19
|
/**
|
|
20
20
|
* Provides a plugin to use with analytics.js, accounting for the possibility
|
|
21
21
|
* that the global command queue has been renamed or not yet defined.
|
|
22
|
-
* @param
|
|
23
|
-
* @param
|
|
22
|
+
* @param window Reference to global object.
|
|
23
|
+
* @param pluginName The plugin name identifier.
|
|
24
|
+
* @param pluginConstructor The plugin constructor function.
|
|
25
|
+
* @param log Logger instance.
|
|
26
|
+
* @param autoRequire If true, log error when auto-require script is not detected
|
|
24
27
|
*/
|
|
25
|
-
function providePlugin(pluginName: string, pluginConstructor: Function) {
|
|
28
|
+
function providePlugin(window: any, pluginName: string, pluginConstructor: Function, log: ILogger, autoRequire?: boolean) {
|
|
26
29
|
// get reference to global command queue. Init it if not defined yet.
|
|
27
|
-
// @ts-expect-error
|
|
28
30
|
const gaAlias = window.GoogleAnalyticsObject || 'ga';
|
|
29
|
-
window[gaAlias] = window[gaAlias] || function (
|
|
30
|
-
(window[gaAlias].q = window[gaAlias].q || []).push(
|
|
31
|
+
window[gaAlias] = window[gaAlias] || function () {
|
|
32
|
+
(window[gaAlias].q = window[gaAlias].q || []).push(arguments);
|
|
31
33
|
};
|
|
32
34
|
|
|
33
35
|
// provides the plugin for use with analytics.js.
|
|
34
|
-
// @ts-expect-error
|
|
35
36
|
window[gaAlias]('provide', pluginName, pluginConstructor);
|
|
37
|
+
|
|
38
|
+
if (autoRequire && (!window[gaAlias].q || window[gaAlias].q.push === [].push)) {
|
|
39
|
+
// Expecting spy on ga.q push method but not found
|
|
40
|
+
log.error(logPrefix + 'integration is configured to autorequire the splitTracker plugin, but the necessary script does not seem to have run.');
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
|
|
38
44
|
// Default mapping: object used for building the default mapper from hits to Split events
|
|
@@ -284,5 +290,5 @@ export function GaToSplit(sdkOptions: GoogleAnalyticsToSplitOptions, params: IIn
|
|
|
284
290
|
}
|
|
285
291
|
|
|
286
292
|
// Register the plugin, even if config is invalid, since, if not provided, it will block `ga` command queue.
|
|
287
|
-
providePlugin('splitTracker', SplitTracker);
|
|
293
|
+
providePlugin(window, 'splitTracker', SplitTracker, log, sdkOptions.autoRequire);
|
|
288
294
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/**
|
|
3
|
+
* Auto-require script to use with GoogleAnalyticsToSplit integration
|
|
4
|
+
*/
|
|
5
|
+
(function (i, r, s) {
|
|
6
|
+
i[s] = i[s] || r;
|
|
7
|
+
i[r] = i[r] || function () { i[r].q.push(arguments); };
|
|
8
|
+
i[r].q = i[r].q || [];
|
|
9
|
+
|
|
10
|
+
var ts = {}; // Tracker names
|
|
11
|
+
function n(arg) { return typeof arg === 'object' && typeof arg.name === 'string' && arg.name; }
|
|
12
|
+
|
|
13
|
+
function p(v) { // Queue a `require` command if v is a `create` command
|
|
14
|
+
if (v && v[0] === 'create') {
|
|
15
|
+
var t = n(v[1]) || n(v[2]) || n(v[3]) || (typeof v[3] === 'string' ? v[3] : undefined); // Get tracker name
|
|
16
|
+
|
|
17
|
+
if (!ts[t]) {
|
|
18
|
+
ts[t] = true;
|
|
19
|
+
i[r]((t ? t + '.' : '') + 'require', 'splitTracker'); // Auto-require
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
i[r].q.forEach(function (v) { p(v); }); // Process already queued commands
|
|
25
|
+
|
|
26
|
+
var o = i[r].q.push;
|
|
27
|
+
i[r].q.push = function (v) { // Spy new queued commands
|
|
28
|
+
var result = o.apply(this, arguments);
|
|
29
|
+
p(v);
|
|
30
|
+
return result;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
})(window, 'ga', 'GoogleAnalyticsObject');
|
|
@@ -53,13 +53,24 @@ export interface GoogleAnalyticsToSplitOptions {
|
|
|
53
53
|
* If not provided, events are sent using the key and traffic type provided at SDK config
|
|
54
54
|
*/
|
|
55
55
|
identities?: Identity[],
|
|
56
|
+
/**
|
|
57
|
+
* Optional flag to log an error if the `auto-require` script is not detected.
|
|
58
|
+
* The auto-require script automatically requires the `splitTracker` plugin for created trackers,
|
|
59
|
+
* and should be placed right after your Google Analytics, GTM or gtag.js script tag.
|
|
60
|
+
*
|
|
61
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-tag-manager}
|
|
62
|
+
*
|
|
63
|
+
* @property {boolean} autoRequire
|
|
64
|
+
* @default false
|
|
65
|
+
*/
|
|
66
|
+
autoRequire?: boolean,
|
|
56
67
|
}
|
|
57
68
|
|
|
58
69
|
/**
|
|
59
70
|
* Enable 'Google Analytics to Split' integration, to track Google Analytics hits as Split events.
|
|
60
71
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
61
72
|
*
|
|
62
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
73
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-analytics-to-split}
|
|
63
74
|
*/
|
|
64
75
|
export interface IGoogleAnalyticsToSplitConfig extends GoogleAnalyticsToSplitOptions {
|
|
65
76
|
type: 'GOOGLE_ANALYTICS_TO_SPLIT'
|
|
@@ -129,7 +140,7 @@ export interface SplitToGoogleAnalyticsOptions {
|
|
|
129
140
|
* Enable 'Split to Google Analytics' integration, to track Split impressions and events as Google Analytics hits.
|
|
130
141
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
131
142
|
*
|
|
132
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
143
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#split-to-google-analytics}
|
|
133
144
|
*/
|
|
134
145
|
export interface ISplitToGoogleAnalyticsConfig extends SplitToGoogleAnalyticsOptions {
|
|
135
146
|
type: 'SPLIT_TO_GOOGLE_ANALYTICS'
|
package/src/listeners/browser.ts
CHANGED
|
@@ -14,13 +14,12 @@ import { ISyncManager } from '../sync/types';
|
|
|
14
14
|
import { isConsentGranted } from '../consent';
|
|
15
15
|
import { telemetryCacheStatsAdapter } from '../sync/submitters/telemetrySubmitter';
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
const PAGEHIDE_EVENT = 'pagehide';
|
|
17
|
+
// 'unload' event is used instead of 'beforeunload', since 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
19
18
|
const UNLOAD_DOM_EVENT = 'unload';
|
|
20
19
|
const EVENT_NAME = 'for unload page event.';
|
|
21
20
|
|
|
22
21
|
/**
|
|
23
|
-
* We'll listen for
|
|
22
|
+
* We'll listen for 'unload' event over the window object, since it's the standard way to listen page reload and close.
|
|
24
23
|
*/
|
|
25
24
|
export class BrowserSignalListener implements ISignalListener {
|
|
26
25
|
|
|
@@ -33,47 +32,33 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
33
32
|
private serviceApi: ISplitApi,
|
|
34
33
|
) {
|
|
35
34
|
this.flushData = this.flushData.bind(this);
|
|
36
|
-
this.flushDataIfHidden = this.flushDataIfHidden.bind(this);
|
|
37
|
-
this.stopSync = this.stopSync.bind(this);
|
|
38
35
|
this.fromImpressionsCollector = fromImpressionsCollector.bind(undefined, settings.core.labelsEnabled);
|
|
39
36
|
}
|
|
40
37
|
|
|
41
38
|
/**
|
|
42
39
|
* start method.
|
|
43
|
-
* Called when SplitFactory is initialized
|
|
40
|
+
* Called when SplitFactory is initialized.
|
|
41
|
+
* We add a handler on unload events. The handler flushes remaining impressions and events to the backend.
|
|
44
42
|
*/
|
|
45
43
|
start() {
|
|
46
44
|
if (typeof window !== 'undefined' && window.addEventListener) {
|
|
47
45
|
this.settings.log.debug(CLEANUP_REGISTERING, [EVENT_NAME]);
|
|
48
|
-
|
|
49
|
-
// Flush data whenever the page is hidden or unloaded.
|
|
50
|
-
window.addEventListener(VISIBILITYCHANGE_EVENT, this.flushDataIfHidden);
|
|
51
|
-
// Some browsers like Safari does not fire the `visibilitychange` event when the page is being unloaded. So we also flush data in the `pagehide` event.
|
|
52
|
-
// If both events are triggered, the last one will find the storage empty, so no duplicated data will be submitted.
|
|
53
|
-
window.addEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
54
|
-
// Stop streaming on 'unload' event. Used instead of 'beforeunload', because 'unload' is not a cancelable event, so no other listeners can stop the event from occurring.
|
|
55
|
-
window.addEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
46
|
+
window.addEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
56
47
|
}
|
|
57
48
|
}
|
|
58
49
|
|
|
59
50
|
/**
|
|
60
51
|
* stop method.
|
|
61
|
-
* Called when client is destroyed
|
|
52
|
+
* Called when client is destroyed.
|
|
53
|
+
* We need to remove the handler for unload events, since it can break if called when Split context was destroyed.
|
|
62
54
|
*/
|
|
63
55
|
stop() {
|
|
64
56
|
if (typeof window !== 'undefined' && window.removeEventListener) {
|
|
65
57
|
this.settings.log.debug(CLEANUP_DEREGISTERING, [EVENT_NAME]);
|
|
66
|
-
window.removeEventListener(
|
|
67
|
-
window.removeEventListener(PAGEHIDE_EVENT, this.flushData);
|
|
68
|
-
window.removeEventListener(UNLOAD_DOM_EVENT, this.stopSync);
|
|
58
|
+
window.removeEventListener(UNLOAD_DOM_EVENT, this.flushData);
|
|
69
59
|
}
|
|
70
60
|
}
|
|
71
61
|
|
|
72
|
-
stopSync() {
|
|
73
|
-
// Close streaming connection
|
|
74
|
-
if (this.syncManager && this.syncManager.pushManager) this.syncManager.pushManager.stop();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
62
|
/**
|
|
78
63
|
* flushData method.
|
|
79
64
|
* Called when unload event is triggered. It flushed remaining impressions and events to the backend,
|
|
@@ -101,10 +86,9 @@ export class BrowserSignalListener implements ISignalListener {
|
|
|
101
86
|
const telemetryCacheAdapter = telemetryCacheStatsAdapter(this.storage.telemetry, this.storage.splits, this.storage.segments);
|
|
102
87
|
this._flushData(telemetryUrl + '/v1/metrics/usage/beacon', telemetryCacheAdapter, this.serviceApi.postMetricsUsage);
|
|
103
88
|
}
|
|
104
|
-
}
|
|
105
89
|
|
|
106
|
-
|
|
107
|
-
if (
|
|
90
|
+
// Close streaming connection
|
|
91
|
+
if (this.syncManager.pushManager) this.syncManager.pushManager.stop();
|
|
108
92
|
}
|
|
109
93
|
|
|
110
94
|
private _flushData<T>(url: string, cache: IRecorderCacheProducerSync<T>, postService: (body: string) => Promise<IResponse>, fromCacheToPayload?: (cacheData: T) => any, extraMetadata?: {}) {
|
|
@@ -52,12 +52,23 @@ export interface GoogleAnalyticsToSplitOptions {
|
|
|
52
52
|
* If not provided, events are sent using the key and traffic type provided at SDK config
|
|
53
53
|
*/
|
|
54
54
|
identities?: Identity[];
|
|
55
|
+
/**
|
|
56
|
+
* Optional flag to log an error if the `auto-require` script is not detected.
|
|
57
|
+
* The auto-require script automatically requires the `splitTracker` plugin for created trackers,
|
|
58
|
+
* and should be placed right after your Google Analytics, GTM or gtag.js script tag.
|
|
59
|
+
*
|
|
60
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-tag-manager}
|
|
61
|
+
*
|
|
62
|
+
* @property {boolean} autoRequire
|
|
63
|
+
* @default false
|
|
64
|
+
*/
|
|
65
|
+
autoRequire?: boolean;
|
|
55
66
|
}
|
|
56
67
|
/**
|
|
57
68
|
* Enable 'Google Analytics to Split' integration, to track Google Analytics hits as Split events.
|
|
58
69
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
59
70
|
*
|
|
60
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
71
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#google-analytics-to-split}
|
|
61
72
|
*/
|
|
62
73
|
export interface IGoogleAnalyticsToSplitConfig extends GoogleAnalyticsToSplitOptions {
|
|
63
74
|
type: 'GOOGLE_ANALYTICS_TO_SPLIT';
|
|
@@ -125,7 +136,7 @@ export interface SplitToGoogleAnalyticsOptions {
|
|
|
125
136
|
* Enable 'Split to Google Analytics' integration, to track Split impressions and events as Google Analytics hits.
|
|
126
137
|
* Used by the browser variant of the isomorphic JS SDK.
|
|
127
138
|
*
|
|
128
|
-
* @see {@link https://help.split.io/hc/en-us/articles/
|
|
139
|
+
* @see {@link https://help.split.io/hc/en-us/articles/360040838752#split-to-google-analytics}
|
|
129
140
|
*/
|
|
130
141
|
export interface ISplitToGoogleAnalyticsConfig extends SplitToGoogleAnalyticsOptions {
|
|
131
142
|
type: 'SPLIT_TO_GOOGLE_ANALYTICS';
|
|
@@ -4,7 +4,7 @@ import { ISplitApi } from '../services/types';
|
|
|
4
4
|
import { ISettings } from '../types';
|
|
5
5
|
import { ISyncManager } from '../sync/types';
|
|
6
6
|
/**
|
|
7
|
-
* We'll listen for
|
|
7
|
+
* We'll listen for 'unload' event over the window object, since it's the standard way to listen page reload and close.
|
|
8
8
|
*/
|
|
9
9
|
export declare class BrowserSignalListener implements ISignalListener {
|
|
10
10
|
private syncManager;
|
|
@@ -15,22 +15,22 @@ export declare class BrowserSignalListener implements ISignalListener {
|
|
|
15
15
|
constructor(syncManager: ISyncManager | undefined, settings: ISettings, storage: IStorageSync, serviceApi: ISplitApi);
|
|
16
16
|
/**
|
|
17
17
|
* start method.
|
|
18
|
-
* Called when SplitFactory is initialized
|
|
18
|
+
* Called when SplitFactory is initialized.
|
|
19
|
+
* We add a handler on unload events. The handler flushes remaining impressions and events to the backend.
|
|
19
20
|
*/
|
|
20
21
|
start(): void;
|
|
21
22
|
/**
|
|
22
23
|
* stop method.
|
|
23
|
-
* Called when client is destroyed
|
|
24
|
+
* Called when client is destroyed.
|
|
25
|
+
* We need to remove the handler for unload events, since it can break if called when Split context was destroyed.
|
|
24
26
|
*/
|
|
25
27
|
stop(): void;
|
|
26
|
-
stopSync(): void;
|
|
27
28
|
/**
|
|
28
29
|
* flushData method.
|
|
29
30
|
* Called when unload event is triggered. It flushed remaining impressions and events to the backend,
|
|
30
31
|
* using beacon API if possible, or falling back to regular post transport.
|
|
31
32
|
*/
|
|
32
33
|
flushData(): void;
|
|
33
|
-
flushDataIfHidden(): void;
|
|
34
34
|
private _flushData;
|
|
35
35
|
/**
|
|
36
36
|
* _sendBeacon method.
|