@schibsted/pulse-sdk 8.0.0-rc.6 → 8.0.0-rc.8
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 +92 -43
- package/dist/cjs/builders/experiments.js +1 -0
- package/dist/cjs/tracker-proxy/consts.js +1 -0
- package/dist/cjs/version.js +1 -1
- package/dist/cjs/visibility-observer/index.js +9 -7
- package/dist/cjs/wrapper/types/event.js +5 -0
- package/dist/ejs/Tracker.js +93 -44
- package/dist/ejs/builders/experiments.js +1 -1
- package/dist/ejs/tracker-proxy/consts.js +1 -0
- package/dist/ejs/version.js +1 -1
- package/dist/ejs/visibility-observer/index.js +9 -7
- package/dist/ejs/wrapper/types/event.js +4 -1
- package/dist/types/Tracker.d.ts +39 -17
- package/dist/types/builders/experiments.d.ts +1 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/tracker-proxy/consts.d.ts +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/visibility-observer/index.d.ts +6 -1
- package/dist/types/wrapper/types/event.d.ts +3 -1
- package/node_modules/@schibsted/tpaas-event-builder/dist/cjs/builders.js +53 -47
- 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.js +53 -48
- 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 +822 -198
- package/node_modules/@schibsted/tpaas-event-builder/package.json +2 -1
- package/node_modules/@schibsted/tpaas-schemas/dist/cjs/constants.js +66 -57
- 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 +64 -55
- 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 +888 -223
- package/package.json +4 -4
package/dist/ejs/Tracker.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parsePulseCookies } from '@schibsted/pulse-cis-sync';
|
|
2
2
|
import { evaluateAndFlatten, isBrowser, isFunction, isPromise, isString, pulseMerge, throttle, } from '@schibsted/pulse-utils';
|
|
3
|
-
import { buildAnonymousViewUIElementEvent, buildCompletedHealthActionEvent, buildEngagementAudioEvent, buildEngagementFormEvent, buildEngagementHealthUIElementEvent, buildEngagementOfferEvent, buildEngagementTeaserEvent, buildEngagementUIElementEvent, buildEngagementVideoAdEvent, buildEngagementVideoEvent, buildEngagementWidgetEvent, buildImpressionFormEvent, buildImpressionHealthUIElementEvent, buildImpressionOfferEvent, buildImpressionPlayerEvent, buildImpressionTeaserEvent, buildImpressionUIElementEvent, buildImpressionWidgetEvent, buildLeaveArticleEvent, buildLeaveAudioPageEvent, buildLeaveErrorEvent, buildLeaveFrontpageEvent, buildLeaveLandingpageEvent, buildLeaveListingEvent, buildLeaveLockedArticleEvent, buildLeaveLockedAudioPageEvent, buildLeaveLockedVideoPageEvent, buildLeavePageEvent, buildLeaveSportsPageEvent, buildLeaveVideoPageEvent, buildLeaveWeatherEvent, buildViewArticleEvent, buildViewAudioPageEvent, buildViewErrorEvent, buildViewFrontpageEvent, buildViewHealthPageEvent, buildViewLandingpageEvent, buildViewListingEvent, buildViewLockedArticleEvent, buildViewLockedAudioPageEvent, buildViewLockedVideoPageEvent, buildViewPageEvent, buildViewSportsPageEvent, buildViewTitleEvent, buildViewVideoPageEvent, buildViewWeatherEvent,
|
|
3
|
+
import { buildAnonymousViewUIElementEvent, buildCompletedHealthActionEvent, buildEngagementAudioEvent, buildEngagementFormEvent, buildEngagementHealthUIElementEvent, buildEngagementOfferEvent, buildEngagementTeaserEvent, buildEngagementUIElementEvent, buildEngagementVideoAdEvent, buildEngagementVideoEvent, buildEngagementWidgetEvent, buildImpressionAdSlotEvent, buildImpressionFormEvent, buildImpressionHealthUIElementEvent, buildImpressionOfferEvent, buildImpressionPlayerEvent, buildImpressionTeaserEvent, buildImpressionUIElementEvent, buildImpressionWidgetEvent, buildLeaveArticleEvent, buildLeaveAudioPageEvent, buildLeaveErrorEvent, buildLeaveFrontpageEvent, buildLeaveLandingpageEvent, buildLeaveListingEvent, buildLeaveLockedArticleEvent, buildLeaveLockedAudioPageEvent, buildLeaveLockedVideoPageEvent, buildLeavePageEvent, buildLeaveSportsPageEvent, buildLeaveVideoPageEvent, buildLeaveWeatherEvent, buildViewArticleEvent, buildViewAudioPageEvent, buildViewErrorEvent, buildViewFrontpageEvent, buildViewHealthPageEvent, buildViewLandingpageEvent, buildViewListingEvent, buildViewLockedArticleEvent, buildViewLockedAudioPageEvent, buildViewLockedVideoPageEvent, buildViewPageEvent, buildViewSportsPageEvent, buildViewTitleEvent, buildViewVideoPageEvent, buildViewWeatherEvent, isPageType, } from '@schibsted/tpaas-event-builder';
|
|
4
4
|
import { LeaveArticle, LeaveAudioPage, LeaveError, LeaveFrontpage, LeaveLandingpage, LeaveListing, LeaveLockedArticle, LeaveLockedAudioPage, LeaveLockedVideoPage, LeavePage, LeaveSportsPage, LeaveVideoPage, LeaveWeather, ViewArticle, ViewAudioPage, ViewError, ViewFrontpage, ViewHealthPage, ViewLandingpage, ViewListing, ViewLockedArticle, ViewLockedAudioPage, ViewLockedVideoPage, ViewPage, ViewSportsPage, ViewTitle, ViewVideoPage, ViewWeather, } from '@schibsted/tpaas-schemas';
|
|
5
5
|
import logger from 'loglevel';
|
|
6
6
|
import { v4 } from 'uuid';
|
|
@@ -10,6 +10,7 @@ import { getConsentsWaitForAnalytics, getFallbackConsents } from './builders/con
|
|
|
10
10
|
import { applyAdvertisingConsent, applyAdvertisingConsentSync, } from './builders/consents';
|
|
11
11
|
import { engagementEvent, identityEvent, routableEvent, trackerEvent } from './builders/events';
|
|
12
12
|
import { anonymousEngagementEvent, anonymousTrackerEvent } from './builders/events-anonymous-node';
|
|
13
|
+
import { generateExperimentSDRN } from './builders/experiments';
|
|
13
14
|
import { readSession } from './builders/session-browser';
|
|
14
15
|
import { baseConfig as defaultConfig } from './config';
|
|
15
16
|
import { CISEndpoints, collectorEndpoints, remoteConfig } from './config-browser';
|
|
@@ -25,6 +26,7 @@ import { SDK_VERSION } from './version';
|
|
|
25
26
|
import { VisibilityObserver } from './visibility-observer';
|
|
26
27
|
import warnOnce from './warnOnce';
|
|
27
28
|
import { buildClickUIElementEvent } from './wrapper/engagement/ui-element/event-builder';
|
|
29
|
+
import { isLegacyPageType } from './wrapper/types';
|
|
28
30
|
import { pageFromPageView } from './wrapper/utils/page-from-page-view';
|
|
29
31
|
import { buildLegacyViewArticleEvent } from './wrapper/view/article/event-builder';
|
|
30
32
|
import { buildLegacyViewFrontpageEvent } from './wrapper/view/frontpage/event-builder';
|
|
@@ -114,6 +116,27 @@ export function unsubscribe(eventName, callback) {
|
|
|
114
116
|
* @class Tracker
|
|
115
117
|
*/
|
|
116
118
|
export default class Tracker {
|
|
119
|
+
async getCurrentTpaasPage() {
|
|
120
|
+
const { id, type, url } = await this.currentPage;
|
|
121
|
+
return {
|
|
122
|
+
// remove the SDRN prefix, it's not expected for TPaaS
|
|
123
|
+
pageId: id.startsWith('sdrn:') ? id.split(':').slice(-1)[0] : id,
|
|
124
|
+
// make sure the pageType is valid for TPaaS
|
|
125
|
+
pageType: isPageType(type) ? type : 'Page',
|
|
126
|
+
url,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
async getCurrentLegacyPage() {
|
|
130
|
+
const { id, type, url } = await this.currentPage;
|
|
131
|
+
// make sure the pageType is valid for legacy events
|
|
132
|
+
const validatedType = isLegacyPageType(type) ? type : 'Page';
|
|
133
|
+
return {
|
|
134
|
+
// add the SDRN prefix if it's not there, legacy events expect the full SDRN format
|
|
135
|
+
id: id.startsWith('sdrn:') ? id : `sdrn:${this.state.providerId}:${validatedType.toLowerCase()}:${id}`,
|
|
136
|
+
type: validatedType,
|
|
137
|
+
url,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
117
140
|
/**
|
|
118
141
|
* > [!WARNING]
|
|
119
142
|
* >
|
|
@@ -132,12 +155,18 @@ export default class Tracker {
|
|
|
132
155
|
// the tracking of the same element with both old and new events at the same time
|
|
133
156
|
this.legacyVisibilityObservers = new Map();
|
|
134
157
|
this.visibilityObservers = new Map();
|
|
135
|
-
|
|
136
|
-
|
|
158
|
+
/**
|
|
159
|
+
* @private
|
|
160
|
+
*
|
|
161
|
+
* This is used as the source of truth for the current page's information, which is updated based on the View Page-level event
|
|
162
|
+
* As a single source of truth for the current page, this needs to be compatible between legacy and TPaaS events, hence the need for a custom data type.
|
|
163
|
+
* Legacy events can provide an id with SDRN, while TPaaS events don't need it
|
|
164
|
+
*/
|
|
165
|
+
this.currentPage = {
|
|
166
|
+
id: 'unknown',
|
|
137
167
|
type: 'Page',
|
|
138
|
-
url:
|
|
168
|
+
url: isBrowser ? window.location.href : undefined,
|
|
139
169
|
};
|
|
140
|
-
this.currentPage = undefined;
|
|
141
170
|
/**
|
|
142
171
|
* Promise that resolves when a session ID becomes available
|
|
143
172
|
* @private
|
|
@@ -149,7 +178,7 @@ export default class Tracker {
|
|
|
149
178
|
*/
|
|
150
179
|
this.hasProxyListener = false;
|
|
151
180
|
this.setPageDefaults = (pageViewEvent) => {
|
|
152
|
-
this.
|
|
181
|
+
this.currentPage = pageFromPageView(pageViewEvent);
|
|
153
182
|
if (pageViewEvent.origin) {
|
|
154
183
|
const pageDefaults = { origin: pageViewEvent.origin };
|
|
155
184
|
this.update(pageDefaults, true);
|
|
@@ -157,8 +186,8 @@ export default class Tracker {
|
|
|
157
186
|
};
|
|
158
187
|
this.setCurrentPage = (id, type) => {
|
|
159
188
|
this.currentPage = {
|
|
160
|
-
|
|
161
|
-
|
|
189
|
+
id: id || 'unknown',
|
|
190
|
+
type: type || 'Page',
|
|
162
191
|
url: isBrowser ? window.location.href : undefined,
|
|
163
192
|
};
|
|
164
193
|
};
|
|
@@ -400,7 +429,9 @@ export default class Tracker {
|
|
|
400
429
|
return {
|
|
401
430
|
name: exp.name || exp.id,
|
|
402
431
|
variant: exp.variant || '',
|
|
403
|
-
|
|
432
|
+
// nobody should be sending experiment id with an sdrn format, but in case they do
|
|
433
|
+
// we want to be able to handle it and not generate an invalid sdrn by adding another layer to it
|
|
434
|
+
experimentSdrn: exp.id.startsWith('sdrn:') ? exp.id : generateExperimentSDRN(exp.id, exp.platform),
|
|
404
435
|
platform: exp.platform || '',
|
|
405
436
|
testId: exp.custom?.testId,
|
|
406
437
|
};
|
|
@@ -487,10 +518,11 @@ export default class Tracker {
|
|
|
487
518
|
source: source || 'unknown',
|
|
488
519
|
};
|
|
489
520
|
}
|
|
490
|
-
const [actor, consents, experiments] = await Promise.all([
|
|
521
|
+
const [actor, consents, experiments, currentPage] = await Promise.all([
|
|
491
522
|
this.getActor(),
|
|
492
523
|
this.getConsents(),
|
|
493
524
|
this.adaptExperiments(this.builders.experiments),
|
|
525
|
+
this.getCurrentTpaasPage(),
|
|
494
526
|
]);
|
|
495
527
|
const { environmentId, jwe } = parsePulseCookies();
|
|
496
528
|
return {
|
|
@@ -501,28 +533,12 @@ export default class Tracker {
|
|
|
501
533
|
consents: adaptConsentsToNewFormat(consents),
|
|
502
534
|
providerId: this.state.providerId,
|
|
503
535
|
pageviewId: this.state.pageViewId,
|
|
504
|
-
currentPage
|
|
536
|
+
currentPage,
|
|
505
537
|
experiments,
|
|
506
538
|
environmentId,
|
|
507
539
|
jwe,
|
|
508
540
|
};
|
|
509
541
|
}
|
|
510
|
-
/**
|
|
511
|
-
* Generate a generic TPaaS event with common builders output
|
|
512
|
-
* The method should be used for experiments, not for real production work.
|
|
513
|
-
* It doesn't have any real TPaaS schema associated with it.
|
|
514
|
-
* The method doesn't queue or send the event, it just returns the merged object.
|
|
515
|
-
* The method can be removed at any time in the future, so use it with caution.
|
|
516
|
-
*
|
|
517
|
-
* @param input - The input object to merge with the common builders output
|
|
518
|
-
* @returns A promise that resolves to the merged object
|
|
519
|
-
* @private
|
|
520
|
-
* @category TPaaS Tracking
|
|
521
|
-
*/
|
|
522
|
-
async generateGenericTpaasEvent(input) {
|
|
523
|
-
const dependencies = await this.prepareTpaasEvent();
|
|
524
|
-
return pulseMerge({}, input, getCommonBuildersOutput(new Date(), dependencies));
|
|
525
|
-
}
|
|
526
542
|
/**
|
|
527
543
|
* This method extends the list of base experiments that will be automatically included in every event sent by the tracker.
|
|
528
544
|
*
|
|
@@ -544,6 +560,9 @@ export default class Tracker {
|
|
|
544
560
|
* @category Tracking
|
|
545
561
|
*/
|
|
546
562
|
addExperiments(experiments) {
|
|
563
|
+
if (experiments.some((experiment) => experiment.id.startsWith('sdrn:'))) {
|
|
564
|
+
logger.warn('Pulse - addExperiments received an experiment id starting with "sdrn:"; pass the raw experiment id instead. The SDK will generate the sdrn automatically.');
|
|
565
|
+
}
|
|
547
566
|
this.update({ experiments }, true);
|
|
548
567
|
}
|
|
549
568
|
/**
|
|
@@ -578,7 +597,7 @@ export default class Tracker {
|
|
|
578
597
|
const viewUIElementInputProperties = buildEventFromElement(element);
|
|
579
598
|
this.trackLegacyViewUIElement(viewUIElementInputProperties);
|
|
580
599
|
}));
|
|
581
|
-
this.legacyVisibilityObservers.get(selector)?.observe(selector);
|
|
600
|
+
this.legacyVisibilityObservers.get(selector)?.observe(selector, {});
|
|
582
601
|
}
|
|
583
602
|
/**
|
|
584
603
|
* The `addUIElementVisibilityTracking` function provides an interface for sending tracking events when specific UI elements become visible within the viewport.
|
|
@@ -610,7 +629,38 @@ export default class Tracker {
|
|
|
610
629
|
const eventInput = buildEventFromElement(element);
|
|
611
630
|
this.trackImpressionUIElement(eventInput);
|
|
612
631
|
}));
|
|
613
|
-
this.visibilityObservers.get(selector)?.observe(selector);
|
|
632
|
+
this.visibilityObservers.get(selector)?.observe(selector, {});
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* The `addElementVisibilityObserver` function provides an interface for executing arbitrary code when specific DOM Elements become visible within the viewport.
|
|
636
|
+
* It is built on the `VisibilityObserver` class, which efficiently detects visibility changes in DOM elements.
|
|
637
|
+
* When an element becomes at least 2/3 visible, a callback is triggered, with the Element that invoked the callback call as argument.
|
|
638
|
+
* It leverages the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) for viewport tracking
|
|
639
|
+
* and the [Mutation Observer API](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to monitor lazy-loaded elements.
|
|
640
|
+
*
|
|
641
|
+
* Example usage:
|
|
642
|
+
*
|
|
643
|
+
* ```ts
|
|
644
|
+
* tracker.addElementVisibilityObserver('[data-pulse-entity-id]', (element) => {
|
|
645
|
+
* const eventInput = parseElementIntoEventInput(element); // user-defined function
|
|
646
|
+
* tracker.trackImpressionTeaser(eventInput); // can be anything actually, not necessarily a Teaser tracking call
|
|
647
|
+
* });
|
|
648
|
+
* ```
|
|
649
|
+
* @param selector
|
|
650
|
+
* @param callback
|
|
651
|
+
* @param options {ObserverOptions}
|
|
652
|
+
* @param options.threshold - A number between 0 and 1 indicating how much of the element should be visible to trigger
|
|
653
|
+
* the callback. Default is 0.67 (2/3 of the element).
|
|
654
|
+
*/
|
|
655
|
+
addElementVisibilityObserver(selector, callback, options = {}) {
|
|
656
|
+
if (this.visibilityObservers.has(selector)) {
|
|
657
|
+
console.warn(`Cannot add UI Element visibility tracking for selector "${selector}" as it is already being tracked.`);
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
this.visibilityObservers.set(selector, new VisibilityObserver((element) => {
|
|
661
|
+
callback(element);
|
|
662
|
+
}));
|
|
663
|
+
this.visibilityObservers.get(selector)?.observe(selector, options);
|
|
614
664
|
}
|
|
615
665
|
/**
|
|
616
666
|
* The old trackViewArticle method from the Media Wrapper.
|
|
@@ -704,7 +754,7 @@ export default class Tracker {
|
|
|
704
754
|
* @category Legacy Tracking
|
|
705
755
|
*/
|
|
706
756
|
trackLegacyViewUIElement(inputProperties, trackOptions) {
|
|
707
|
-
const viewUIElementEventData = buildLegacyViewUIElementEvent(inputProperties, this.
|
|
757
|
+
const viewUIElementEventData = buildLegacyViewUIElementEvent(inputProperties, this.getCurrentLegacyPage());
|
|
708
758
|
return this.track('trackerEvent', viewUIElementEventData, trackOptions);
|
|
709
759
|
}
|
|
710
760
|
/**
|
|
@@ -715,7 +765,7 @@ export default class Tracker {
|
|
|
715
765
|
* @category Legacy Tracking
|
|
716
766
|
*/
|
|
717
767
|
trackLegacyClickUIElement(inputProperties, trackOptions) {
|
|
718
|
-
const clickUIElementEventData = buildClickUIElementEvent(inputProperties, this.
|
|
768
|
+
const clickUIElementEventData = buildClickUIElementEvent(inputProperties, this.getCurrentLegacyPage());
|
|
719
769
|
return this.track('trackerEvent', clickUIElementEventData, trackOptions);
|
|
720
770
|
}
|
|
721
771
|
/**
|
|
@@ -788,10 +838,9 @@ export default class Tracker {
|
|
|
788
838
|
const result = this.sendTpaasEvent(event);
|
|
789
839
|
if (shouldEnableLeaveTracking(options.leaveTracking)) {
|
|
790
840
|
const leavePageCallback = async (leave) => {
|
|
791
|
-
const { metrics, ...rest } = input; // metrics are not part of LeavePage schema, so we need to omit them
|
|
792
841
|
await this.trackLeavePage({
|
|
793
842
|
leave,
|
|
794
|
-
...
|
|
843
|
+
...input,
|
|
795
844
|
});
|
|
796
845
|
};
|
|
797
846
|
addTpaasLeaveTracking({
|
|
@@ -862,12 +911,9 @@ export default class Tracker {
|
|
|
862
911
|
const result = this.sendTpaasEvent(event);
|
|
863
912
|
if (shouldEnableLeaveTracking(options.leaveTracking)) {
|
|
864
913
|
const leaveArticleCallback = async (leave) => {
|
|
865
|
-
// omit these properties from LeaveArticle because they're not part of the LeaveArticle schema
|
|
866
|
-
const { authors, hotness, lifetime, sponsor, wordCount, ...rest } = input.object;
|
|
867
914
|
await this.trackLeaveArticle({
|
|
868
915
|
leave,
|
|
869
916
|
...input,
|
|
870
|
-
object: rest,
|
|
871
917
|
});
|
|
872
918
|
};
|
|
873
919
|
addTpaasLeaveTracking({
|
|
@@ -977,6 +1023,15 @@ export default class Tracker {
|
|
|
977
1023
|
}
|
|
978
1024
|
return result;
|
|
979
1025
|
}
|
|
1026
|
+
/**
|
|
1027
|
+
* @param input
|
|
1028
|
+
* @category TPaaS Tracking
|
|
1029
|
+
*/
|
|
1030
|
+
async trackImpressionAdSlot(input) {
|
|
1031
|
+
const dependencies = await this.prepareTpaasEvent();
|
|
1032
|
+
const event = buildImpressionAdSlotEvent(input, dependencies);
|
|
1033
|
+
return this.sendTpaasEvent(event);
|
|
1034
|
+
}
|
|
980
1035
|
/**
|
|
981
1036
|
* @param input
|
|
982
1037
|
* @category TPaaS Tracking
|
|
@@ -1035,10 +1090,9 @@ export default class Tracker {
|
|
|
1035
1090
|
const result = this.sendTpaasEvent(event);
|
|
1036
1091
|
if (shouldEnableLeaveTracking(options.leaveTracking)) {
|
|
1037
1092
|
const leaveFrontpageCallback = async (leave) => {
|
|
1038
|
-
const { metrics, ...rest } = input; // metrics are not part of LeaveFrontpage schema, so we need to omit them
|
|
1039
1093
|
await this.trackLeaveFrontpage({
|
|
1040
1094
|
leave,
|
|
1041
|
-
...
|
|
1095
|
+
...input,
|
|
1042
1096
|
});
|
|
1043
1097
|
};
|
|
1044
1098
|
addTpaasLeaveTracking({
|
|
@@ -1114,12 +1168,9 @@ export default class Tracker {
|
|
|
1114
1168
|
const result = this.sendTpaasEvent(event);
|
|
1115
1169
|
if (shouldEnableLeaveTracking(options.leaveTracking)) {
|
|
1116
1170
|
const leaveLockedArticleCallback = async (leave) => {
|
|
1117
|
-
// omit these properties because they're not part of the LeaveLockedArticle schema
|
|
1118
|
-
const { authors, hotness, lifetime, sponsor, wordCount, ...rest } = input.object;
|
|
1119
1171
|
await this.trackLeaveLockedArticle({
|
|
1120
1172
|
leave,
|
|
1121
1173
|
...input,
|
|
1122
|
-
object: rest,
|
|
1123
1174
|
});
|
|
1124
1175
|
};
|
|
1125
1176
|
addTpaasLeaveTracking({
|
|
@@ -1265,11 +1316,9 @@ export default class Tracker {
|
|
|
1265
1316
|
const result = this.sendTpaasEvent(event);
|
|
1266
1317
|
if (shouldEnableLeaveTracking(options.leaveTracking)) {
|
|
1267
1318
|
const leaveWeatherCallback = async (leave) => {
|
|
1268
|
-
// omit object and page from input because they're not part of the LeaveWeather schema
|
|
1269
|
-
const { object, page, ...rest } = input;
|
|
1270
1319
|
await this.trackLeaveWeather({
|
|
1271
1320
|
leave,
|
|
1272
|
-
...
|
|
1321
|
+
...input,
|
|
1273
1322
|
});
|
|
1274
1323
|
};
|
|
1275
1324
|
addTpaasLeaveTracking({
|
package/dist/ejs/version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
// This file is auto-generated by bin/generate-version.js. Do not edit manually.
|
|
2
|
-
export const SDK_VERSION = '8.0.0-rc.
|
|
2
|
+
export const SDK_VERSION = '8.0.0-rc.8';
|
|
@@ -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() {
|
package/dist/types/Tracker.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { type AdvertisingIdentifiers, type AdvertisingVendor } from '@schibsted/pulse-cis-sync';
|
|
2
|
-
import {
|
|
3
|
-
import { type IAnonymousViewUIElement, type ICompletedHealthAction, type IEngagementAudio, type IEngagementForm, type IEngagementHealthUIElement, type IEngagementOffer, type IEngagementTeaser, type IEngagementUIElement, type IEngagementVideo, type IEngagementVideoAd, type IEngagementWidget, type IImpressionForm, type IImpressionHealthUIElement, type IImpressionOffer, type IImpressionPlayer, type IImpressionTeaser, type IImpressionUIElement, type IImpressionWidget, type ILeave, type ILeaveArticle, type ILeaveAudioPage, type ILeaveError, type ILeaveFrontpage, type ILeaveLandingpage, type ILeaveListing, type ILeaveLockedArticle, type ILeaveLockedAudioPage, type ILeaveLockedVideoPage, type ILeavePage, type ILeaveSportsPage, type ILeaveVideoPage, type ILeaveWeather, type ITpaasEvent, type IViewArticle, type IViewAudioPage, type IViewError, type IViewFrontpage, type IViewHealthPage, type IViewLandingpage, type IViewListing, type IViewLockedArticle, type IViewLockedAudioPage, type IViewLockedVideoPage, type IViewPage, type IViewSportsPage, type IViewTitle, type IViewVideoPage, type IViewWeather } from '@schibsted/tpaas-schemas';
|
|
2
|
+
import { type IAnonymousViewUIElement, type ICompletedHealthAction, type IEngagementAudio, type IEngagementForm, type IEngagementHealthUIElement, type IEngagementOffer, type IEngagementTeaser, type IEngagementUIElement, type IEngagementVideo, type IEngagementVideoAd, type IEngagementWidget, type IImpressionAdSlot, type IImpressionForm, type IImpressionHealthUIElement, type IImpressionOffer, type IImpressionPlayer, type IImpressionTeaser, type IImpressionUIElement, type IImpressionWidget, type ILeave, type ILeaveArticle, type ILeaveAudioPage, type ILeaveError, type ILeaveFrontpage, type ILeaveLandingpage, type ILeaveListing, type ILeaveLockedArticle, type ILeaveLockedAudioPage, type ILeaveLockedVideoPage, type ILeavePage, type ILeaveSportsPage, type ILeaveVideoPage, type ILeaveWeather, type InputParams, type ITpaasEvent, type IViewArticle, type IViewAudioPage, type IViewError, type IViewFrontpage, type IViewHealthPage, type IViewLandingpage, type IViewListing, type IViewLockedArticle, type IViewLockedAudioPage, type IViewLockedVideoPage, type IViewPage, type IViewSportsPage, type IViewTitle, type IViewVideoPage, type IViewWeather } from '@schibsted/tpaas-schemas';
|
|
4
3
|
import logger from 'loglevel';
|
|
5
4
|
import type { ActorInput, Consents, ConsentsInput, DeviceInput, LocationInput, ObjectInput, OriginInput, ProviderInput, TrackerInput } from './builders';
|
|
6
5
|
import { engagementEvent, identityEvent, routableEvent, trackerEvent } from './builders/events';
|
|
@@ -9,8 +8,9 @@ import type { Deferred, ResolvedInput } from './defer';
|
|
|
9
8
|
import { type Listener } from './EventBus/EventBus';
|
|
10
9
|
import type { LeaveEvent, LeaveEventBuilder, LeaveEventOptions } from './leaveTracking/types';
|
|
11
10
|
import type { AnonymousEventInputTypesByTrackingMethod, EventInput, EventInputTypesByTrackingMethod, TrackViewEventOptions } from './types';
|
|
11
|
+
import { type ObserverOptions } from './visibility-observer';
|
|
12
12
|
import type { ClickUIElementInputProperties } from './wrapper/engagement/ui-element/types';
|
|
13
|
-
import type
|
|
13
|
+
import { type BaseEventExperiment } from './wrapper/types';
|
|
14
14
|
import type { ViewArticleInputProperties } from './wrapper/view/article/types';
|
|
15
15
|
import type { ViewFrontpageInputProperties } from './wrapper/view/frontpage/types';
|
|
16
16
|
import type { ViewListingInputProperties } from './wrapper/view/listing/types';
|
|
@@ -273,8 +273,16 @@ export default class Tracker {
|
|
|
273
273
|
private bookmark;
|
|
274
274
|
private legacyVisibilityObservers;
|
|
275
275
|
private visibilityObservers;
|
|
276
|
-
|
|
276
|
+
/**
|
|
277
|
+
* @private
|
|
278
|
+
*
|
|
279
|
+
* This is used as the source of truth for the current page's information, which is updated based on the View Page-level event
|
|
280
|
+
* As a single source of truth for the current page, this needs to be compatible between legacy and TPaaS events, hence the need for a custom data type.
|
|
281
|
+
* Legacy events can provide an id with SDRN, while TPaaS events don't need it
|
|
282
|
+
*/
|
|
277
283
|
private currentPage;
|
|
284
|
+
private getCurrentTpaasPage;
|
|
285
|
+
private getCurrentLegacyPage;
|
|
278
286
|
/**
|
|
279
287
|
* Promise that resolves when a session ID becomes available
|
|
280
288
|
* @private
|
|
@@ -380,19 +388,6 @@ export default class Tracker {
|
|
|
380
388
|
* @category TPaaS Tracking
|
|
381
389
|
*/
|
|
382
390
|
private prepareTpaasEvent;
|
|
383
|
-
/**
|
|
384
|
-
* Generate a generic TPaaS event with common builders output
|
|
385
|
-
* The method should be used for experiments, not for real production work.
|
|
386
|
-
* It doesn't have any real TPaaS schema associated with it.
|
|
387
|
-
* The method doesn't queue or send the event, it just returns the merged object.
|
|
388
|
-
* The method can be removed at any time in the future, so use it with caution.
|
|
389
|
-
*
|
|
390
|
-
* @param input - The input object to merge with the common builders output
|
|
391
|
-
* @returns A promise that resolves to the merged object
|
|
392
|
-
* @private
|
|
393
|
-
* @category TPaaS Tracking
|
|
394
|
-
*/
|
|
395
|
-
generateGenericTpaasEvent<T>(input: T): Promise<T & ReturnType<typeof getCommonBuildersOutput>>;
|
|
396
391
|
/**
|
|
397
392
|
* This method extends the list of base experiments that will be automatically included in every event sent by the tracker.
|
|
398
393
|
*
|
|
@@ -460,6 +455,28 @@ export default class Tracker {
|
|
|
460
455
|
* @category Tracking
|
|
461
456
|
*/
|
|
462
457
|
addUIElementVisibilityTracking(selector: string, buildEventFromElement: (element: HTMLElement) => InputParams<IImpressionUIElement>): void;
|
|
458
|
+
/**
|
|
459
|
+
* The `addElementVisibilityObserver` function provides an interface for executing arbitrary code when specific DOM Elements become visible within the viewport.
|
|
460
|
+
* It is built on the `VisibilityObserver` class, which efficiently detects visibility changes in DOM elements.
|
|
461
|
+
* When an element becomes at least 2/3 visible, a callback is triggered, with the Element that invoked the callback call as argument.
|
|
462
|
+
* It leverages the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) for viewport tracking
|
|
463
|
+
* and the [Mutation Observer API](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver) to monitor lazy-loaded elements.
|
|
464
|
+
*
|
|
465
|
+
* Example usage:
|
|
466
|
+
*
|
|
467
|
+
* ```ts
|
|
468
|
+
* tracker.addElementVisibilityObserver('[data-pulse-entity-id]', (element) => {
|
|
469
|
+
* const eventInput = parseElementIntoEventInput(element); // user-defined function
|
|
470
|
+
* tracker.trackImpressionTeaser(eventInput); // can be anything actually, not necessarily a Teaser tracking call
|
|
471
|
+
* });
|
|
472
|
+
* ```
|
|
473
|
+
* @param selector
|
|
474
|
+
* @param callback
|
|
475
|
+
* @param options {ObserverOptions}
|
|
476
|
+
* @param options.threshold - A number between 0 and 1 indicating how much of the element should be visible to trigger
|
|
477
|
+
* the callback. Default is 0.67 (2/3 of the element).
|
|
478
|
+
*/
|
|
479
|
+
addElementVisibilityObserver(selector: string, callback: (element: HTMLElement) => void, options?: ObserverOptions): void;
|
|
463
480
|
private setPageDefaults;
|
|
464
481
|
/**
|
|
465
482
|
* The old trackViewArticle method from the Media Wrapper.
|
|
@@ -625,6 +642,11 @@ export default class Tracker {
|
|
|
625
642
|
* @category TPaaS Tracking
|
|
626
643
|
*/
|
|
627
644
|
trackViewError(input: InputParams<IViewError>, options: TrackViewEventOptions<IViewError>): Promise<unknown>;
|
|
645
|
+
/**
|
|
646
|
+
* @param input
|
|
647
|
+
* @category TPaaS Tracking
|
|
648
|
+
*/
|
|
649
|
+
trackImpressionAdSlot(input: InputParams<IImpressionAdSlot>): Promise<unknown>;
|
|
628
650
|
/**
|
|
629
651
|
* @param input
|
|
630
652
|
* @category TPaaS Tracking
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { TrackerEventInput } from './events';
|
|
2
|
+
export declare function generateExperimentSDRN(id?: string | number, experimentationPlatform?: string): string;
|
|
2
3
|
/**
|
|
3
4
|
* The necessary values to construct a valid "sdrn" for experiment.
|
|
4
5
|
* Additional properties are allowed.
|
package/dist/types/index.d.ts
CHANGED
|
@@ -5,7 +5,6 @@ export { TrackerEventInput } from './builders/events-node';
|
|
|
5
5
|
export * from './Tracker';
|
|
6
6
|
export { EventInput } from './types';
|
|
7
7
|
export { T as Tracker };
|
|
8
|
-
export type { InputParams } from '@schibsted/tpaas-event-builder';
|
|
9
8
|
export * from '@schibsted/tpaas-schemas';
|
|
10
9
|
export type { IPulseTrackerCreateParams } from './createPulseTracker';
|
|
11
10
|
export { createPulseTracker } from './createPulseTracker';
|
|
@@ -17,7 +17,7 @@ export declare const MESSAGE_TYPE_INVOKE = "pulse-tracker-proxy:invoke";
|
|
|
17
17
|
export declare const MESSAGE_TYPE_RETURN = "pulse-tracker-proxy:return";
|
|
18
18
|
export declare const MESSAGE_TYPE_RETURN_ERROR = "pulse-tracker-proxy:return-error";
|
|
19
19
|
export declare const ALLOWED_METHODS: readonly ["track"];
|
|
20
|
-
export declare const TPAAS_ALLOWED_METHODS: readonly ["trackAnonymousViewUIElement", "trackEngagementAudio", "trackEngagementForm", "trackEngagementHealthUIElement", "trackEngagementOffer", "trackEngagementTeaser", "trackEngagementUIElement", "trackEngagementVideo", "trackEngagementVideoAd", "trackEngagementWidget", "trackCompletedHealthAction", "trackImpressionForm", "trackImpressionHealthUIElement", "trackImpressionOffer", "trackImpressionPlayer", "trackImpressionTeaser", "trackImpressionUIElement", "trackImpressionWidget", "trackLeaveArticle", "trackLeaveAudioPage", "trackLeaveError", "trackLeaveFrontpage", "trackLeaveLandingpage", "trackLeaveListing", "trackLeaveLockedArticle", "trackLeaveLockedAudioPage", "trackLeaveLockedVideoPage", "trackLeavePage", "trackLeaveSportsPage", "trackLeaveVideoPage", "trackLeaveWeather", "trackViewArticle", "trackViewAudioPage", "trackViewError", "trackViewFrontpage", "trackViewHealthPage", "trackViewLandingpage", "trackViewListing", "trackViewLockedArticle", "trackViewLockedAudioPage", "trackViewLockedVideoPage", "trackViewPage", "trackViewSportsPage", "trackViewTitle", "trackViewVideoPage", "trackViewWeather", "trackLegacyViewArticle", "trackLegacyViewLoginPoster", "trackLegacyViewSalesPoster", "trackLegacyViewListing", "trackLegacyViewFrontpage", "trackLegacyViewPage", "trackLegacyViewUIElement", "trackLegacyClickUIElement"];
|
|
20
|
+
export declare const TPAAS_ALLOWED_METHODS: readonly ["trackAnonymousViewUIElement", "trackEngagementAudio", "trackEngagementForm", "trackEngagementHealthUIElement", "trackEngagementOffer", "trackEngagementTeaser", "trackEngagementUIElement", "trackEngagementVideo", "trackEngagementVideoAd", "trackEngagementWidget", "trackCompletedHealthAction", "trackImpressionAdSlot", "trackImpressionForm", "trackImpressionHealthUIElement", "trackImpressionOffer", "trackImpressionPlayer", "trackImpressionTeaser", "trackImpressionUIElement", "trackImpressionWidget", "trackLeaveArticle", "trackLeaveAudioPage", "trackLeaveError", "trackLeaveFrontpage", "trackLeaveLandingpage", "trackLeaveListing", "trackLeaveLockedArticle", "trackLeaveLockedAudioPage", "trackLeaveLockedVideoPage", "trackLeavePage", "trackLeaveSportsPage", "trackLeaveVideoPage", "trackLeaveWeather", "trackViewArticle", "trackViewAudioPage", "trackViewError", "trackViewFrontpage", "trackViewHealthPage", "trackViewLandingpage", "trackViewListing", "trackViewLockedArticle", "trackViewLockedAudioPage", "trackViewLockedVideoPage", "trackViewPage", "trackViewSportsPage", "trackViewTitle", "trackViewVideoPage", "trackViewWeather", "trackLegacyViewArticle", "trackLegacyViewLoginPoster", "trackLegacyViewSalesPoster", "trackLegacyViewListing", "trackLegacyViewFrontpage", "trackLegacyViewPage", "trackLegacyViewUIElement", "trackLegacyClickUIElement"];
|
|
21
21
|
export declare function isPulseProxyMessage(message: unknown): message is Message;
|
|
22
22
|
export type TrackInvocation = {
|
|
23
23
|
method: 'track';
|
package/dist/types/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const SDK_VERSION = "8.0.0-rc.
|
|
1
|
+
export declare const SDK_VERSION = "8.0.0-rc.8";
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
type ComponentViewCallback = (node: HTMLElement) => void;
|
|
2
|
+
export interface ObserverOptions {
|
|
3
|
+
threshold?: number;
|
|
4
|
+
}
|
|
2
5
|
/**
|
|
3
6
|
* Observes visibility of elements matching a selector using MutationObserver and IntersectionObserver.
|
|
4
7
|
*/
|
|
@@ -16,9 +19,11 @@ export declare class VisibilityObserver {
|
|
|
16
19
|
* Uses {@link https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver | MutationObserver} to monitor the DOM for dynamically loaded content.
|
|
17
20
|
* Callback is invoked only once per element.
|
|
18
21
|
* @param selector The CSS selector for elements to track.
|
|
22
|
+
* @param options {ObserverOptions} Optional configuration for the observer.
|
|
23
|
+
* @param options.threshold Which ratio triggers the Observer callback.
|
|
19
24
|
* @throws Error if called more than once.
|
|
20
25
|
*/
|
|
21
|
-
observe(selector: string): void;
|
|
26
|
+
observe(selector: string, { threshold }: ObserverOptions): void;
|
|
22
27
|
/**
|
|
23
28
|
* @returns {HTMLElement[]} An array of elements that match the selector in the document.
|
|
24
29
|
*/
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
type NavigationType = 'navigation' | 'alternative' | 'refresh' | 'unknown';
|
|
2
|
-
|
|
2
|
+
declare const LEGACY_PAGE_TYPE_VALUES: readonly ["Article", "Listing", "Frontpage", "SalesPoster", "Page", "LoginPoster"];
|
|
3
|
+
export declare function isLegacyPageType(value: string): value is PageType;
|
|
4
|
+
type PageType = (typeof LEGACY_PAGE_TYPE_VALUES)[number];
|
|
3
5
|
type TargetCategory = 'Article' | 'Audio' | 'Video' | 'Weather' | 'Title' | 'other';
|
|
4
6
|
type TargetType = 'Article' | 'ArticleReference' | 'ExternalContent';
|
|
5
7
|
type SalesPosterType = 'Ip' | 'Login' | 'Paid' | 'Meter' | 'Personalised';
|