@guardian/commercial-core 0.0.0-beta-20250716121613

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.
Files changed (111) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +45 -0
  3. package/dist/cjs/ad-sizes.d.ts +202 -0
  4. package/dist/cjs/ad-sizes.js +400 -0
  5. package/dist/cjs/breakpoint.d.ts +8 -0
  6. package/dist/cjs/breakpoint.js +10 -0
  7. package/dist/cjs/constants/ad-label-height.d.ts +4 -0
  8. package/dist/cjs/constants/ad-label-height.js +7 -0
  9. package/dist/cjs/constants/index.d.ts +3 -0
  10. package/dist/cjs/constants/index.js +9 -0
  11. package/dist/cjs/constants/prebid-timeout.d.ts +4 -0
  12. package/dist/cjs/constants/prebid-timeout.js +7 -0
  13. package/dist/cjs/constants/top-above-nav-height.d.ts +10 -0
  14. package/dist/cjs/constants/top-above-nav-height.js +48 -0
  15. package/dist/cjs/detect-ad-blocker.d.ts +12 -0
  16. package/dist/cjs/detect-ad-blocker.js +61 -0
  17. package/dist/cjs/event-timer.d.ts +103 -0
  18. package/dist/cjs/event-timer.js +204 -0
  19. package/dist/cjs/geo/country-code.d.ts +3 -0
  20. package/dist/cjs/geo/country-code.js +34 -0
  21. package/dist/cjs/geo/geo-utils.d.ts +11 -0
  22. package/dist/cjs/geo/geo-utils.js +31 -0
  23. package/dist/cjs/geo/get-locale.d.ts +8 -0
  24. package/dist/cjs/geo/get-locale.js +43 -0
  25. package/dist/cjs/global.d.ts +71 -0
  26. package/dist/cjs/global.js +2 -0
  27. package/dist/cjs/index.d.ts +13 -0
  28. package/dist/cjs/index.js +46 -0
  29. package/dist/cjs/messenger/post-message.d.ts +1 -0
  30. package/dist/cjs/messenger/post-message.js +7 -0
  31. package/dist/cjs/permutive.d.ts +9 -0
  32. package/dist/cjs/permutive.js +38 -0
  33. package/dist/cjs/send-commercial-metrics.d.ts +58 -0
  34. package/dist/cjs/send-commercial-metrics.js +209 -0
  35. package/dist/cjs/targeting/build-page-targeting.d.ts +47 -0
  36. package/dist/cjs/targeting/build-page-targeting.js +112 -0
  37. package/dist/cjs/targeting/content.d.ts +87 -0
  38. package/dist/cjs/targeting/content.js +76 -0
  39. package/dist/cjs/targeting/personalised.d.ts +83 -0
  40. package/dist/cjs/targeting/personalised.js +140 -0
  41. package/dist/cjs/targeting/pick-targeting-values.d.ts +25 -0
  42. package/dist/cjs/targeting/pick-targeting-values.js +47 -0
  43. package/dist/cjs/targeting/session.d.ts +111 -0
  44. package/dist/cjs/targeting/session.js +61 -0
  45. package/dist/cjs/targeting/shared.d.ts +156 -0
  46. package/dist/cjs/targeting/shared.js +28 -0
  47. package/dist/cjs/targeting/teads-eligibility.d.ts +2 -0
  48. package/dist/cjs/targeting/teads-eligibility.js +20 -0
  49. package/dist/cjs/targeting/types.d.ts +6 -0
  50. package/dist/cjs/targeting/types.js +2 -0
  51. package/dist/cjs/targeting/viewport.d.ts +48 -0
  52. package/dist/cjs/targeting/viewport.js +22 -0
  53. package/dist/cjs/targeting/youtube-ima.d.ts +12 -0
  54. package/dist/cjs/targeting/youtube-ima.js +76 -0
  55. package/dist/cjs/types.d.ts +426 -0
  56. package/dist/cjs/types.js +12 -0
  57. package/dist/esm/ad-sizes.d.ts +202 -0
  58. package/dist/esm/ad-sizes.js +390 -0
  59. package/dist/esm/breakpoint.d.ts +8 -0
  60. package/dist/esm/breakpoint.js +6 -0
  61. package/dist/esm/constants/ad-label-height.d.ts +4 -0
  62. package/dist/esm/constants/ad-label-height.js +4 -0
  63. package/dist/esm/constants/index.d.ts +3 -0
  64. package/dist/esm/constants/index.js +3 -0
  65. package/dist/esm/constants/prebid-timeout.d.ts +4 -0
  66. package/dist/esm/constants/prebid-timeout.js +4 -0
  67. package/dist/esm/constants/top-above-nav-height.d.ts +10 -0
  68. package/dist/esm/constants/top-above-nav-height.js +45 -0
  69. package/dist/esm/detect-ad-blocker.d.ts +12 -0
  70. package/dist/esm/detect-ad-blocker.js +58 -0
  71. package/dist/esm/event-timer.d.ts +103 -0
  72. package/dist/esm/event-timer.js +199 -0
  73. package/dist/esm/geo/country-code.d.ts +3 -0
  74. package/dist/esm/geo/country-code.js +31 -0
  75. package/dist/esm/geo/geo-utils.d.ts +11 -0
  76. package/dist/esm/geo/geo-utils.js +20 -0
  77. package/dist/esm/geo/get-locale.d.ts +8 -0
  78. package/dist/esm/geo/get-locale.js +38 -0
  79. package/dist/esm/global.d.ts +71 -0
  80. package/dist/esm/global.js +0 -0
  81. package/dist/esm/index.d.ts +13 -0
  82. package/dist/esm/index.js +10 -0
  83. package/dist/esm/messenger/post-message.d.ts +1 -0
  84. package/dist/esm/messenger/post-message.js +3 -0
  85. package/dist/esm/permutive.d.ts +9 -0
  86. package/dist/esm/permutive.js +33 -0
  87. package/dist/esm/send-commercial-metrics.d.ts +58 -0
  88. package/dist/esm/send-commercial-metrics.js +204 -0
  89. package/dist/esm/targeting/build-page-targeting.d.ts +47 -0
  90. package/dist/esm/targeting/build-page-targeting.js +108 -0
  91. package/dist/esm/targeting/content.d.ts +87 -0
  92. package/dist/esm/targeting/content.js +73 -0
  93. package/dist/esm/targeting/personalised.d.ts +83 -0
  94. package/dist/esm/targeting/personalised.js +137 -0
  95. package/dist/esm/targeting/pick-targeting-values.d.ts +25 -0
  96. package/dist/esm/targeting/pick-targeting-values.js +43 -0
  97. package/dist/esm/targeting/session.d.ts +111 -0
  98. package/dist/esm/targeting/session.js +57 -0
  99. package/dist/esm/targeting/shared.d.ts +156 -0
  100. package/dist/esm/targeting/shared.js +25 -0
  101. package/dist/esm/targeting/teads-eligibility.d.ts +2 -0
  102. package/dist/esm/targeting/teads-eligibility.js +17 -0
  103. package/dist/esm/targeting/types.d.ts +6 -0
  104. package/dist/esm/targeting/types.js +0 -0
  105. package/dist/esm/targeting/viewport.d.ts +48 -0
  106. package/dist/esm/targeting/viewport.js +19 -0
  107. package/dist/esm/targeting/youtube-ima.d.ts +12 -0
  108. package/dist/esm/targeting/youtube-ima.js +73 -0
  109. package/dist/esm/types.d.ts +426 -0
  110. package/dist/esm/types.js +10 -0
  111. package/package.json +65 -0
