@guardian/commercial-core 0.40.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/EventTimer.d.ts +12 -6
- package/dist/cjs/EventTimer.js +7 -2
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.js +3 -2
- package/dist/cjs/sendCommercialMetrics.d.ts +51 -1
- package/dist/cjs/sendCommercialMetrics.js +143 -36
- package/dist/esm/EventTimer.d.ts +12 -6
- package/dist/esm/EventTimer.js +7 -2
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/sendCommercialMetrics.d.ts +51 -1
- package/dist/esm/sendCommercialMetrics.js +140 -34
- package/package.json +3 -2
package/dist/cjs/EventTimer.d.ts
CHANGED
|
@@ -19,7 +19,16 @@ interface SlotEventStatus {
|
|
|
19
19
|
}
|
|
20
20
|
interface PageEventStatus {
|
|
21
21
|
commercialStart: boolean;
|
|
22
|
-
|
|
22
|
+
commercialExtraModulesLoaded: boolean;
|
|
23
|
+
commercialBaseModulesLoaded: boolean;
|
|
24
|
+
commercialModulesLoaded: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface EventTimerProperties {
|
|
27
|
+
type?: ConnectionType;
|
|
28
|
+
downlink?: number;
|
|
29
|
+
effectiveType?: string;
|
|
30
|
+
adSlotsInline?: number;
|
|
31
|
+
adSlotsTotal?: number;
|
|
23
32
|
}
|
|
24
33
|
export declare class EventTimer {
|
|
25
34
|
private _events;
|
|
@@ -31,11 +40,7 @@ export declare class EventTimer {
|
|
|
31
40
|
page: PageEventStatus;
|
|
32
41
|
};
|
|
33
42
|
gaConfig: GAConfig;
|
|
34
|
-
properties:
|
|
35
|
-
type?: ConnectionType;
|
|
36
|
-
downlink?: number;
|
|
37
|
-
effectiveType?: string;
|
|
38
|
-
};
|
|
43
|
+
properties: EventTimerProperties;
|
|
39
44
|
/**
|
|
40
45
|
* Initialise the EventTimer class on page.
|
|
41
46
|
* Returns the singleton instance of the EventTimer class and binds
|
|
@@ -58,6 +63,7 @@ export declare class EventTimer {
|
|
|
58
63
|
*/
|
|
59
64
|
get events(): Event[];
|
|
60
65
|
private constructor();
|
|
66
|
+
setProperty(name: 'adSlotsInline' | 'adSlotsTotal', value: number): void;
|
|
61
67
|
/**
|
|
62
68
|
* Creates a new performance mark
|
|
63
69
|
* For slot events also ensures each TYPE of event event is marked only once for 'first'
|
package/dist/cjs/EventTimer.js
CHANGED
|
@@ -29,7 +29,9 @@ class EventTimer {
|
|
|
29
29
|
},
|
|
30
30
|
page: {
|
|
31
31
|
commercialStart: false,
|
|
32
|
-
|
|
32
|
+
commercialExtraModulesLoaded: false,
|
|
33
|
+
commercialBaseModulesLoaded: false,
|
|
34
|
+
commercialModulesLoaded: false,
|
|
33
35
|
},
|
|
34
36
|
};
|
|
35
37
|
this.gaConfig = {
|
|
@@ -45,7 +47,7 @@ class EventTimer {
|
|
|
45
47
|
timingLabel: 'Commercial start parse time',
|
|
46
48
|
},
|
|
47
49
|
{
|
|
48
|
-
timingVariable: '
|
|
50
|
+
timingVariable: 'commercialModulesLoaded',
|
|
49
51
|
timingLabel: 'Commercial end parse time',
|
|
50
52
|
},
|
|
51
53
|
],
|
|
@@ -106,6 +108,9 @@ class EventTimer {
|
|
|
106
108
|
]
|
|
107
109
|
: this._events;
|
|
108
110
|
}
|
|
111
|
+
setProperty(name, value) {
|
|
112
|
+
this.properties[name] = value;
|
|
113
|
+
}
|
|
109
114
|
/**
|
|
110
115
|
* Creates a new performance mark
|
|
111
116
|
* For slot events also ensures each TYPE of event event is marked only once for 'first'
|
package/dist/cjs/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { twitter } from './third-party-tags/twitter-uwt';
|
|
|
5
5
|
export { inizio } from './third-party-tags/inizio';
|
|
6
6
|
export { remarketing } from './third-party-tags/remarketing';
|
|
7
7
|
export { EventTimer } from './EventTimer';
|
|
8
|
-
export {
|
|
8
|
+
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './sendCommercialMetrics';
|
|
9
9
|
export type { ThirdPartyTag } from './types';
|
|
10
10
|
export { adSizes, getAdSize } from './ad-sizes';
|
|
11
11
|
export type { SizeKeys, AdSizeString, AdSize } from './ad-sizes';
|
package/dist/cjs/index.js
CHANGED
|
@@ -20,7 +20,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
20
20
|
return result;
|
|
21
21
|
};
|
|
22
22
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
-
exports.pickTargetingValues = exports.getViewportTargeting = exports.getSharedTargeting = exports.getSessionTargeting = exports.getPersonalisedTargeting = exports.getContentTargeting = exports.constants = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.getAdSize = exports.adSizes = exports.
|
|
23
|
+
exports.pickTargetingValues = exports.getViewportTargeting = exports.getSharedTargeting = exports.getSessionTargeting = exports.getPersonalisedTargeting = exports.getContentTargeting = exports.constants = exports.disabledAds = exports.buildAdsConfigWithConsent = exports.getPermutivePFPSegments = exports.getPermutiveSegments = exports.clearPermutiveSegments = exports.isAdBlockInUse = exports.getAdSize = exports.adSizes = exports.initCommercialMetrics = exports.bypassCommercialMetricsSampling = exports.EventTimer = exports.remarketing = exports.inizio = exports.twitter = exports.fbPixel = exports.permutive = exports.ias = void 0;
|
|
24
24
|
var ias_1 = require("./third-party-tags/ias");
|
|
25
25
|
Object.defineProperty(exports, "ias", { enumerable: true, get: function () { return ias_1.ias; } });
|
|
26
26
|
var permutive_1 = require("./third-party-tags/permutive");
|
|
@@ -36,7 +36,8 @@ Object.defineProperty(exports, "remarketing", { enumerable: true, get: function
|
|
|
36
36
|
var EventTimer_1 = require("./EventTimer");
|
|
37
37
|
Object.defineProperty(exports, "EventTimer", { enumerable: true, get: function () { return EventTimer_1.EventTimer; } });
|
|
38
38
|
var sendCommercialMetrics_1 = require("./sendCommercialMetrics");
|
|
39
|
-
Object.defineProperty(exports, "
|
|
39
|
+
Object.defineProperty(exports, "bypassCommercialMetricsSampling", { enumerable: true, get: function () { return sendCommercialMetrics_1.bypassCommercialMetricsSampling; } });
|
|
40
|
+
Object.defineProperty(exports, "initCommercialMetrics", { enumerable: true, get: function () { return sendCommercialMetrics_1.initCommercialMetrics; } });
|
|
40
41
|
var ad_sizes_1 = require("./ad-sizes");
|
|
41
42
|
Object.defineProperty(exports, "adSizes", { enumerable: true, get: function () { return ad_sizes_1.adSizes; } });
|
|
42
43
|
Object.defineProperty(exports, "getAdSize", { enumerable: true, get: function () { return ad_sizes_1.getAdSize; } });
|
|
@@ -1 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
declare type Metric = {
|
|
2
|
+
name: string;
|
|
3
|
+
value: number;
|
|
4
|
+
};
|
|
5
|
+
declare type Property = {
|
|
6
|
+
name: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
declare type TimedEvent = {
|
|
10
|
+
name: string;
|
|
11
|
+
ts: number;
|
|
12
|
+
};
|
|
13
|
+
declare type EventProperties = {
|
|
14
|
+
type?: ConnectionType;
|
|
15
|
+
downlink?: number;
|
|
16
|
+
effectiveType?: string;
|
|
17
|
+
};
|
|
18
|
+
declare enum Endpoints {
|
|
19
|
+
CODE = "//performance-events.code.dev-guardianapis.com/commercial-metrics",
|
|
20
|
+
PROD = "//performance-events.guardianapis.com/commercial-metrics"
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A method to asynchronously send metrics after initialization.
|
|
24
|
+
*/
|
|
25
|
+
export declare function bypassCommercialMetricsSampling(): void;
|
|
26
|
+
interface InitCommercialMetricsArgs {
|
|
27
|
+
pageViewId: string;
|
|
28
|
+
browserId: string | undefined;
|
|
29
|
+
isDev: boolean;
|
|
30
|
+
adBlockerInUse?: boolean;
|
|
31
|
+
sampling?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A method to initialise metrics.
|
|
35
|
+
* @param init.pageViewId - identifies the page view. Usually available on `guardian.config.ophan.pageViewId`. Defaults to `null`
|
|
36
|
+
* @param init.browserId - identifies the browser. Usually available via `getCookie({ name: 'bwid' })`. Defaults to `null`
|
|
37
|
+
* @param init.isDev - used to determine whether to use CODE or PROD endpoints.
|
|
38
|
+
* @param init.adBlockerInUse - indicates whether or not an adblocker is being used.
|
|
39
|
+
* @param init.sampling - rate at which to sample commercial metrics - the default is to send for 1% of pageviews
|
|
40
|
+
*/
|
|
41
|
+
export declare function initCommercialMetrics({ pageViewId, browserId, isDev, adBlockerInUse, sampling, }: InitCommercialMetricsArgs): boolean;
|
|
42
|
+
export declare const _: {
|
|
43
|
+
Endpoints: typeof Endpoints;
|
|
44
|
+
setEndpoint: (isDev: boolean) => Endpoints;
|
|
45
|
+
filterUndefinedProperties: <T>(transformedProperties: [string, T | undefined][]) => [string, T][];
|
|
46
|
+
mapEventTimerPropertiesToString: (properties: Array<[string, string | number]>) => Property[];
|
|
47
|
+
roundTimeStamp: (events: TimedEvent[]) => Metric[];
|
|
48
|
+
transformToObjectEntries: (eventTimerProperties: EventProperties) => Array<[string, string | number | undefined]>;
|
|
49
|
+
reset: () => void;
|
|
50
|
+
};
|
|
51
|
+
export type { Property, TimedEvent, Metric };
|
|
@@ -1,44 +1,151 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports._ = exports.initCommercialMetrics = exports.bypassCommercialMetricsSampling = void 0;
|
|
4
4
|
const libs_1 = require("@guardian/libs");
|
|
5
5
|
const EventTimer_1 = require("./EventTimer");
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
6
|
+
var Endpoints;
|
|
7
|
+
(function (Endpoints) {
|
|
8
|
+
Endpoints["CODE"] = "//performance-events.code.dev-guardianapis.com/commercial-metrics";
|
|
9
|
+
Endpoints["PROD"] = "//performance-events.guardianapis.com/commercial-metrics";
|
|
10
|
+
})(Endpoints || (Endpoints = {}));
|
|
11
|
+
let commercialMetricsPayload = {
|
|
12
|
+
page_view_id: undefined,
|
|
13
|
+
browser_id: undefined,
|
|
14
|
+
platform: 'NEXT_GEN',
|
|
15
|
+
metrics: [],
|
|
16
|
+
properties: [],
|
|
17
|
+
};
|
|
18
|
+
let devProperties = [];
|
|
19
|
+
let adBlockerProperties = [];
|
|
20
|
+
let initialised = false;
|
|
21
|
+
let endpoint;
|
|
22
|
+
const setEndpoint = (isDev) => (endpoint = isDev ? Endpoints.CODE : Endpoints.PROD);
|
|
23
|
+
const setDevProperties = (isDev) => (devProperties = isDev
|
|
24
|
+
? [{ name: 'isDev', value: window.location.hostname }]
|
|
25
|
+
: []);
|
|
26
|
+
const setAdBlockerProperties = (adBlockerInUse) => {
|
|
27
|
+
adBlockerProperties =
|
|
28
|
+
adBlockerInUse !== undefined
|
|
29
|
+
? [
|
|
30
|
+
{
|
|
31
|
+
name: 'adBlockerInUse',
|
|
32
|
+
value: adBlockerInUse.toString(),
|
|
33
|
+
},
|
|
34
|
+
]
|
|
35
|
+
: [];
|
|
36
|
+
};
|
|
37
|
+
const transformToObjectEntries = (eventTimerProperties) => {
|
|
38
|
+
// Transforms object {key: value} pairs into an array of [key, value] arrays
|
|
39
|
+
return Object.entries(eventTimerProperties);
|
|
40
|
+
};
|
|
41
|
+
const filterUndefinedProperties = (transformedProperties) => transformedProperties.reduce((acc, [key, value]) => {
|
|
42
|
+
if (typeof value !== 'undefined') {
|
|
43
|
+
acc.push([key, value]);
|
|
44
|
+
}
|
|
45
|
+
return acc;
|
|
46
|
+
}, []);
|
|
47
|
+
const mapEventTimerPropertiesToString = (properties) => {
|
|
48
|
+
return properties.map(([name, value]) => ({
|
|
49
|
+
name: String(name),
|
|
50
|
+
value: String(value),
|
|
51
|
+
}));
|
|
52
|
+
};
|
|
53
|
+
const roundTimeStamp = (events) => {
|
|
54
|
+
return events.map(({ name, ts }) => ({
|
|
31
55
|
name,
|
|
32
56
|
value: Math.ceil(ts),
|
|
33
57
|
}));
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
58
|
+
};
|
|
59
|
+
function sendMetrics() {
|
|
60
|
+
(0, libs_1.log)('commercial', 'About to send commercial metrics', commercialMetricsPayload);
|
|
61
|
+
return navigator.sendBeacon(endpoint, JSON.stringify(commercialMetricsPayload));
|
|
62
|
+
}
|
|
63
|
+
function gatherMetricsOnPageUnload() {
|
|
64
|
+
// Assemble commercial properties and metrics
|
|
65
|
+
const eventTimer = EventTimer_1.EventTimer.get();
|
|
66
|
+
const transformedEntries = transformToObjectEntries(eventTimer.properties);
|
|
67
|
+
const filteredEventTimerProperties = filterUndefinedProperties(transformedEntries);
|
|
68
|
+
const mappedEventTimerProperties = mapEventTimerPropertiesToString(filteredEventTimerProperties);
|
|
69
|
+
const properties = mappedEventTimerProperties
|
|
70
|
+
.concat(devProperties)
|
|
71
|
+
.concat(adBlockerProperties);
|
|
72
|
+
commercialMetricsPayload.properties = properties;
|
|
73
|
+
const metrics = roundTimeStamp(eventTimer.events);
|
|
74
|
+
commercialMetricsPayload.metrics = metrics;
|
|
75
|
+
sendMetrics();
|
|
76
|
+
}
|
|
77
|
+
const listener = (e) => {
|
|
78
|
+
switch (e.type) {
|
|
79
|
+
case 'visibilitychange':
|
|
80
|
+
if (document.visibilityState === 'hidden') {
|
|
81
|
+
gatherMetricsOnPageUnload();
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
case 'pagehide':
|
|
85
|
+
gatherMetricsOnPageUnload();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
const addVisibilityListeners = () => {
|
|
90
|
+
// Report all available metrics when the page is unloaded or in background.
|
|
91
|
+
window.addEventListener('visibilitychange', listener);
|
|
92
|
+
// Safari does not reliably fire the `visibilitychange` on page unload.
|
|
93
|
+
window.addEventListener('pagehide', listener);
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* A method to asynchronously send metrics after initialization.
|
|
97
|
+
*/
|
|
98
|
+
function bypassCommercialMetricsSampling() {
|
|
99
|
+
if (!initialised) {
|
|
100
|
+
console.warn('initCommercialMetrics not yet initialised');
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
addVisibilityListeners();
|
|
104
|
+
}
|
|
105
|
+
exports.bypassCommercialMetricsSampling = bypassCommercialMetricsSampling;
|
|
106
|
+
/**
|
|
107
|
+
* A method to initialise metrics.
|
|
108
|
+
* @param init.pageViewId - identifies the page view. Usually available on `guardian.config.ophan.pageViewId`. Defaults to `null`
|
|
109
|
+
* @param init.browserId - identifies the browser. Usually available via `getCookie({ name: 'bwid' })`. Defaults to `null`
|
|
110
|
+
* @param init.isDev - used to determine whether to use CODE or PROD endpoints.
|
|
111
|
+
* @param init.adBlockerInUse - indicates whether or not an adblocker is being used.
|
|
112
|
+
* @param init.sampling - rate at which to sample commercial metrics - the default is to send for 1% of pageviews
|
|
113
|
+
*/
|
|
114
|
+
function initCommercialMetrics({ pageViewId, browserId, isDev, adBlockerInUse, sampling = 1 / 100, }) {
|
|
115
|
+
commercialMetricsPayload.page_view_id = pageViewId;
|
|
116
|
+
commercialMetricsPayload.browser_id = browserId;
|
|
117
|
+
setEndpoint(isDev);
|
|
118
|
+
setDevProperties(isDev);
|
|
119
|
+
setAdBlockerProperties(adBlockerInUse);
|
|
120
|
+
if (initialised) {
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
initialised = true;
|
|
124
|
+
const userIsInSamplingGroup = Math.random() <= sampling;
|
|
125
|
+
if (isDev || userIsInSamplingGroup) {
|
|
126
|
+
addVisibilityListeners();
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
return false;
|
|
43
130
|
}
|
|
44
|
-
exports.
|
|
131
|
+
exports.initCommercialMetrics = initCommercialMetrics;
|
|
132
|
+
exports._ = {
|
|
133
|
+
Endpoints,
|
|
134
|
+
setEndpoint,
|
|
135
|
+
filterUndefinedProperties,
|
|
136
|
+
mapEventTimerPropertiesToString,
|
|
137
|
+
roundTimeStamp,
|
|
138
|
+
transformToObjectEntries,
|
|
139
|
+
reset: () => {
|
|
140
|
+
initialised = false;
|
|
141
|
+
commercialMetricsPayload = {
|
|
142
|
+
page_view_id: undefined,
|
|
143
|
+
browser_id: undefined,
|
|
144
|
+
platform: 'NEXT_GEN',
|
|
145
|
+
metrics: [],
|
|
146
|
+
properties: [],
|
|
147
|
+
};
|
|
148
|
+
removeEventListener('visibilitychange', listener);
|
|
149
|
+
removeEventListener('pagehide', listener);
|
|
150
|
+
},
|
|
151
|
+
};
|
package/dist/esm/EventTimer.d.ts
CHANGED
|
@@ -19,7 +19,16 @@ interface SlotEventStatus {
|
|
|
19
19
|
}
|
|
20
20
|
interface PageEventStatus {
|
|
21
21
|
commercialStart: boolean;
|
|
22
|
-
|
|
22
|
+
commercialExtraModulesLoaded: boolean;
|
|
23
|
+
commercialBaseModulesLoaded: boolean;
|
|
24
|
+
commercialModulesLoaded: boolean;
|
|
25
|
+
}
|
|
26
|
+
interface EventTimerProperties {
|
|
27
|
+
type?: ConnectionType;
|
|
28
|
+
downlink?: number;
|
|
29
|
+
effectiveType?: string;
|
|
30
|
+
adSlotsInline?: number;
|
|
31
|
+
adSlotsTotal?: number;
|
|
23
32
|
}
|
|
24
33
|
export declare class EventTimer {
|
|
25
34
|
private _events;
|
|
@@ -31,11 +40,7 @@ export declare class EventTimer {
|
|
|
31
40
|
page: PageEventStatus;
|
|
32
41
|
};
|
|
33
42
|
gaConfig: GAConfig;
|
|
34
|
-
properties:
|
|
35
|
-
type?: ConnectionType;
|
|
36
|
-
downlink?: number;
|
|
37
|
-
effectiveType?: string;
|
|
38
|
-
};
|
|
43
|
+
properties: EventTimerProperties;
|
|
39
44
|
/**
|
|
40
45
|
* Initialise the EventTimer class on page.
|
|
41
46
|
* Returns the singleton instance of the EventTimer class and binds
|
|
@@ -58,6 +63,7 @@ export declare class EventTimer {
|
|
|
58
63
|
*/
|
|
59
64
|
get events(): Event[];
|
|
60
65
|
private constructor();
|
|
66
|
+
setProperty(name: 'adSlotsInline' | 'adSlotsTotal', value: number): void;
|
|
61
67
|
/**
|
|
62
68
|
* Creates a new performance mark
|
|
63
69
|
* For slot events also ensures each TYPE of event event is marked only once for 'first'
|
package/dist/esm/EventTimer.js
CHANGED
|
@@ -26,7 +26,9 @@ export class EventTimer {
|
|
|
26
26
|
},
|
|
27
27
|
page: {
|
|
28
28
|
commercialStart: false,
|
|
29
|
-
|
|
29
|
+
commercialExtraModulesLoaded: false,
|
|
30
|
+
commercialBaseModulesLoaded: false,
|
|
31
|
+
commercialModulesLoaded: false,
|
|
30
32
|
},
|
|
31
33
|
};
|
|
32
34
|
this.gaConfig = {
|
|
@@ -42,7 +44,7 @@ export class EventTimer {
|
|
|
42
44
|
timingLabel: 'Commercial start parse time',
|
|
43
45
|
},
|
|
44
46
|
{
|
|
45
|
-
timingVariable: '
|
|
47
|
+
timingVariable: 'commercialModulesLoaded',
|
|
46
48
|
timingLabel: 'Commercial end parse time',
|
|
47
49
|
},
|
|
48
50
|
],
|
|
@@ -103,6 +105,9 @@ export class EventTimer {
|
|
|
103
105
|
]
|
|
104
106
|
: this._events;
|
|
105
107
|
}
|
|
108
|
+
setProperty(name, value) {
|
|
109
|
+
this.properties[name] = value;
|
|
110
|
+
}
|
|
106
111
|
/**
|
|
107
112
|
* Creates a new performance mark
|
|
108
113
|
* For slot events also ensures each TYPE of event event is marked only once for 'first'
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export { twitter } from './third-party-tags/twitter-uwt';
|
|
|
5
5
|
export { inizio } from './third-party-tags/inizio';
|
|
6
6
|
export { remarketing } from './third-party-tags/remarketing';
|
|
7
7
|
export { EventTimer } from './EventTimer';
|
|
8
|
-
export {
|
|
8
|
+
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './sendCommercialMetrics';
|
|
9
9
|
export type { ThirdPartyTag } from './types';
|
|
10
10
|
export { adSizes, getAdSize } from './ad-sizes';
|
|
11
11
|
export type { SizeKeys, AdSizeString, AdSize } from './ad-sizes';
|
package/dist/esm/index.js
CHANGED
|
@@ -6,7 +6,7 @@ export { twitter } from './third-party-tags/twitter-uwt';
|
|
|
6
6
|
export { inizio } from './third-party-tags/inizio';
|
|
7
7
|
export { remarketing } from './third-party-tags/remarketing';
|
|
8
8
|
export { EventTimer } from './EventTimer';
|
|
9
|
-
export {
|
|
9
|
+
export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './sendCommercialMetrics';
|
|
10
10
|
export { adSizes, getAdSize } from './ad-sizes';
|
|
11
11
|
export { isAdBlockInUse } from './detectAdBlocker';
|
|
12
12
|
export { clearPermutiveSegments, getPermutiveSegments, getPermutivePFPSegments, } from './permutive';
|
|
@@ -1 +1,51 @@
|
|
|
1
|
-
|
|
1
|
+
declare type Metric = {
|
|
2
|
+
name: string;
|
|
3
|
+
value: number;
|
|
4
|
+
};
|
|
5
|
+
declare type Property = {
|
|
6
|
+
name: string;
|
|
7
|
+
value: string;
|
|
8
|
+
};
|
|
9
|
+
declare type TimedEvent = {
|
|
10
|
+
name: string;
|
|
11
|
+
ts: number;
|
|
12
|
+
};
|
|
13
|
+
declare type EventProperties = {
|
|
14
|
+
type?: ConnectionType;
|
|
15
|
+
downlink?: number;
|
|
16
|
+
effectiveType?: string;
|
|
17
|
+
};
|
|
18
|
+
declare enum Endpoints {
|
|
19
|
+
CODE = "//performance-events.code.dev-guardianapis.com/commercial-metrics",
|
|
20
|
+
PROD = "//performance-events.guardianapis.com/commercial-metrics"
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* A method to asynchronously send metrics after initialization.
|
|
24
|
+
*/
|
|
25
|
+
export declare function bypassCommercialMetricsSampling(): void;
|
|
26
|
+
interface InitCommercialMetricsArgs {
|
|
27
|
+
pageViewId: string;
|
|
28
|
+
browserId: string | undefined;
|
|
29
|
+
isDev: boolean;
|
|
30
|
+
adBlockerInUse?: boolean;
|
|
31
|
+
sampling?: number;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* A method to initialise metrics.
|
|
35
|
+
* @param init.pageViewId - identifies the page view. Usually available on `guardian.config.ophan.pageViewId`. Defaults to `null`
|
|
36
|
+
* @param init.browserId - identifies the browser. Usually available via `getCookie({ name: 'bwid' })`. Defaults to `null`
|
|
37
|
+
* @param init.isDev - used to determine whether to use CODE or PROD endpoints.
|
|
38
|
+
* @param init.adBlockerInUse - indicates whether or not an adblocker is being used.
|
|
39
|
+
* @param init.sampling - rate at which to sample commercial metrics - the default is to send for 1% of pageviews
|
|
40
|
+
*/
|
|
41
|
+
export declare function initCommercialMetrics({ pageViewId, browserId, isDev, adBlockerInUse, sampling, }: InitCommercialMetricsArgs): boolean;
|
|
42
|
+
export declare const _: {
|
|
43
|
+
Endpoints: typeof Endpoints;
|
|
44
|
+
setEndpoint: (isDev: boolean) => Endpoints;
|
|
45
|
+
filterUndefinedProperties: <T>(transformedProperties: [string, T | undefined][]) => [string, T][];
|
|
46
|
+
mapEventTimerPropertiesToString: (properties: Array<[string, string | number]>) => Property[];
|
|
47
|
+
roundTimeStamp: (events: TimedEvent[]) => Metric[];
|
|
48
|
+
transformToObjectEntries: (eventTimerProperties: EventProperties) => Array<[string, string | number | undefined]>;
|
|
49
|
+
reset: () => void;
|
|
50
|
+
};
|
|
51
|
+
export type { Property, TimedEvent, Metric };
|
|
@@ -1,40 +1,146 @@
|
|
|
1
1
|
import { log } from '@guardian/libs';
|
|
2
2
|
import { EventTimer } from './EventTimer';
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
3
|
+
var Endpoints;
|
|
4
|
+
(function (Endpoints) {
|
|
5
|
+
Endpoints["CODE"] = "//performance-events.code.dev-guardianapis.com/commercial-metrics";
|
|
6
|
+
Endpoints["PROD"] = "//performance-events.guardianapis.com/commercial-metrics";
|
|
7
|
+
})(Endpoints || (Endpoints = {}));
|
|
8
|
+
let commercialMetricsPayload = {
|
|
9
|
+
page_view_id: undefined,
|
|
10
|
+
browser_id: undefined,
|
|
11
|
+
platform: 'NEXT_GEN',
|
|
12
|
+
metrics: [],
|
|
13
|
+
properties: [],
|
|
14
|
+
};
|
|
15
|
+
let devProperties = [];
|
|
16
|
+
let adBlockerProperties = [];
|
|
17
|
+
let initialised = false;
|
|
18
|
+
let endpoint;
|
|
19
|
+
const setEndpoint = (isDev) => (endpoint = isDev ? Endpoints.CODE : Endpoints.PROD);
|
|
20
|
+
const setDevProperties = (isDev) => (devProperties = isDev
|
|
21
|
+
? [{ name: 'isDev', value: window.location.hostname }]
|
|
22
|
+
: []);
|
|
23
|
+
const setAdBlockerProperties = (adBlockerInUse) => {
|
|
24
|
+
adBlockerProperties =
|
|
25
|
+
adBlockerInUse !== undefined
|
|
26
|
+
? [
|
|
27
|
+
{
|
|
28
|
+
name: 'adBlockerInUse',
|
|
29
|
+
value: adBlockerInUse.toString(),
|
|
30
|
+
},
|
|
31
|
+
]
|
|
32
|
+
: [];
|
|
33
|
+
};
|
|
34
|
+
const transformToObjectEntries = (eventTimerProperties) => {
|
|
35
|
+
// Transforms object {key: value} pairs into an array of [key, value] arrays
|
|
36
|
+
return Object.entries(eventTimerProperties);
|
|
37
|
+
};
|
|
38
|
+
const filterUndefinedProperties = (transformedProperties) => transformedProperties.reduce((acc, [key, value]) => {
|
|
39
|
+
if (typeof value !== 'undefined') {
|
|
40
|
+
acc.push([key, value]);
|
|
41
|
+
}
|
|
42
|
+
return acc;
|
|
43
|
+
}, []);
|
|
44
|
+
const mapEventTimerPropertiesToString = (properties) => {
|
|
45
|
+
return properties.map(([name, value]) => ({
|
|
46
|
+
name: String(name),
|
|
47
|
+
value: String(value),
|
|
48
|
+
}));
|
|
49
|
+
};
|
|
50
|
+
const roundTimeStamp = (events) => {
|
|
51
|
+
return events.map(({ name, ts }) => ({
|
|
28
52
|
name,
|
|
29
53
|
value: Math.ceil(ts),
|
|
30
54
|
}));
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
55
|
+
};
|
|
56
|
+
function sendMetrics() {
|
|
57
|
+
log('commercial', 'About to send commercial metrics', commercialMetricsPayload);
|
|
58
|
+
return navigator.sendBeacon(endpoint, JSON.stringify(commercialMetricsPayload));
|
|
59
|
+
}
|
|
60
|
+
function gatherMetricsOnPageUnload() {
|
|
61
|
+
// Assemble commercial properties and metrics
|
|
62
|
+
const eventTimer = EventTimer.get();
|
|
63
|
+
const transformedEntries = transformToObjectEntries(eventTimer.properties);
|
|
64
|
+
const filteredEventTimerProperties = filterUndefinedProperties(transformedEntries);
|
|
65
|
+
const mappedEventTimerProperties = mapEventTimerPropertiesToString(filteredEventTimerProperties);
|
|
66
|
+
const properties = mappedEventTimerProperties
|
|
67
|
+
.concat(devProperties)
|
|
68
|
+
.concat(adBlockerProperties);
|
|
69
|
+
commercialMetricsPayload.properties = properties;
|
|
70
|
+
const metrics = roundTimeStamp(eventTimer.events);
|
|
71
|
+
commercialMetricsPayload.metrics = metrics;
|
|
72
|
+
sendMetrics();
|
|
73
|
+
}
|
|
74
|
+
const listener = (e) => {
|
|
75
|
+
switch (e.type) {
|
|
76
|
+
case 'visibilitychange':
|
|
77
|
+
if (document.visibilityState === 'hidden') {
|
|
78
|
+
gatherMetricsOnPageUnload();
|
|
79
|
+
}
|
|
80
|
+
return;
|
|
81
|
+
case 'pagehide':
|
|
82
|
+
gatherMetricsOnPageUnload();
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const addVisibilityListeners = () => {
|
|
87
|
+
// Report all available metrics when the page is unloaded or in background.
|
|
88
|
+
window.addEventListener('visibilitychange', listener);
|
|
89
|
+
// Safari does not reliably fire the `visibilitychange` on page unload.
|
|
90
|
+
window.addEventListener('pagehide', listener);
|
|
91
|
+
};
|
|
92
|
+
/**
|
|
93
|
+
* A method to asynchronously send metrics after initialization.
|
|
94
|
+
*/
|
|
95
|
+
export function bypassCommercialMetricsSampling() {
|
|
96
|
+
if (!initialised) {
|
|
97
|
+
console.warn('initCommercialMetrics not yet initialised');
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
addVisibilityListeners();
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* A method to initialise metrics.
|
|
104
|
+
* @param init.pageViewId - identifies the page view. Usually available on `guardian.config.ophan.pageViewId`. Defaults to `null`
|
|
105
|
+
* @param init.browserId - identifies the browser. Usually available via `getCookie({ name: 'bwid' })`. Defaults to `null`
|
|
106
|
+
* @param init.isDev - used to determine whether to use CODE or PROD endpoints.
|
|
107
|
+
* @param init.adBlockerInUse - indicates whether or not an adblocker is being used.
|
|
108
|
+
* @param init.sampling - rate at which to sample commercial metrics - the default is to send for 1% of pageviews
|
|
109
|
+
*/
|
|
110
|
+
export function initCommercialMetrics({ pageViewId, browserId, isDev, adBlockerInUse, sampling = 1 / 100, }) {
|
|
111
|
+
commercialMetricsPayload.page_view_id = pageViewId;
|
|
112
|
+
commercialMetricsPayload.browser_id = browserId;
|
|
113
|
+
setEndpoint(isDev);
|
|
114
|
+
setDevProperties(isDev);
|
|
115
|
+
setAdBlockerProperties(adBlockerInUse);
|
|
116
|
+
if (initialised) {
|
|
117
|
+
return false;
|
|
118
|
+
}
|
|
119
|
+
initialised = true;
|
|
120
|
+
const userIsInSamplingGroup = Math.random() <= sampling;
|
|
121
|
+
if (isDev || userIsInSamplingGroup) {
|
|
122
|
+
addVisibilityListeners();
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
return false;
|
|
40
126
|
}
|
|
127
|
+
export const _ = {
|
|
128
|
+
Endpoints,
|
|
129
|
+
setEndpoint,
|
|
130
|
+
filterUndefinedProperties,
|
|
131
|
+
mapEventTimerPropertiesToString,
|
|
132
|
+
roundTimeStamp,
|
|
133
|
+
transformToObjectEntries,
|
|
134
|
+
reset: () => {
|
|
135
|
+
initialised = false;
|
|
136
|
+
commercialMetricsPayload = {
|
|
137
|
+
page_view_id: undefined,
|
|
138
|
+
browser_id: undefined,
|
|
139
|
+
platform: 'NEXT_GEN',
|
|
140
|
+
metrics: [],
|
|
141
|
+
properties: [],
|
|
142
|
+
};
|
|
143
|
+
removeEventListener('visibilitychange', listener);
|
|
144
|
+
removeEventListener('pagehide', listener);
|
|
145
|
+
},
|
|
146
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guardian/commercial-core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Guardian advertising business logic",
|
|
5
5
|
"homepage": "https://github.com/guardian/commercial-core#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"precommit:lint": "lint-staged",
|
|
27
27
|
"prepush:test": "jest --verbose --runInBand --onlyChanged",
|
|
28
28
|
"test": "jest",
|
|
29
|
+
"test:watch": "jest --watch",
|
|
29
30
|
"test:ci": "jest --coverage --ci",
|
|
30
31
|
"tsc": "tsc --noEmit",
|
|
31
32
|
"validate": "npm-run-all tsc lint test build",
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
"@commitlint/config-conventional": "^16.0.0",
|
|
46
47
|
"@guardian/ab-core": "^2.0.0",
|
|
47
48
|
"@guardian/consent-management-platform": "^10.1.0",
|
|
48
|
-
"@guardian/eslint-config-typescript": "^0.
|
|
49
|
+
"@guardian/eslint-config-typescript": "^1.0.0",
|
|
49
50
|
"@guardian/libs": "3.6.1",
|
|
50
51
|
"@guardian/prettier": "^0.7.0",
|
|
51
52
|
"@octokit/core": "^3.5.1",
|