@schibsted/pulse-sdk 8.0.0-rc.0 → 8.0.0-rc.10
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/dist/cjs/Tracker.js +201 -209
- package/dist/cjs/Tracker.test-d.js +2 -2
- package/dist/cjs/builders/actor.js +3 -3
- package/dist/cjs/builders/consents.js +2 -2
- package/dist/cjs/builders/events-anonymous-node.js +1 -1
- package/dist/cjs/builders/events-node.js +3 -3
- package/dist/cjs/builders/experiments.js +1 -0
- package/dist/cjs/builders/tracker-node.js +2 -5
- package/dist/cjs/identity/actor.js +18 -6
- package/dist/cjs/identity/cis.js +4 -6
- package/dist/cjs/leaveTrackingTpaas/constants.js +2 -7
- package/dist/cjs/leaveTrackingTpaas/index.js +52 -40
- package/dist/cjs/tracker-proxy/consts.js +12 -6
- package/dist/cjs/tracker-proxy/proxy-provider.js +6 -0
- package/dist/cjs/version.js +5 -0
- package/dist/cjs/visibility-observer/index.js +9 -7
- package/dist/cjs/wrapper/types/event.js +5 -0
- package/dist/ejs/Tracker.js +203 -211
- package/dist/ejs/Tracker.test-d.js +2 -2
- package/dist/ejs/builders/actor.js +2 -2
- package/dist/ejs/builders/consents.js +2 -2
- package/dist/ejs/builders/events-anonymous-node.js +1 -1
- package/dist/ejs/builders/events-node.js +3 -3
- package/dist/ejs/builders/experiments.js +1 -1
- package/dist/ejs/builders/tracker-node.js +2 -2
- package/dist/ejs/identity/actor.js +19 -7
- package/dist/ejs/identity/cis.js +4 -3
- package/dist/ejs/leaveTrackingTpaas/constants.js +1 -5
- package/dist/ejs/leaveTrackingTpaas/index.js +53 -41
- package/dist/ejs/tracker-proxy/consts.js +12 -6
- package/dist/ejs/tracker-proxy/proxy-provider.js +6 -0
- package/dist/ejs/version.js +2 -0
- package/dist/ejs/visibility-observer/index.js +9 -7
- package/dist/ejs/wrapper/types/event.js +4 -1
- package/dist/types/Tracker.d.ts +92 -87
- package/dist/types/builders/actor.d.ts +3 -2
- package/dist/types/builders/consents.d.ts +2 -2
- package/dist/types/builders/experiments.d.ts +1 -0
- package/dist/types/builders/index.d.ts +1 -1
- package/dist/types/identity/actor.d.ts +2 -2
- package/dist/types/identity/cis.d.ts +1 -1
- package/dist/types/index.d.ts +1 -2
- package/dist/types/leaveTrackingTpaas/constants.d.ts +1 -5
- package/dist/types/leaveTrackingTpaas/index.d.ts +6 -6
- package/dist/types/leaveTrackingTpaas/types.d.ts +1 -9
- package/dist/types/tracker-proxy/consts.d.ts +1 -1
- package/dist/types/types.d.ts +19 -13
- package/dist/types/version.d.ts +1 -0
- package/dist/types/visibility-observer/index.d.ts +6 -1
- package/dist/types/wrapper/engagement/ui-element/types.d.ts +1 -0
- package/dist/types/wrapper/types/event.d.ts +3 -1
- package/dist/types/wrapper/view/ui-element/types.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/cis-browser.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/cis-browser.js +17 -3
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/cis-browser.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/pulseStorage.d.ts +4 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/pulseStorage.js +15 -5
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/pulseStorage.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/storage.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/storage.js +5 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/cjs/storage/storage.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/cis-browser.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/cis-browser.js +16 -2
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/cis-browser.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/pulseStorage.d.ts +4 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/pulseStorage.js +12 -3
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/pulseStorage.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/storage.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/storage.js +5 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/ejs/storage/storage.js.map +1 -1
- package/node_modules/@schibsted/pulse-cis-sync/dist/types/cis-browser.d.ts +1 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/types/storage/pulseStorage.d.ts +4 -0
- package/node_modules/@schibsted/pulse-cis-sync/dist/types/storage/storage.d.ts +1 -0
- package/node_modules/@schibsted/pulse-utils/package.json +1 -1
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders/catalogVersion.js +9 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders/device.js +8 -2
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders/provider.js +3 -1
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders/session.js +19 -6
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders.js +75 -76
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/guards.js +7 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/index.js +3 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/builders/catalogVersion.js +6 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/builders/device.js +8 -2
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/builders/provider.js +3 -1
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/builders/session.js +19 -6
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/builders.js +74 -71
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/guards.js +4 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/ejs/index.js +1 -0
- package/node_modules/@schibsted/tpaas-event-builder/dist/index.d.ts +1730 -1127
- package/node_modules/@schibsted/tpaas-event-builder/package.json +3 -2
- package/node_modules/@schibsted/tpaas-schemas/dist/cjs/constants.js +136 -103
- package/node_modules/@schibsted/tpaas-schemas/dist/cjs/index.js +1 -0
- package/node_modules/@schibsted/tpaas-schemas/dist/cjs/types.js +2 -0
- package/node_modules/@schibsted/tpaas-schemas/dist/ejs/constants.js +134 -101
- package/node_modules/@schibsted/tpaas-schemas/dist/ejs/index.js +1 -0
- package/node_modules/@schibsted/tpaas-schemas/dist/ejs/types.js +1 -0
- package/node_modules/@schibsted/tpaas-schemas/dist/index.d.ts +1940 -1266
- package/node_modules/@schibsted/tpaas-schemas/package.json +1 -1
- package/package.json +7 -6
- package/dist/cjs/version.json +0 -1
- package/dist/ejs/version.json +0 -1
|
@@ -5,6 +5,8 @@ const ARTICLE_PAYLOAD = {
|
|
|
5
5
|
{
|
|
6
6
|
name: 'test-experiment',
|
|
7
7
|
variant: 'test-variant',
|
|
8
|
+
platform: 'web',
|
|
9
|
+
experimentSdrn: 'sdrn:the-standard:experiment:test-experiment',
|
|
8
10
|
},
|
|
9
11
|
],
|
|
10
12
|
object: {
|
|
@@ -30,8 +32,6 @@ const ARTICLE_PAYLOAD = {
|
|
|
30
32
|
},
|
|
31
33
|
},
|
|
32
34
|
provider: {
|
|
33
|
-
component: 'test-component',
|
|
34
|
-
componentVersion: '1.0.0',
|
|
35
35
|
product: 'test-product',
|
|
36
36
|
stage: 'Dev',
|
|
37
37
|
version: '1.0.0',
|
|
@@ -12,11 +12,11 @@ export function generateActorSDRN(id, realm = '__REALM_NOT_SET__') {
|
|
|
12
12
|
return `sdrn:${realm}:user:${outputId}`;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Type guard to check if the input
|
|
15
|
+
* Type guard to check if the input has an Actor Builder
|
|
16
16
|
* @param input
|
|
17
17
|
* @internal
|
|
18
18
|
*/
|
|
19
|
-
export function
|
|
19
|
+
export function hasActorBuilder(input) {
|
|
20
20
|
// biome-ignore lint/suspicious/noPrototypeBuiltins: Object.hasOwn is not available in ES2020
|
|
21
21
|
return isPlainObject(input) && Object.prototype.hasOwnProperty.call(input, 'actor');
|
|
22
22
|
}
|
|
@@ -3,7 +3,7 @@ import { isPromise } from '@schibsted/pulse-utils';
|
|
|
3
3
|
import warnOnce from '../warnOnce';
|
|
4
4
|
import { getFallbackConsents } from './consent-manager';
|
|
5
5
|
/**
|
|
6
|
-
* @enum
|
|
6
|
+
* @enum ConsentsCategory
|
|
7
7
|
*/
|
|
8
8
|
export var ConsentsCategory;
|
|
9
9
|
(function (ConsentsCategory) {
|
|
@@ -12,7 +12,7 @@ export var ConsentsCategory;
|
|
|
12
12
|
ConsentsCategory["CMP_ADVERTISING"] = "CMP_ADVERTISING";
|
|
13
13
|
ConsentsCategory["CMP_PERSONALIZATION"] = "CMP_PERSONALIZATION";
|
|
14
14
|
})(ConsentsCategory || (ConsentsCategory = {}));
|
|
15
|
-
export const ConsentsSourceValues = ['default', 'cmp', 'cache'];
|
|
15
|
+
export const ConsentsSourceValues = ['default', 'cmp', 'cache', 'url'];
|
|
16
16
|
export const ConsentsPurposeCategoryStatusValues = ['accepted', 'rejected', 'unknown'];
|
|
17
17
|
const isLegacyConsentsPurpose = (consentsPurposeCategory) => {
|
|
18
18
|
return !consentsPurposeCategory?.status;
|
|
@@ -25,7 +25,7 @@ export function anonymousTrackerEvent({ eventInput, sdkConfig } = {}) {
|
|
|
25
25
|
return Object.assign({}, omit(eventInput, ['type']), {
|
|
26
26
|
'@type': eventInput?.type || 'View',
|
|
27
27
|
schema: eventInput?.schema ||
|
|
28
|
-
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/tracker-event.json/
|
|
28
|
+
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/tracker-event.json/360.json`,
|
|
29
29
|
consents: consentsBuilder(parentInput),
|
|
30
30
|
experiments: experimentsBuilder(parentInput),
|
|
31
31
|
experimentMetadata: experimentMetadataBuilder(parentInput),
|
|
@@ -22,7 +22,7 @@ function routableEventDefaults(eventInput) {
|
|
|
22
22
|
export function routableEvent({ eventInput, sdkConfig } = {}) {
|
|
23
23
|
return Object.assign({}, eventInput, {
|
|
24
24
|
schema: eventInput?.schema ||
|
|
25
|
-
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/base-routable-event.json/
|
|
25
|
+
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/base-routable-event.json/248.json#`,
|
|
26
26
|
provider: providerBuilder(eventInput),
|
|
27
27
|
actor: actorBuilder(eventInput),
|
|
28
28
|
});
|
|
@@ -55,7 +55,7 @@ export function trackerEvent({ eventInput, sdkConfig } = {}) {
|
|
|
55
55
|
'@type': eventInput?.type || 'View',
|
|
56
56
|
pageViewId: pageViewIdInput || pageViewIdSdk,
|
|
57
57
|
schema: eventInput?.schema ||
|
|
58
|
-
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/tracker-event.json/
|
|
58
|
+
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/tracker-event.json/361.json`,
|
|
59
59
|
actor: actorBuilder(parentInput),
|
|
60
60
|
consents: consentsBuilder(parentInput),
|
|
61
61
|
experiments: experimentsBuilder(parentInput),
|
|
@@ -73,7 +73,7 @@ trackerEvent.defaults = trackerEventInput;
|
|
|
73
73
|
export function engagementEvent({ eventInput, sdkConfig } = {}) {
|
|
74
74
|
return Object.assign(trackerEvent({ eventInput, sdkConfig }), {
|
|
75
75
|
schema: eventInput?.schema ||
|
|
76
|
-
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/engagement-event.json/
|
|
76
|
+
`http://${sdkConfig?.schemaLocation || DEFAULT_SCHEMA_LOCATION}/events/engagement-event.json/388.json`,
|
|
77
77
|
'@type': 'Engagement',
|
|
78
78
|
});
|
|
79
79
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { SDK_VERSION } from '../version';
|
|
2
2
|
/**
|
|
3
3
|
* Format tracker objects
|
|
4
4
|
*/
|
|
@@ -7,7 +7,7 @@ export default function tracker(input) {
|
|
|
7
7
|
const base = {
|
|
8
8
|
name: 'Pulse Node.js SDK',
|
|
9
9
|
type: 'JS',
|
|
10
|
-
version:
|
|
10
|
+
version: SDK_VERSION,
|
|
11
11
|
};
|
|
12
12
|
return Object.assign({}, base, trackerInput);
|
|
13
13
|
}
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { evaluateAndFlatten } from '@schibsted/pulse-utils';
|
|
2
|
-
import {
|
|
2
|
+
import { hasActorBuilder } from '../builders/actor';
|
|
3
3
|
import warnOnce from '../warnOnce';
|
|
4
4
|
/**
|
|
5
5
|
* @internal exported for testing
|
|
6
6
|
*/
|
|
7
|
-
export const WARN_CIS_SYNC_LOGIN_UNDEFINED = '
|
|
8
|
-
' this using tracker.update({ actor: undefined }), otherwise do tracker.update({ actor: somePromise }) with a' +
|
|
9
|
-
' promise that resolves to the login state.';
|
|
7
|
+
export const WARN_CIS_SYNC_LOGIN_UNDEFINED = 'No Actor Builder found in event input or tracker builders. Please provide an Actor Builder to ensure the SDK resolves logged-in and logged-out scenarios correctly.';
|
|
10
8
|
/**
|
|
11
9
|
* Get the actor id (userId) from the current browser. A promise is returned
|
|
12
10
|
* because a call may be made to complete the login process.
|
|
@@ -25,6 +23,19 @@ const getUserId = async (builders) => {
|
|
|
25
23
|
const getActor = async (builders) => {
|
|
26
24
|
return await evaluateActor(builders);
|
|
27
25
|
};
|
|
26
|
+
/**
|
|
27
|
+
* Pinpoints the Actor Builder from the Event payload or the available Builders
|
|
28
|
+
* @param eventInput - The event input which may contain an `actor` property
|
|
29
|
+
* @param builders - The builders managed by the SDK.
|
|
30
|
+
*/
|
|
31
|
+
function getActorSource(eventInput = {}, builders = {}) {
|
|
32
|
+
if (hasActorBuilder(eventInput)) {
|
|
33
|
+
return eventInput.actor;
|
|
34
|
+
}
|
|
35
|
+
if (hasActorBuilder(builders)) {
|
|
36
|
+
return builders.actor;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
28
39
|
const userIsLoggedIn = async (builders) => {
|
|
29
40
|
const actor = await getActor(builders);
|
|
30
41
|
return !!actor?.id;
|
|
@@ -36,8 +47,9 @@ const userIsLoggedIn = async (builders) => {
|
|
|
36
47
|
* @private
|
|
37
48
|
*/
|
|
38
49
|
const evaluateActor = async (eventInput = {}, builders = {}) => {
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
const actorSource = getActorSource(eventInput, builders);
|
|
51
|
+
if (actorSource) {
|
|
52
|
+
const evaluatedActor = await evaluateAndFlatten(actorSource);
|
|
41
53
|
if (evaluatedActor) {
|
|
42
54
|
return evaluatedActor;
|
|
43
55
|
}
|
|
@@ -45,7 +57,7 @@ const evaluateActor = async (eventInput = {}, builders = {}) => {
|
|
|
45
57
|
// We allow an empty actor object, because it is a sign that the application is not setting nor updating Actor correctly.
|
|
46
58
|
// Inferring "id: undefined" as a fallback would mask that bug.
|
|
47
59
|
// Hence, the warning below.
|
|
48
|
-
warnOnce('no-actor-builder
|
|
60
|
+
warnOnce('no-actor-builder', WARN_CIS_SYNC_LOGIN_UNDEFINED);
|
|
49
61
|
return {};
|
|
50
62
|
};
|
|
51
63
|
export { getUserId, getActor, userIsLoggedIn, evaluateActor };
|
package/dist/ejs/identity/cis.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { clearCookieJweIfStale, resetRefreshAfter, syncWithCis } from '@schibsted/pulse-cis-sync';
|
|
2
|
-
import
|
|
2
|
+
import { SDK_VERSION } from '../version';
|
|
3
3
|
import { evaluateActor } from './actor';
|
|
4
4
|
const requireCisSyncCallForAdvertisingIds = () => {
|
|
5
5
|
resetRefreshAfter(new Date());
|
|
@@ -40,14 +40,15 @@ const cisSync = async (data, builders, config) => {
|
|
|
40
40
|
// _pulse2data cookie, or just not do the sync.
|
|
41
41
|
//
|
|
42
42
|
const actorPromise = evaluateActor(data, builders);
|
|
43
|
-
const { cisBaseUrl, cisEnabled, includeAdvertising: includeAdvertisingPromise, isHybrid, nativeJwe, providerId, trackerId, vendors, } = config || {};
|
|
43
|
+
const { adChoicesEnabled, cisBaseUrl, cisEnabled, includeAdvertising: includeAdvertisingPromise, isHybrid, nativeJwe, providerId, trackerId, vendors, } = config || {};
|
|
44
44
|
const [includeAdvertising, actor] = await Promise.all([includeAdvertisingPromise, actorPromise]);
|
|
45
45
|
const { id, realm } = actor;
|
|
46
46
|
if (cisEnabled) {
|
|
47
47
|
// @ts-expect-error
|
|
48
48
|
return syncWithCis(
|
|
49
49
|
// @ts-expect-error
|
|
50
|
-
id, nativeJwe, cisBaseUrl, realm, providerId, isHybrid ? 'Hybrid' : 'Web',
|
|
50
|
+
id, nativeJwe, cisBaseUrl, realm, providerId, isHybrid ? 'Hybrid' : 'Web', SDK_VERSION, {
|
|
51
|
+
adChoicesEnabled,
|
|
51
52
|
includeAdvertising,
|
|
52
53
|
vendors,
|
|
53
54
|
trackerId,
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export const DEFAULT_ACTIVITY_DURATION = () => ({
|
|
2
|
-
value: 0,
|
|
3
|
-
interval: undefined,
|
|
4
|
-
timeSinceLastActivity: 0,
|
|
5
|
-
});
|
|
6
1
|
export const DEFAULT_PAGE_LEAVE_EVENT = () => ({
|
|
7
2
|
objectViewPercentage: 0,
|
|
8
3
|
maxObjectViewPercentage: 0,
|
|
@@ -11,3 +6,4 @@ export const DEFAULT_PAGE_LEAVE_EVENT = () => ({
|
|
|
11
6
|
pageScrollPosition: 0,
|
|
12
7
|
maxPageScrollPosition: 0,
|
|
13
8
|
});
|
|
9
|
+
export const ACTIVITY_DURATION_LIMIT_MS = 30000;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { isBrowser, isFunction, throttle } from '@schibsted/pulse-utils';
|
|
2
2
|
import * as logger from 'loglevel';
|
|
3
|
-
import {
|
|
3
|
+
import { ACTIVITY_DURATION_LIMIT_MS, DEFAULT_PAGE_LEAVE_EVENT } from './constants';
|
|
4
4
|
import { BrowserEvents } from './types';
|
|
5
5
|
let currentLeaveSchema;
|
|
6
6
|
let currentTrackMethod;
|
|
@@ -9,19 +9,42 @@ let updateViewedContentListeners = [];
|
|
|
9
9
|
let activityListeners = [];
|
|
10
10
|
let resizeObserver = null;
|
|
11
11
|
let throttledUpdateFn = throttle(() => undefined, 0);
|
|
12
|
-
let
|
|
13
|
-
let
|
|
12
|
+
let durationStartTime = 0;
|
|
13
|
+
let activityStartTime = 0;
|
|
14
14
|
let currentLeaveEvent = DEFAULT_PAGE_LEAVE_EVENT();
|
|
15
15
|
let additionalHeightBuilder;
|
|
16
|
+
/**
|
|
17
|
+
* Resolves a DOM element from either a CSS selector string or an Element instance.
|
|
18
|
+
*/
|
|
19
|
+
function resolveDomElement(element) {
|
|
20
|
+
try {
|
|
21
|
+
return typeof element === 'string' ? document.querySelector(element) : element || null;
|
|
22
|
+
}
|
|
23
|
+
catch (e) {
|
|
24
|
+
logger.error('Error while resolving DOM element', e);
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
16
28
|
/*
|
|
17
29
|
Add leave tracking
|
|
18
30
|
*/
|
|
19
31
|
export function addTpaasLeaveTracking({ objectElement, pageElement, schema, objectResizable, heightBuilder, trackMethod, }) {
|
|
20
32
|
function _addLeaveTracking() {
|
|
33
|
+
const objectDomElement = resolveDomElement(objectElement);
|
|
34
|
+
if (objectDomElement == null) {
|
|
35
|
+
logger.error('Could not find object element for leave tracking');
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
let pageDomElement = resolveDomElement(pageElement);
|
|
39
|
+
if (pageDomElement == null) {
|
|
40
|
+
logger.warn('Could not find page element for leave tracking, defaulting to document.body');
|
|
41
|
+
pageDomElement = document.body;
|
|
42
|
+
}
|
|
21
43
|
additionalHeightBuilder = heightBuilder;
|
|
22
44
|
addTpaasLeaveListeners();
|
|
23
|
-
addUpdateEventListeners(
|
|
24
|
-
|
|
45
|
+
addUpdateEventListeners(objectDomElement, pageDomElement, objectResizable);
|
|
46
|
+
activityStartTime = resetTime();
|
|
47
|
+
durationStartTime = resetTime();
|
|
25
48
|
currentLeaveSchema = schema;
|
|
26
49
|
currentTrackMethod = trackMethod;
|
|
27
50
|
logger.debug('addLeaveTracking:after:state', currentLeaveEvent);
|
|
@@ -113,12 +136,8 @@ function removeUpdateEventListeners() {
|
|
|
113
136
|
*/
|
|
114
137
|
const resetEventDefaults = () => {
|
|
115
138
|
currentLeaveEvent = DEFAULT_PAGE_LEAVE_EVENT();
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
};
|
|
119
|
-
const resetActivityDuration = () => {
|
|
120
|
-
clearInterval(activityDuration.interval);
|
|
121
|
-
return DEFAULT_ACTIVITY_DURATION();
|
|
139
|
+
durationStartTime = resetTime();
|
|
140
|
+
activityStartTime = resetTime();
|
|
122
141
|
};
|
|
123
142
|
export const resetTpaasViewedContent = () => {
|
|
124
143
|
currentLeaveEvent = DEFAULT_PAGE_LEAVE_EVENT();
|
|
@@ -126,34 +145,41 @@ export const resetTpaasViewedContent = () => {
|
|
|
126
145
|
const resetTime = () => Date.now();
|
|
127
146
|
/*
|
|
128
147
|
Send a Leave event only if Page Leave tracking is active in the SDK
|
|
129
|
-
The event that is ultimately sent is
|
|
130
|
-
|
|
131
|
-
to the brand event. After the event has been sent, leave page tracking is removed
|
|
148
|
+
The event that is ultimately sent is the View event saved in the currentTrackMethod callback.
|
|
149
|
+
After the event has been sent, leave page tracking is removed
|
|
132
150
|
and must be explicitly re-added if needed.
|
|
133
151
|
*/
|
|
134
|
-
export function trackTpaasActiveLeave() {
|
|
152
|
+
export async function trackTpaasActiveLeave() {
|
|
135
153
|
if (leaveTpaasTrackingIsActive()) {
|
|
136
|
-
trackTpaasLeave();
|
|
154
|
+
await trackTpaasLeave();
|
|
137
155
|
}
|
|
138
156
|
}
|
|
139
157
|
/*
|
|
140
158
|
Send a Leave event regardless of whether Page Leave tracking is active in the SDK
|
|
141
|
-
The event that is ultimately sent is
|
|
142
|
-
|
|
143
|
-
to the brand event. After the event has been sent, leave page tracking is removed
|
|
159
|
+
The event that is ultimately sent is the View event saved in the currentTrackMethod callback.
|
|
160
|
+
After the event has been sent, leave page tracking is removed
|
|
144
161
|
and must be explicitly re-added if needed.
|
|
145
162
|
*/
|
|
146
|
-
export function trackTpaasLeave() {
|
|
163
|
+
export async function trackTpaasLeave() {
|
|
147
164
|
const leave = getTpaasLeaveObject();
|
|
148
|
-
currentTrackMethod
|
|
165
|
+
// Capture currentTrackMethod and remove tracking synchronously before awaiting.
|
|
166
|
+
// If removal happened after the await, a new trackView* call arriving during the async
|
|
167
|
+
// gap would see tracking still active with the same schema and silently discard its
|
|
168
|
+
// new callback (e.g. a fresh leaveAudioBuilder), causing the next leave event to
|
|
169
|
+
// never fire or to use the wrong builder.
|
|
170
|
+
const trackMethod = currentTrackMethod;
|
|
149
171
|
removeTpaasLeaveTracking();
|
|
172
|
+
await trackMethod(leave);
|
|
150
173
|
}
|
|
151
174
|
export function getTpaasLeaveObject() {
|
|
152
175
|
const endTime = Date.now();
|
|
153
|
-
|
|
176
|
+
// TPaaS leave event requires duration/activity to be at least 1ms, otherwise the event is rejected
|
|
177
|
+
// also, in practice, it's almost impossible to have an activity or duration of 0ms
|
|
178
|
+
const durationMs = Math.max(endTime - durationStartTime, 1);
|
|
179
|
+
const activityDurationMs = Math.max(Math.min(endTime - activityStartTime, ACTIVITY_DURATION_LIMIT_MS), 1);
|
|
154
180
|
const leave = {
|
|
155
|
-
durationMs
|
|
156
|
-
activityDurationMs
|
|
181
|
+
durationMs,
|
|
182
|
+
activityDurationMs,
|
|
157
183
|
...currentLeaveEvent,
|
|
158
184
|
};
|
|
159
185
|
logger.debug('trackTpaasLeave: event', leave);
|
|
@@ -226,18 +252,10 @@ export const calculateScrollPosition = (element) => Math.abs(Math.min(element.ge
|
|
|
226
252
|
'mousedown', 'mousemove', 'keydown', 'scroll' and/or 'touchstart' browser events.
|
|
227
253
|
*/
|
|
228
254
|
function addUpdateActivityDurationListeners() {
|
|
229
|
-
if
|
|
230
|
-
|
|
255
|
+
// if there are already listeners for activity, do not add more
|
|
256
|
+
if (activityListeners.length > 0) {
|
|
231
257
|
return;
|
|
232
258
|
}
|
|
233
|
-
const interval = 1000;
|
|
234
|
-
const activityTimeout = 30 * 1000;
|
|
235
|
-
activityDuration.interval = window.setInterval(() => {
|
|
236
|
-
activityDuration.timeSinceLastActivity += interval;
|
|
237
|
-
if (activityDuration.timeSinceLastActivity < activityTimeout) {
|
|
238
|
-
activityDuration.value += interval;
|
|
239
|
-
}
|
|
240
|
-
}, interval);
|
|
241
259
|
const activityEvents = [
|
|
242
260
|
BrowserEvents.SCROLL,
|
|
243
261
|
BrowserEvents.MOUSEDOWN,
|
|
@@ -246,15 +264,9 @@ function addUpdateActivityDurationListeners() {
|
|
|
246
264
|
BrowserEvents.TOUCHSTART,
|
|
247
265
|
];
|
|
248
266
|
activityListeners = addEventListeners(activityEvents, () => {
|
|
249
|
-
|
|
267
|
+
activityStartTime = resetTime();
|
|
250
268
|
}, { passive: true });
|
|
251
269
|
}
|
|
252
|
-
function resetLastActivity(activityDuration) {
|
|
253
|
-
return {
|
|
254
|
-
...activityDuration,
|
|
255
|
-
timeSinceLastActivity: 0,
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
270
|
/*
|
|
259
271
|
Add listeners to a set of browser events.
|
|
260
272
|
*/
|
|
@@ -33,15 +33,13 @@ export const TPAAS_ALLOWED_METHODS = [
|
|
|
33
33
|
'trackLeaveLandingpage',
|
|
34
34
|
'trackLeaveListing',
|
|
35
35
|
'trackLeaveLockedArticle',
|
|
36
|
-
'trackLeaveLockedAudio',
|
|
37
36
|
'trackLeaveLockedAudioPage',
|
|
38
|
-
'trackLeaveLockedVideo',
|
|
39
37
|
'trackLeaveLockedVideoPage',
|
|
40
38
|
'trackLeavePage',
|
|
39
|
+
'trackLeaveSportsPage',
|
|
41
40
|
'trackLeaveVideoPage',
|
|
42
41
|
'trackLeaveWeather',
|
|
43
42
|
'trackViewArticle',
|
|
44
|
-
'trackViewAudio',
|
|
45
43
|
'trackViewAudioPage',
|
|
46
44
|
'trackViewError',
|
|
47
45
|
'trackViewFrontpage',
|
|
@@ -49,15 +47,23 @@ export const TPAAS_ALLOWED_METHODS = [
|
|
|
49
47
|
'trackViewLandingpage',
|
|
50
48
|
'trackViewListing',
|
|
51
49
|
'trackViewLockedArticle',
|
|
52
|
-
'trackViewLockedAudio',
|
|
53
50
|
'trackViewLockedAudioPage',
|
|
54
|
-
'trackViewLockedVideo',
|
|
55
51
|
'trackViewLockedVideoPage',
|
|
56
52
|
'trackViewPage',
|
|
53
|
+
'trackViewSportsPage',
|
|
57
54
|
'trackViewTitle',
|
|
58
|
-
'trackViewVideo',
|
|
59
55
|
'trackViewVideoPage',
|
|
60
56
|
'trackViewWeather',
|
|
57
|
+
// these are not TPaaS methods,
|
|
58
|
+
// but they're part of this list to not have to duplicate the tracker-tpaas-proxy.ts implementation in tracker-proxy.ts
|
|
59
|
+
'trackLegacyViewArticle',
|
|
60
|
+
'trackLegacyViewLoginPoster',
|
|
61
|
+
'trackLegacyViewSalesPoster',
|
|
62
|
+
'trackLegacyViewListing',
|
|
63
|
+
'trackLegacyViewFrontpage',
|
|
64
|
+
'trackLegacyViewPage',
|
|
65
|
+
'trackLegacyViewUIElement',
|
|
66
|
+
'trackLegacyClickUIElement',
|
|
61
67
|
];
|
|
62
68
|
export function isPulseProxyMessage(message) {
|
|
63
69
|
return (message !== null &&
|
|
@@ -7,6 +7,11 @@ export function startProxyProviderListener(tracker) {
|
|
|
7
7
|
logger.debug('Proxy Provider - Not in browser environment, skipping message listener');
|
|
8
8
|
return () => { };
|
|
9
9
|
}
|
|
10
|
+
if (tracker.hasProxyListener) {
|
|
11
|
+
logger.debug('Proxy Provider - Message listener already registered for this tracker, skipping');
|
|
12
|
+
return () => { };
|
|
13
|
+
}
|
|
14
|
+
tracker.hasProxyListener = true;
|
|
10
15
|
logger.debug('Proxy Provider - Added message listener for proxy provider');
|
|
11
16
|
const listener = async (event) => {
|
|
12
17
|
logger.debug('Proxy Provider - message received', event.data);
|
|
@@ -58,5 +63,6 @@ export function startProxyProviderListener(tracker) {
|
|
|
58
63
|
window.addEventListener('message', listener);
|
|
59
64
|
return () => {
|
|
60
65
|
window.removeEventListener('message', listener);
|
|
66
|
+
tracker.hasProxyListener = false;
|
|
61
67
|
};
|
|
62
68
|
}
|
|
@@ -13,14 +13,16 @@ export class VisibilityObserver {
|
|
|
13
13
|
* Uses {@link https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver | MutationObserver} to monitor the DOM for dynamically loaded content.
|
|
14
14
|
* Callback is invoked only once per element.
|
|
15
15
|
* @param selector The CSS selector for elements to track.
|
|
16
|
+
* @param options {ObserverOptions} Optional configuration for the observer.
|
|
17
|
+
* @param options.threshold Which ratio triggers the Observer callback.
|
|
16
18
|
* @throws Error if called more than once.
|
|
17
19
|
*/
|
|
18
|
-
observe(selector) {
|
|
20
|
+
observe(selector, { threshold = 0.67 }) {
|
|
19
21
|
if (this.selector) {
|
|
20
22
|
throw new Error(`Cannot observe selector ${selector}. A visibility observer has already been set up for selector ${this.selector}.`);
|
|
21
23
|
}
|
|
22
24
|
this.selector = selector;
|
|
23
|
-
this.setupObservers();
|
|
25
|
+
this.setupObservers({ threshold });
|
|
24
26
|
// biome-ignore lint/suspicious/useIterableCallbackReturn: -
|
|
25
27
|
this.elements().forEach((elementToTrack) => this.observeIntersection(elementToTrack));
|
|
26
28
|
}
|
|
@@ -30,14 +32,14 @@ export class VisibilityObserver {
|
|
|
30
32
|
elements() {
|
|
31
33
|
return Array.from(document.querySelectorAll(this.selector));
|
|
32
34
|
}
|
|
33
|
-
//
|
|
34
|
-
setupObservers() {
|
|
35
|
-
this.setupIntersectionObserver();
|
|
35
|
+
// Initialise both observers and start watching for DOM changes
|
|
36
|
+
setupObservers({ threshold }) {
|
|
37
|
+
this.setupIntersectionObserver({ threshold });
|
|
36
38
|
this.setupMutationObserver();
|
|
37
39
|
this.observeMutations();
|
|
38
40
|
}
|
|
39
41
|
// Create observer to detect when elements become visible in the viewport
|
|
40
|
-
setupIntersectionObserver() {
|
|
42
|
+
setupIntersectionObserver({ threshold }) {
|
|
41
43
|
this.intersectionObserver = new IntersectionObserver((entries) => {
|
|
42
44
|
entries.forEach((entry) => {
|
|
43
45
|
if (entry.isIntersecting) {
|
|
@@ -46,7 +48,7 @@ export class VisibilityObserver {
|
|
|
46
48
|
this.intersectionObserver.unobserve(node);
|
|
47
49
|
}
|
|
48
50
|
});
|
|
49
|
-
}, { threshold
|
|
51
|
+
}, { threshold });
|
|
50
52
|
}
|
|
51
53
|
// Create observer to detect DOM changes that may add/remove tracked elements
|
|
52
54
|
setupMutationObserver() {
|