@@ -0,0 +1,12 @@
1
+ /**
2
+ Detect whether or not the user has an ad blocking extension enabled.
3
+ A few ad blockers are not detectable with this approach e.g. Safari / Adblock
4
+ Code inspired by just-detect-adblock's:
5
+ https://github.com/wmcmurray/just-detect-adblock/blob/master/src/helpers.js
6
+ */
7
+ /**
8
+ * Determines whether or not the user has an ad blocking extension enabled.
9
+ * Note: positive results can be considered reliable while negative ones may not be.
10
+ * @returns Promise
11
+ */
12
+ export declare function isAdBlockInUse(): Promise<boolean>;
@@ -0,0 +1,58 @@
1
+ /**
2
+ Detect whether or not the user has an ad blocking extension enabled.
3
+ A few ad blockers are not detectable with this approach e.g. Safari / Adblock
4
+ Code inspired by just-detect-adblock's:
5
+ https://github.com/wmcmurray/just-detect-adblock/blob/master/src/helpers.js
6
+ */
7
+ /*istanbul ignore file -- adElementBlocked can't be tested without patching each of the properties of
8
+ HTMLElement.prototype that it accesses, defeating the purpose of the test! */
9
+ let adBlockInUse = undefined;
10
+ function adElementBlocked(ad) {
11
+ if (ad.offsetParent === null ||
12
+ ad.offsetHeight === 0 ||
13
+ ad.offsetLeft === 0 ||
14
+ ad.offsetTop === 0 ||
15
+ ad.offsetWidth === 0 ||
16
+ ad.clientHeight === 0 ||
17
+ ad.clientWidth === 0) {
18
+ return true;
19
+ }
20
+ const adStyles = window.getComputedStyle(ad);
21
+ if (adStyles.getPropertyValue('display') === 'none')
22
+ return true;
23
+ if (adStyles.getPropertyValue('visibility') === 'hidden')
24
+ return true;
25
+ const mozBindingProp = adStyles.getPropertyValue('-moz-binding');
26
+ if (mozBindingProp.includes('about:'))
27
+ return true;
28
+ return false;
29
+ }
30
+ /**
31
+ * Determines whether or not the user has an ad blocking extension enabled.
32
+ * Note: positive results can be considered reliable while negative ones may not be.
33
+ * @returns Promise
34
+ */
35
+ export function isAdBlockInUse() {
36
+ if (adBlockInUse !== undefined) {
37
+ return Promise.resolve(adBlockInUse);
38
+ }
39
+ if (typeof window.getComputedStyle !== 'function') {
40
+ // Old browsers not supporting getComputedStyle most likely won't have adBlockers
41
+ adBlockInUse = false;
42
+ return Promise.resolve(adBlockInUse);
43
+ }
44
+ return new Promise((resolve) => {
45
+ window.requestAnimationFrame(() => {
46
+ // create a fake ad element and append it to the document
47
+ const ad = document.createElement('div');
48
+ ad.setAttribute('class', 'ad_unit pub_300x250 pub_300x250m pub_728x90 text-ad textAd text_ad text_ads text-ads text-ad-links ad-text adSense adBlock adContent adBanner');
49
+ ad.setAttribute('style', 'width: 1px !important; height: 1px !important; position: absolute !important; left: -10000px !important; top: -1000px !important;');
50
+ document.body.appendChild(ad);
51
+ // avoid a forced layout
52
+ window.requestAnimationFrame(() => {
53
+ // if the ad element has been hidden, an ad blocker is enabled.
54
+ resolve(adElementBlocked(ad));
55
+ });
56
+ });
57
+ });
58
+ }
@@ -0,0 +1,103 @@
1
+ import type { ConnectionType } from './types';
2
+ declare const supportsPerformanceAPI: () => boolean;
3
+ interface EventTimerProperties {
4
+ type?: ConnectionType;
5
+ downlink?: number;
6
+ effectiveType?: string;
7
+ adSlotsInline?: number;
8
+ adSlotsTotal?: number;
9
+ /** the height of the page / the viewport height */
10
+ pageHeightVH?: number;
11
+ gpcSignal?: number;
12
+ /** distance in percentage of viewport height at which ads are lazy loaded */
13
+ lazyLoadMarginPercent?: number;
14
+ hasLabsContainer?: boolean;
15
+ labsUrl?: string;
16
+ /** Record whether we've detected an ad blocker. This is intentionally
17
+ * distinct from the property we pass into commercial metrics, and in the
18
+ * future _could_ be removed in favour of this property */
19
+ detectedAdBlocker?: boolean;
20
+ /** Record whether we've shown the adblock as message */
21
+ didDisplayAdBlockAsk?: boolean;
22
+ /** creative ID of a video interscroller for video reporting metrics */
23
+ videoInterscrollerCreativeId?: number | null | undefined;
24
+ /** percentage progress of video interscroller on page unload */
25
+ videoInterscrollerPercentageProgress?: number;
26
+ }
27
+ declare class EventTimer {
28
+ private _marks;
29
+ private _measures;
30
+ properties: EventTimerProperties;
31
+ /**
32
+ * Initialise the EventTimer class on page.
33
+ * Returns the singleton instance of the EventTimer class and binds
34
+ * to window.guardian.commercialTimer. If it's been previously
35
+ * initialised and bound it returns the original instance
36
+ * Note: We save to window.guardian.commercialTimer because
37
+ * different bundles (DCR / DCP) can use commercial, and we want
38
+ * all timer events saved to a single instance per-page
39
+ * @returns {EventTimer} Instance of EventTimer
40
+ */
41
+ static init(): EventTimer;
42
+ /**
43
+ * Just a helper method to access the singleton instance of EventTimer.
44
+ * Typical use case is EventTimer.get().trigger
45
+ */
46
+ static get(): EventTimer;
47
+ /**
48
+ * These are marks that are not triggered by commercial but we are interested in
49
+ * tracking their performance. For example, CMP-related events.
50
+ **/
51
+ private get _externalMarks();
52
+ /**
53
+ * Returns all performance marks that should be saved as commercial metrics.
54
+ */
55
+ get marks(): {
56
+ name: string;
57
+ ts: number;
58
+ }[];
59
+ /**
60
+ * Returns all performance measures that should be saved as commercial metrics.
61
+ */
62
+ get measures(): {
63
+ name: string;
64
+ duration: number;
65
+ }[];
66
+ private constructor();
67
+ /**
68
+ * Adds a non timer measurement
69
+ *
70
+ * @param {string} name - the property's name
71
+ * @param value - the property's value
72
+ */
73
+ setProperty<T extends keyof EventTimerProperties>(name: T, value: EventTimerProperties[T]): void;
74
+ /**
75
+ * Creates a new performance mark, and if the mark ends with 'End' it will
76
+ * create a performance measure between the start and end marks.
77
+ *
78
+ * Marks can be triggered multiple times, but we only save the first
79
+ * instance of a mark, as things like ad refreshes can trigger the same mark.
80
+ *
81
+ * More info on the performance API:
82
+ * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark
83
+ * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure
84
+ *
85
+ * @todo more strict typing for eventName and origin
86
+ * @param eventName The short name applied to the mark
87
+ * @param origin - Either 'page' (default) or the name of the slot
88
+ */
89
+ mark(eventName: string, origin?: string): void;
90
+ /**
91
+ * Creates a performance measure given the name of the end marks.
92
+ * The start mark is inferred from the end mark.
93
+ *
94
+ * @param endMark - The name of the mark that ends the measure
95
+ **/
96
+ private measure;
97
+ }
98
+ declare const _: {
99
+ slotMarks: readonly ["slotReady", "adRenderStart", "prebidStart", "adOnPage", "viewable"];
100
+ slotMeasures: readonly ["adRender", "defineSlot", "prepareSlot", "prebid", "fetchAd"];
101
+ trackedSlots: readonly ["top-above-nav", "inline1", "inline2", "fronts-banner-1", "fronts-banner-2"];
102
+ };
103
+ export { EventTimer, _, supportsPerformanceAPI };
@@ -0,0 +1,199 @@
1
+ import { log } from '@guardian/libs';
2
+ const supportsPerformanceAPI = () => typeof window !== 'undefined' &&
3
+ typeof window.performance !== 'undefined' &&
4
+ typeof window.performance.mark === 'function';
5
+ // Events will be logged using the performance API for all slots, but only these slots will be tracked as commercial metrics and sent to the data lake
6
+ const trackedSlots = [
7
+ 'top-above-nav',
8
+ 'inline1',
9
+ 'inline2',
10
+ 'fronts-banner-1',
11
+ 'fronts-banner-2',
12
+ ];
13
+ // marks that we want to save as commercial metrics
14
+ const slotMarks = [
15
+ 'slotReady',
16
+ 'adRenderStart',
17
+ 'prebidStart',
18
+ 'adOnPage',
19
+ 'viewable',
20
+ ];
21
+ // measures that we want to save as commercial metrics
22
+ const slotMeasures = [
23
+ 'adRender',
24
+ 'defineSlot',
25
+ 'prepareSlot',
26
+ 'prebid',
27
+ 'fetchAd',
28
+ ];
29
+ const pageMarks = ['commercialStart', 'commercialModulesLoaded'];
30
+ // measures that we want to save as commercial metrics
31
+ const pageMeasures = ['commercialBoot', 'googletagInit'];
32
+ // all marks, including the measure start and end marks
33
+ const allSlotMarks = [
34
+ ...slotMarks,
35
+ ...slotMeasures.map((measure) => `${measure}Start`),
36
+ ...slotMeasures.map((measure) => `${measure}End`),
37
+ ];
38
+ const externalMarks = [
39
+ 'cmp-init',
40
+ 'cmp-ui-displayed',
41
+ 'cmp-got-consent',
42
+ ];
43
+ const shouldSave = (name) => {
44
+ let [origin, type] = name.split('_');
45
+ if (!type) {
46
+ type = origin;
47
+ origin = 'page';
48
+ }
49
+ const shouldSaveMark = (trackedSlots.includes(origin) &&
50
+ slotMarks.includes(type)) ||
51
+ (origin === 'page' && pageMarks.includes(type));
52
+ const shouldSaveMeasure = (trackedSlots.includes(origin) &&
53
+ slotMeasures.includes(type)) ||
54
+ (origin === 'page' && pageMeasures.includes(type));
55
+ return shouldSaveMark || shouldSaveMeasure;
56
+ };
57
+ class EventTimer {
58
+ _marks;
59
+ _measures;
60
+ properties;
61
+ /**
62
+ * Initialise the EventTimer class on page.
63
+ * Returns the singleton instance of the EventTimer class and binds
64
+ * to window.guardian.commercialTimer. If it's been previously
65
+ * initialised and bound it returns the original instance
66
+ * Note: We save to window.guardian.commercialTimer because
67
+ * different bundles (DCR / DCP) can use commercial, and we want
68
+ * all timer events saved to a single instance per-page
69
+ * @returns {EventTimer} Instance of EventTimer
70
+ */
71
+ static init() {
72
+ return (window.guardian.commercialTimer ??= new EventTimer());
73
+ }
74
+ /**
75
+ * Just a helper method to access the singleton instance of EventTimer.
76
+ * Typical use case is EventTimer.get().trigger
77
+ */
78
+ static get() {
79
+ return this.init();
80
+ }
81
+ /**
82
+ * These are marks that are not triggered by commercial but we are interested in
83
+ * tracking their performance. For example, CMP-related events.
84
+ **/
85
+ get _externalMarks() {
86
+ if (!supportsPerformanceAPI()) {
87
+ return new Map();
88
+ }
89
+ return externalMarks.reduce((map, mark) => {
90
+ const entries = window.performance.getEntriesByName(mark);
91
+ if (entries.length && entries[0]) {
92
+ map.set(mark, entries[0]);
93
+ }
94
+ return map;
95
+ }, new Map());
96
+ }
97
+ /**
98
+ * Returns all performance marks that should be saved as commercial metrics.
99
+ */
100
+ get marks() {
101
+ return [...this._marks, ...this._externalMarks].map(([name, timer]) => ({
102
+ name,
103
+ ts: timer.startTime,
104
+ }));
105
+ }
106
+ /**
107
+ * Returns all performance measures that should be saved as commercial metrics.
108
+ */
109
+ get measures() {
110
+ return [...this._measures].map(([name, measure]) => ({
111
+ name,
112
+ duration: measure.duration,
113
+ }));
114
+ }
115
+ constructor() {
116
+ this._marks = new Map();
117
+ this._measures = new Map();
118
+ this.properties = {};
119
+ if (window.navigator.connection) {
120
+ this.properties.type = window.navigator.connection.type;
121
+ this.properties.downlink = window.navigator.connection.downlink;
122
+ this.properties.effectiveType =
123
+ window.navigator.connection.effectiveType;
124
+ }
125
+ }
126
+ /**
127
+ * Adds a non timer measurement
128
+ *
129
+ * @param {string} name - the property's name
130
+ * @param value - the property's value
131
+ */
132
+ setProperty(name, value) {
133
+ this.properties[name] = value;
134
+ }
135
+ /**
136
+ * Creates a new performance mark, and if the mark ends with 'End' it will
137
+ * create a performance measure between the start and end marks.
138
+ *
139
+ * Marks can be triggered multiple times, but we only save the first
140
+ * instance of a mark, as things like ad refreshes can trigger the same mark.
141
+ *
142
+ * More info on the performance API:
143
+ * https://developer.mozilla.org/en-US/docs/Web/API/Performance/mark
144
+ * https://developer.mozilla.org/en-US/docs/Web/API/Performance/measure
145
+ *
146
+ * @todo more strict typing for eventName and origin
147
+ * @param eventName The short name applied to the mark
148
+ * @param origin - Either 'page' (default) or the name of the slot
149
+ */
150
+ mark(eventName, origin = 'page') {
151
+ let name = eventName;
152
+ if (allSlotMarks.includes(eventName) && origin !== 'page') {
153
+ name = `${origin}_${name}`;
154
+ }
155
+ if (!!this._marks.get(name) || !supportsPerformanceAPI()) {
156
+ return;
157
+ }
158
+ const mark = window.performance.mark(name);
159
+ if (
160
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- browser support is patchy
161
+ typeof mark?.startTime === 'number' &&
162
+ // we only want to save the marks that are related to certain slots or the page
163
+ shouldSave(name)) {
164
+ this._marks.set(name, mark);
165
+ }
166
+ if (name.endsWith('End')) {
167
+ this.measure(name);
168
+ }
169
+ }
170
+ /**
171
+ * Creates a performance measure given the name of the end marks.
172
+ * The start mark is inferred from the end mark.
173
+ *
174
+ * @param endMark - The name of the mark that ends the measure
175
+ **/
176
+ measure(endMark) {
177
+ const startMark = endMark.replace('End', 'Start');
178
+ const measureName = endMark.replace('End', '');
179
+ const startMarkExists = window.performance.getEntriesByName(startMark).length > 0;
180
+ if (startMarkExists) {
181
+ try {
182
+ const measure = window.performance.measure(measureName, startMark, endMark);
183
+ // we only want to save the measures that are related to certain slots or the page
184
+ if (measure && shouldSave(measureName)) {
185
+ this._measures.set(measureName, measure);
186
+ }
187
+ }
188
+ catch (e) {
189
+ log('commercial', `error measuring ${measureName}`, e);
190
+ }
191
+ }
192
+ }
193
+ }
194
+ const _ = {
195
+ slotMarks,
196
+ slotMeasures,
197
+ trackedSlots,
198
+ };
199
+ export { EventTimer, _, supportsPerformanceAPI };
@@ -0,0 +1,3 @@
1
+ import type { CountryCode } from '@guardian/libs';
2
+ declare const getCountryCode: () => CountryCode;
3
+ export { getCountryCode };
@@ -0,0 +1,31 @@
1
+ import { getCookie, isString, storage } from '@guardian/libs';
2
+ const editionToCountryCodeMap = {
3
+ UK: 'GB',
4
+ US: 'US',
5
+ AU: 'AU',
6
+ };
7
+ const editionToCountryCode = (editionKey = 'UK') => editionToCountryCodeMap[editionKey];
8
+ const countryCookieName = 'GU_geo_country';
9
+ const countryOverrideName = 'gu.geo.override';
10
+ let locale;
11
+ /*
12
+ This method can be used as a non async way of getting the country code
13
+ after init has been called. Returning locale should cover all/most
14
+ of the cases but if a race condition happen or the cookie is not set,
15
+ we keep fallbacks to cookie or geo from edition.
16
+ */
17
+ const getCountryCode = () => {
18
+ const pageEdition = window.guardian.config.page.edition;
19
+ const maybeCountryOverride = storage.local.get(countryOverrideName);
20
+ const countryOverride = isString(maybeCountryOverride)
21
+ ? maybeCountryOverride
22
+ : null;
23
+ return (locale ??
24
+ countryOverride ??
25
+ getCookie({
26
+ name: countryCookieName,
27
+ shouldMemoize: true,
28
+ }) ??
29
+ editionToCountryCode(pageEdition));
30
+ };
31
+ export { getCountryCode };
@@ -0,0 +1,11 @@
1
+ export declare const isInUk: () => boolean;
2
+ export declare const isInUsa: () => boolean;
3
+ export declare const isInCanada: () => boolean;
4
+ export declare const isInAustralia: () => boolean;
5
+ export declare const isInNewZealand: () => boolean;
6
+ export declare const isInUsOrCa: () => boolean;
7
+ export declare const isInAuOrNz: () => boolean;
8
+ export declare const isInRow: () => boolean;
9
+ export declare const _: {
10
+ resetModule: () => void;
11
+ };
@@ -0,0 +1,20 @@
1
+ import { getCountryCode } from './country-code';
2
+ // cache the users location so we only have to look it up once
3
+ let geo;
4
+ const currentGeoLocation = () => {
5
+ geo = geo ?? getCountryCode();
6
+ return geo;
7
+ };
8
+ export const isInUk = () => currentGeoLocation() === 'GB';
9
+ export const isInUsa = () => currentGeoLocation() === 'US';
10
+ export const isInCanada = () => currentGeoLocation() === 'CA';
11
+ export const isInAustralia = () => currentGeoLocation() === 'AU';
12
+ export const isInNewZealand = () => currentGeoLocation() === 'NZ';
13
+ export const isInUsOrCa = () => isInUsa() || isInCanada();
14
+ export const isInAuOrNz = () => isInAustralia() || isInNewZealand();
15
+ export const isInRow = () => !isInUk() && !isInUsOrCa() && !isInAuOrNz();
16
+ export const _ = {
17
+ resetModule: () => {
18
+ geo = undefined;
19
+ },
20
+ };
@@ -0,0 +1,8 @@
1
+ import type { CountryCode } from '@guardian/libs';
2
+ export declare const __resetCachedValue: () => void;
3
+ /**
4
+ * Fetches the user's current location as an ISO 3166-1 alpha-2 string e.g. 'GB', 'AU' etc
5
+ * Note: This has been copied from guardian-libs and made syncronous by ommiting the call to
6
+ * the geolocation API
7
+ */
8
+ export declare const getLocale: () => CountryCode;
@@ -0,0 +1,38 @@
1
+ import { getCookie, isString, storage } from '@guardian/libs';
2
+ const KEY = 'GU_geo_country';
3
+ const KEY_OVERRIDE = 'gu.geo.override';
4
+ const COUNTRY_REGEX = /^[A-Z]{2}$/;
5
+ // best guess that we have a valid code, without actually shipping the entire list
6
+ const isValidCountryCode = (country) => isString(country) && COUNTRY_REGEX.test(country);
7
+ // we'll cache any successful lookups so we only have to do this once
8
+ let locale;
9
+ const editionToGeolocationMap = {
10
+ UK: 'GB',
11
+ US: 'US',
12
+ AU: 'AU',
13
+ };
14
+ const editionToGeolocation = (editionKey) => editionToGeolocationMap[editionKey];
15
+ // just used for tests
16
+ export const __resetCachedValue = () => (locale = undefined);
17
+ /**
18
+ * Fetches the user's current location as an ISO 3166-1 alpha-2 string e.g. 'GB', 'AU' etc
19
+ * Note: This has been copied from guardian-libs and made syncronous by ommiting the call to
20
+ * the geolocation API
21
+ */
22
+ export const getLocale = () => {
23
+ if (locale)
24
+ return locale;
25
+ // return overridden geo from localStorage, used for changing geo only for development purposes
26
+ const geoOverride = storage.local.get(KEY_OVERRIDE);
27
+ if (isValidCountryCode(geoOverride)) {
28
+ return (locale = geoOverride);
29
+ }
30
+ // return locale from cookie if it exists
31
+ const stored = getCookie({ name: KEY });
32
+ if (stored && isValidCountryCode(stored)) {
33
+ return (locale = stored);
34
+ }
35
+ // return locale from edition
36
+ const editionCountryCode = editionToGeolocation(window.guardian.config.page.edition);
37
+ return (locale = editionCountryCode);
38
+ };
@@ -0,0 +1,71 @@
1
+ import type { EventTimer } from './event-timer';
2
+ import type { AdBlockers, Apstag, ArticleCounts, ComscoreGlobals, Confiant, Config, DfpEnv, FetchBidResponse, GoogleTagParams, GoogleTrackConversionObject, HeaderNotification, IasPET, NetworkInformation, NSdkInstance, Ophan, OptOutAdSlot, OptOutInitializeOptions, Permutive, SafeFrameAPI, TeadsAnalytics, Trac } from './types';
3
+ declare global {
4
+ interface Navigator {
5
+ readonly connection?: NetworkInformation;
6
+ readonly cookieDeprecationLabel?: {
7
+ getValue: () => Promise<string>;
8
+ };
9
+ }
10
+ interface Window {
11
+ guardian: {
12
+ ophan?: Ophan;
13
+ config: Config;
14
+ queue: Array<() => Promise<void>>;
15
+ mustardCut?: boolean;
16
+ polyfilled?: boolean;
17
+ adBlockers: AdBlockers;
18
+ css: {
19
+ onLoad: () => void;
20
+ loaded: boolean;
21
+ };
22
+ articleCounts?: ArticleCounts;
23
+ commercial?: {
24
+ dfpEnv?: DfpEnv;
25
+ a9WinningBids?: FetchBidResponse[];
26
+ };
27
+ notificationEventHistory?: HeaderNotification[][];
28
+ commercialTimer?: EventTimer;
29
+ offlineCount?: number;
30
+ modules: {
31
+ sentry?: {
32
+ reportError?: (error: Error, feature: string, tags?: Record<string, string>, extras?: Record<string, unknown>) => void;
33
+ };
34
+ };
35
+ };
36
+ ootag: {
37
+ queue: Array<() => void>;
38
+ initializeOo: (o: OptOutInitializeOptions) => void;
39
+ addParameter: (key: string, value: string | string[]) => void;
40
+ addParameterForSlot: (slotId: string, key: string, value: string | string[]) => void;
41
+ defineSlot: (o: OptOutAdSlot) => void;
42
+ makeRequests: () => void;
43
+ refreshSlot: (slotId: string) => void;
44
+ refreshAllSlots: () => void;
45
+ logger: (...args: unknown[]) => void;
46
+ };
47
+ readonly navigator: Navigator;
48
+ confiant?: Confiant;
49
+ apstag?: Apstag;
50
+ permutive?: Permutive;
51
+ _comscore?: ComscoreGlobals[];
52
+ __iasPET?: IasPET;
53
+ teads_analytics?: TeadsAnalytics;
54
+ $sf: SafeFrameAPI;
55
+ conf: unknown;
56
+ NOLCMB: {
57
+ getInstance: (apid: string) => NSdkInstance;
58
+ };
59
+ nol_t: (pvar: {
60
+ cid: string;
61
+ content: string;
62
+ server: string;
63
+ }) => Trac;
64
+ google_trackConversion?: (arg0: GoogleTrackConversionObject) => void;
65
+ google_tag_params?: GoogleTagParams;
66
+ _brandmetrics?: Array<{
67
+ cmd: string;
68
+ val: Record<string, unknown>;
69
+ }>;
70
+ }
71
+ }
File without changes
@@ -0,0 +1,13 @@
1
+ export { isAdBlockInUse } from './detect-ad-blocker';
2
+ export { EventTimer } from './event-timer';
3
+ export { adSizes } from './ad-sizes';
4
+ export * as constants from './constants';
5
+ export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
6
+ export { buildPageTargeting } from './targeting/build-page-targeting';
7
+ export { postMessage } from './messenger/post-message';
8
+ export { buildImaAdTagUrl } from './targeting/youtube-ima';
9
+ export { getPermutivePFPSegments } from './permutive';
10
+ export { isEligibleForTeads } from './targeting/teads-eligibility';
11
+ export type { AdSize, SizeMapping, SlotName } from './ad-sizes';
12
+ export type { PageTargeting } from './targeting/build-page-targeting';
13
+ export type { AdsConfigDisabled, AdsConfigUSNATorAus, AdsConfigTCFV2, } from './types';
@@ -0,0 +1,10 @@
1
+ export { isAdBlockInUse } from './detect-ad-blocker';
2
+ export { EventTimer } from './event-timer';
3
+ export { adSizes } from './ad-sizes';
4
+ export * as constants from './constants';
5
+ export { bypassCommercialMetricsSampling, initCommercialMetrics, } from './send-commercial-metrics';
6
+ export { buildPageTargeting } from './targeting/build-page-targeting';
7
+ export { postMessage } from './messenger/post-message';
8
+ export { buildImaAdTagUrl } from './targeting/youtube-ima';
9
+ export { getPermutivePFPSegments } from './permutive';
10
+ export { isEligibleForTeads } from './targeting/teads-eligibility';
@@ -0,0 +1 @@
1
+ export declare const postMessage: (message: Record<string, unknown>, target: MessageEventSource, targetOrigin?: string) => void;
@@ -0,0 +1,3 @@
1
+ export const postMessage = (message, target, targetOrigin = '*') => {
2
+ target.postMessage(JSON.stringify(message), { targetOrigin });
3
+ };
@@ -0,0 +1,9 @@
1
+ declare const getPermutiveSegments: () => string[];
2
+ declare const getPermutivePFPSegments: () => string[];
3
+ declare const clearPermutiveSegments: () => void;
4
+ export declare const _: {
5
+ PERMUTIVE_KEY: string;
6
+ PERMUTIVE_PFP_KEY: string;
7
+ getSegments: (key: string) => string[];
8
+ };
9
+ export { getPermutiveSegments, getPermutivePFPSegments, clearPermutiveSegments, };
@@ -0,0 +1,33 @@
1
+ import { storage } from '@guardian/libs';
2
+ const PERMUTIVE_KEY = `_papns`;
3
+ const PERMUTIVE_PFP_KEY = `_pdfps`;
4
+ const getSegments = (key) => {
5
+ try {
6
+ const rawSegments = storage.local.getRaw(key);
7
+ const segments = rawSegments
8
+ ? JSON.parse(rawSegments)
9
+ : null;
10
+ if (!Array.isArray(segments))
11
+ return [];
12
+ return segments
13
+ .slice(0, 250)
14
+ .map((s) => Number.parseInt(s, 10))
15
+ .filter((n) => typeof n === 'number' && !Number.isNaN(n))
16
+ .map(String);
17
+ }
18
+ catch (err) {
19
+ return [];
20
+ }
21
+ };
22
+ const getPermutiveSegments = () => getSegments(PERMUTIVE_KEY);
23
+ const getPermutivePFPSegments = () => getSegments(PERMUTIVE_PFP_KEY);
24
+ const clearPermutiveSegments = () => {
25
+ storage.local.remove(PERMUTIVE_KEY);
26
+ storage.local.remove(PERMUTIVE_PFP_KEY);
27
+ };
28
+ export const _ = {
29
+ PERMUTIVE_KEY,
30
+ PERMUTIVE_PFP_KEY,
31
+ getSegments,
32
+ };
33
+ export { getPermutiveSegments, getPermutivePFPSegments, clearPermutiveSegments, };