@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,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getPersonalisedTargeting = void 0;
4
+ const libs_1 = require("@guardian/libs");
5
+ const permutive_1 = require("../permutive");
6
+ /* -- Types -- */
7
+ const frequency = [
8
+ '0',
9
+ '1',
10
+ '2',
11
+ '3',
12
+ '4',
13
+ '5',
14
+ '6-9',
15
+ '10-15',
16
+ '16-19',
17
+ '20-29',
18
+ '30plus',
19
+ ];
20
+ const AMTGRP_STORAGE_KEY = 'gu.adManagerGroup';
21
+ const adManagerGroups = [
22
+ '1',
23
+ '2',
24
+ '3',
25
+ '4',
26
+ '5',
27
+ '6',
28
+ '7',
29
+ '8',
30
+ '9',
31
+ '10',
32
+ '11',
33
+ '12',
34
+ ];
35
+ /* -- Methods -- */
36
+ const getRawWithConsent = (key, state) => {
37
+ if (state.tcfv2) {
38
+ if (state.tcfv2.consents['1'])
39
+ return libs_1.storage.local.getRaw(key);
40
+ }
41
+ if (state.usnat) {
42
+ if (!state.usnat.doNotSell)
43
+ return libs_1.storage.local.getRaw(key);
44
+ }
45
+ if (state.aus) {
46
+ if (state.aus.personalisedAdvertising)
47
+ return libs_1.storage.local.getRaw(key);
48
+ }
49
+ return null;
50
+ };
51
+ const getFrequencyValue = (state) => {
52
+ const rawValue = getRawWithConsent('gu.alreadyVisited', state);
53
+ if (!rawValue)
54
+ return '0';
55
+ const visitCount = parseInt(rawValue, 10);
56
+ if (visitCount <= 5) {
57
+ return frequency[visitCount] ?? '0';
58
+ }
59
+ else if (visitCount >= 6 && visitCount <= 9) {
60
+ return '6-9';
61
+ }
62
+ else if (visitCount >= 10 && visitCount <= 15) {
63
+ return '10-15';
64
+ }
65
+ else if (visitCount >= 16 && visitCount <= 19) {
66
+ return '16-19';
67
+ }
68
+ else if (visitCount >= 20 && visitCount <= 29) {
69
+ return '20-29';
70
+ }
71
+ else if (visitCount >= 30) {
72
+ return '30plus';
73
+ }
74
+ return '0';
75
+ };
76
+ const getCMPTargeting = (state) => {
77
+ if (state.tcfv2) {
78
+ return {
79
+ cmp_interaction: state.tcfv2.eventStatus,
80
+ pa: state.canTarget ? 't' : 'f',
81
+ consent_tcfv2: state.canTarget ? 't' : 'f',
82
+ rdp: 'na',
83
+ };
84
+ }
85
+ if (state.usnat) {
86
+ return {
87
+ consent_tcfv2: 'na',
88
+ rdp: !state.canTarget ? 't' : 'f',
89
+ pa: state.canTarget ? 't' : 'f',
90
+ };
91
+ }
92
+ if (state.aus) {
93
+ return {
94
+ consent_tcfv2: 'na',
95
+ rdp: 'na',
96
+ pa: state.canTarget ? 't' : 'f',
97
+ };
98
+ }
99
+ return {
100
+ cmp_interaction: 'na',
101
+ consent_tcfv2: 'na',
102
+ rdp: 'na',
103
+ pa: 'f',
104
+ };
105
+ };
106
+ const isAdManagerGroup = (s) => adManagerGroups.some((g) => g === s);
107
+ const createAdManagerGroup = () => {
108
+ const index = Math.floor(Math.random() * adManagerGroups.length);
109
+ const group = adManagerGroups[index] ?? '12';
110
+ libs_1.storage.local.setRaw(AMTGRP_STORAGE_KEY, group);
111
+ return group;
112
+ };
113
+ const getAdManagerGroup = (state) => {
114
+ if (!state.framework) {
115
+ libs_1.storage.local.remove(AMTGRP_STORAGE_KEY);
116
+ return null;
117
+ }
118
+ if (state.tcfv2 && !state.canTarget) {
119
+ libs_1.storage.local.remove(AMTGRP_STORAGE_KEY);
120
+ return null;
121
+ }
122
+ const existingGroup = libs_1.storage.local.getRaw(AMTGRP_STORAGE_KEY);
123
+ return isAdManagerGroup(existingGroup)
124
+ ? existingGroup
125
+ : createAdManagerGroup();
126
+ };
127
+ const getPermutiveWithState = (state, youtube) => {
128
+ if (state.canTarget) {
129
+ return youtube ? (0, permutive_1.getPermutivePFPSegments)() : (0, permutive_1.getPermutiveSegments)();
130
+ }
131
+ (0, permutive_1.clearPermutiveSegments)();
132
+ return [];
133
+ };
134
+ const getPersonalisedTargeting = ({ state, youtube, }) => ({
135
+ amtgrp: getAdManagerGroup(state),
136
+ fr: getFrequencyValue(state),
137
+ permutive: getPermutiveWithState(state, youtube),
138
+ ...getCMPTargeting(state),
139
+ });
140
+ exports.getPersonalisedTargeting = getPersonalisedTargeting;
@@ -0,0 +1,25 @@
1
+ import type { ConditionalExcept } from 'type-fest';
2
+ type ValidTargetingObject<Base> = ConditionalExcept<Base, null | undefined | '' | readonly [] | readonly [''] | never[] | boolean | number>;
3
+ /**
4
+ * Picks only keys with targeting values from an object.
5
+ * A targeting values is defined as either:
6
+ * - a non-empty string
7
+ * - an array of non-empty strings
8
+ *
9
+ * If you object is read-only, you can safely access properties on the result.
10
+ * For example:
11
+ *
12
+ * ```ts
13
+ * dirty = {
14
+ * valid: 'real',
15
+ * invalid: undefined,
16
+ * } as const;
17
+ *
18
+ * clean = pickDefinedValues(dirty);
19
+ *
20
+ * // @ts-expect-error -- you can’t access this property
21
+ * clean.invalid
22
+ * ```
23
+ */
24
+ export declare const pickTargetingValues: <T extends Record<string, string | readonly string[] | undefined>>(obj: T) => ValidTargetingObject<T>;
25
+ export {};
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.pickTargetingValues = void 0;
4
+ const libs_1 = require("@guardian/libs");
5
+ const isTargetingString = (string) => (0, libs_1.isString)(string) && string !== '';
6
+ const isTargetingArray = (array) => Array.isArray(array) && array.filter(isTargetingString).length > 0;
7
+ const isValidTargeting = (value) => {
8
+ if (isTargetingString(value))
9
+ return true;
10
+ if (isTargetingArray(value))
11
+ return true;
12
+ return false;
13
+ };
14
+ /**
15
+ * Picks only keys with targeting values from an object.
16
+ * A targeting values is defined as either:
17
+ * - a non-empty string
18
+ * - an array of non-empty strings
19
+ *
20
+ * If you object is read-only, you can safely access properties on the result.
21
+ * For example:
22
+ *
23
+ * ```ts
24
+ * dirty = {
25
+ * valid: 'real',
26
+ * invalid: undefined,
27
+ * } as const;
28
+ *
29
+ * clean = pickDefinedValues(dirty);
30
+ *
31
+ * // @ts-expect-error -- you can’t access this property
32
+ * clean.invalid
33
+ * ```
34
+ */
35
+ const pickTargetingValues = (obj) => {
36
+ const initialValue = {};
37
+ return Object.entries(obj).reduce((valid, [key, value]) => {
38
+ if (isValidTargeting(value)) {
39
+ // @ts-expect-error -- isValidTargeting checks this
40
+ valid[key] = Array.isArray(value)
41
+ ? value.filter(isTargetingString)
42
+ : value;
43
+ }
44
+ return valid;
45
+ }, initialValue);
46
+ };
47
+ exports.pickTargetingValues = pickTargetingValues;
@@ -0,0 +1,111 @@
1
+ import type { Participations } from '@guardian/ab-core';
2
+ import type { CountryCode } from '@guardian/libs';
3
+ import type { False, True } from './types';
4
+ declare const referrers: readonly [{
5
+ readonly id: "facebook";
6
+ readonly match: "facebook.com";
7
+ }, {
8
+ readonly id: "google";
9
+ readonly match: "www.google";
10
+ }, {
11
+ readonly id: "twitter";
12
+ readonly match: "/t.co/";
13
+ }, {
14
+ readonly id: "reddit";
15
+ readonly match: "reddit.com";
16
+ }];
17
+ /**
18
+ * Session Targeting is based on the browser session
19
+ *
20
+ * Includes information such as the country of origin, referrer, page view ID.
21
+ *
22
+ * These values identify a browser session are either generated client-side,
23
+ * read from a cookie or passed down from the server.
24
+ */
25
+ type SessionTargeting = {
26
+ /**
27
+ * **AB** Tests – [see on Ad Manager][gam]
28
+ *
29
+ * Type: _Dynamic_
30
+ *
31
+ * Values: typically start with `ab`
32
+ *
33
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=186327
34
+ */
35
+ ab: string[] | null;
36
+ /**
37
+ * **A**d **T**est – [see on Ad Manager][gam]
38
+ *
39
+ * Used for testing purposes, based on query param and/or cookie.
40
+ *
41
+ * Type: _Dynamic_
42
+ *
43
+ * [See Current values](https://frontend.gutools.co.uk/commercial/adtests)
44
+ *
45
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=177567
46
+ */
47
+ at: string | null;
48
+ /**
49
+ * **C**ountry **C**ode – [see on Ad Manager][gam]
50
+ *
51
+ * Type: _Dynamic_
52
+ *
53
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=11703293
54
+ */
55
+ cc: CountryCode;
56
+ /**
57
+ * Ophan **P**age **V**iew id – [see on Ad Manager][gam]
58
+ *
59
+ * ID Generated client-side, usually available on
60
+ * `guardian.config.ophan.pageViewId`
61
+ *
62
+ * Used mainly for internal reporting
63
+ *
64
+ * Type: _Dynamic_
65
+ *
66
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=206127
67
+ */
68
+ pv: string;
69
+ /**
70
+ * **Ref**errer – [see on Ad Manager][gam]
71
+ *
72
+ * Type: _Dynamic_
73
+ *
74
+ * Sample values:
75
+ * - `facebook`
76
+ * - `google`
77
+ * - `googleplus`
78
+ * - `reddit`
79
+ * - `twitter`
80
+ *
81
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=228567
82
+ */
83
+ ref: (typeof referrers)[number]['id'] | null;
84
+ /**
85
+ * **S**igned **I**n – [see on Ad Manager][gam]
86
+ *
87
+ *Whether a user is signed in. Based on presence of a cookie.
88
+ *
89
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=215727
90
+ */
91
+ si: True | False;
92
+ };
93
+ type AllParticipations = {
94
+ clientSideParticipations: Participations;
95
+ serverSideParticipations: {
96
+ [key: `${string}Control`]: 'control';
97
+ [key: `${string}Variant`]: 'variant';
98
+ };
99
+ };
100
+ declare const experimentsTargeting: ({ clientSideParticipations, serverSideParticipations, }: AllParticipations) => SessionTargeting["ab"];
101
+ type Session = {
102
+ adTest: SessionTargeting['at'];
103
+ countryCode: CountryCode;
104
+ isSignedIn: boolean;
105
+ pageViewId: SessionTargeting['pv'];
106
+ participations: AllParticipations;
107
+ referrer: string;
108
+ };
109
+ declare const getSessionTargeting: ({ adTest, countryCode, isSignedIn, pageViewId, participations, referrer, }: Session) => SessionTargeting;
110
+ export type { SessionTargeting, AllParticipations };
111
+ export { getSessionTargeting, experimentsTargeting };
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.experimentsTargeting = exports.getSessionTargeting = void 0;
4
+ const libs_1 = require("@guardian/libs");
5
+ /* -- Types -- */
6
+ const referrers = [
7
+ {
8
+ id: 'facebook',
9
+ match: 'facebook.com',
10
+ },
11
+ {
12
+ id: 'google',
13
+ match: 'www.google',
14
+ },
15
+ {
16
+ id: 'twitter',
17
+ match: '/t.co/',
18
+ },
19
+ {
20
+ id: 'reddit',
21
+ match: 'reddit.com',
22
+ },
23
+ ];
24
+ /* -- Methods -- */
25
+ const getReferrer = (referrer) => {
26
+ if (referrer === '')
27
+ return null;
28
+ const matchedRef = referrers.find((referrerType) => referrer.includes(referrerType.match)) ?? null;
29
+ return matchedRef ? matchedRef.id : null;
30
+ };
31
+ const experimentsTargeting = ({ clientSideParticipations, serverSideParticipations, }) => {
32
+ const testToParams = (testName, variant) => {
33
+ if (variant === 'notintest')
34
+ return null;
35
+ // GAM key-value pairs accept value strings up to 40 characters long
36
+ return `${testName}-${variant}`.substring(0, 40);
37
+ };
38
+ const clientSideExperiment = Object.entries(clientSideParticipations)
39
+ .map((test) => {
40
+ const [name, variant] = test;
41
+ return testToParams(name, variant.variant);
42
+ })
43
+ .filter(libs_1.isString);
44
+ const serverSideExperiments = Object.entries(serverSideParticipations)
45
+ .map((test) => testToParams(...test))
46
+ .filter(libs_1.isString);
47
+ if (clientSideExperiment.length + serverSideExperiments.length === 0) {
48
+ return null;
49
+ }
50
+ return [...clientSideExperiment, ...serverSideExperiments];
51
+ };
52
+ exports.experimentsTargeting = experimentsTargeting;
53
+ const getSessionTargeting = ({ adTest, countryCode, isSignedIn, pageViewId, participations, referrer, }) => ({
54
+ ab: experimentsTargeting(participations),
55
+ at: adTest,
56
+ cc: countryCode,
57
+ pv: pageViewId,
58
+ ref: getReferrer(referrer),
59
+ si: isSignedIn ? 't' : 'f',
60
+ });
61
+ exports.getSessionTargeting = getSessionTargeting;
@@ -0,0 +1,156 @@
1
+ type Brands = {
2
+ Foundation: 'f';
3
+ Paid: 'p';
4
+ Sponsored: 's';
5
+ };
6
+ type ContentTypes = [
7
+ 'article',
8
+ 'audio',
9
+ 'crossword',
10
+ 'gallery',
11
+ 'interactive',
12
+ 'liveblog',
13
+ 'network-front',
14
+ 'section',
15
+ 'tag',
16
+ 'video'
17
+ ];
18
+ type Editions = {
19
+ UnitedKingdom: 'uk';
20
+ UnitedStates: 'us';
21
+ Australia: 'au';
22
+ International: 'int';
23
+ };
24
+ type Platforms = {
25
+ R2: 'r2';
26
+ NextGen: 'ng';
27
+ MobileApp: 'app';
28
+ AcceleratedMobilePages: 'amp';
29
+ };
30
+ declare const surges: {
31
+ readonly 0: "0";
32
+ readonly 50: "5";
33
+ readonly 100: "4";
34
+ readonly 200: "3";
35
+ readonly 300: "2";
36
+ readonly 400: "1";
37
+ };
38
+ /**
39
+ * Shared Targeting is passed by `frontend`:
40
+ * https://github.com/guardian/frontend/blob/5b970cd7308175cfc1bcae2d4fb8c06ee13c5fa0/common/app/common/commercial/EditionAdTargeting.scala
41
+ *
42
+ * It is generated in `commercial-shared`:
43
+ * https://github.com/guardian/commercial-shared/blob/a692e8b2eba6e79eeeb666e5594f2193663f6514/src/main/scala/com/gu/commercial/display/AdTargetParam.scala
44
+ *
45
+ *
46
+ *
47
+ */
48
+ type SharedTargeting = {
49
+ /**
50
+ * **Bl**og tags – [see on Ad Manager][gam]
51
+ *
52
+ * Type: _Dynamic_
53
+ *
54
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=186687
55
+ */
56
+ bl: string[];
57
+ /**
58
+ * **Br**anding - [see on Ad Manager][gam]
59
+ *
60
+ * Type: _Predefined_
61
+ *
62
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=259767
63
+ */
64
+ br: Brands[keyof Brands];
65
+ /**
66
+ * **Co**ntributors and Authors - [see on Ad Manager][gam]
67
+ *
68
+ * Array of all contributors to the content on the page
69
+ *
70
+ * Type: _Dynamic_
71
+ *
72
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=186207
73
+ */
74
+ co: string[];
75
+ /**
76
+ * **C**ontent **T**ype - [see on Ad Manager][gam]
77
+ *
78
+ * Type: _Predefined_
79
+ *
80
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=177807
81
+ */
82
+ ct: ContentTypes[number];
83
+ /**
84
+ * **Edition** - [see on Ad Manager][gam]
85
+ *
86
+ * Type: _Predefined_
87
+ *
88
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=174207
89
+ */
90
+ edition: Editions[keyof Editions];
91
+ /**
92
+ * **K**eywords - [see on Ad Manager][gam]
93
+ *
94
+ * Type: _Dynamic_
95
+ *
96
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=177687
97
+ */
98
+ k: string[];
99
+ /**
100
+ * **Ob**server Content - [see on Ad Manager][gam]
101
+ *
102
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=256887
103
+ */
104
+ ob: 't';
105
+ /**
106
+ * **P**latform - [see on Ad Manager][gam]
107
+ *
108
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=180207
109
+ */
110
+ p: Platforms[keyof Platforms];
111
+ /**
112
+ * **Se**ries - [see on Ad Manager][gam]
113
+ *
114
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=180447
115
+ */
116
+ se: string[];
117
+ /**
118
+ * **Sh**ort URL - [see on Ad Manager][gam]
119
+ *
120
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=286047
121
+ */
122
+ sh: `https://www.theguardian.com/p/${string}`;
123
+ /**
124
+ * **Su**rging Article - [see on Ad Manager][gam]
125
+ *
126
+ * Type: _Predefined_
127
+ *
128
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=185007
129
+ */
130
+ su: Array<(typeof surges)[keyof typeof surges]>;
131
+ /**
132
+ * **T**o**n**es - [see on Ad Manager][gam]
133
+ *
134
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=191487
135
+ */
136
+ tn: string[];
137
+ /**
138
+ * **U**niform **R**esource **L**ocator - [see on Ad Manager][gam]
139
+ *
140
+ * Relative to `www.theguardian.com`, starts with `/`
141
+ *
142
+ * Type: _Dynamic_
143
+ *
144
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=174327
145
+ */
146
+ url: `/${string}`;
147
+ };
148
+ /**
149
+ * What goes in comes out
150
+ */
151
+ declare const getSharedTargeting: (shared: Partial<SharedTargeting>) => Partial<SharedTargeting>;
152
+ export declare const _: {
153
+ getSurgingParam: (surging: number) => SharedTargeting["su"];
154
+ };
155
+ export type { SharedTargeting };
156
+ export { getSharedTargeting };
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getSharedTargeting = exports._ = void 0;
4
+ const pick_targeting_values_1 = require("./pick-targeting-values");
5
+ const surges = {
6
+ 0: '0',
7
+ 50: '5',
8
+ 100: '4',
9
+ 200: '3',
10
+ 300: '2',
11
+ 400: '1',
12
+ };
13
+ /* -- Methods -- */
14
+ const getSurgingParam = (surging) => {
15
+ if (surging < 50 || isNaN(surging))
16
+ return ['0'];
17
+ const thresholds = [400, 300, 200, 100, 50];
18
+ return thresholds.filter((n) => n <= surging).map((s) => surges[s]);
19
+ };
20
+ /* -- Targeting -- */
21
+ /**
22
+ * What goes in comes out
23
+ */
24
+ const getSharedTargeting = (shared) => (0, pick_targeting_values_1.pickTargetingValues)(shared);
25
+ exports.getSharedTargeting = getSharedTargeting;
26
+ exports._ = {
27
+ getSurgingParam,
28
+ };
@@ -0,0 +1,2 @@
1
+ declare const isEligibleForTeads: (slotId: string) => boolean;
2
+ export { isEligibleForTeads };
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isEligibleForTeads = void 0;
4
+ const allowedContentTypes = ['Article', 'LiveBlog'];
5
+ const isEligibleForTeads = (slotId) => {
6
+ const { contentType, isSensitive } = window.guardian.config.page;
7
+ // This IAS value is returned when a page is thought to contain content which is not brand safe
8
+ const isBrandSafe = !window.googletag
9
+ .pubads()
10
+ .getTargeting('ias-kw')
11
+ .includes('IAS_16425_KW');
12
+ if (slotId === 'dfp-ad--inline1' &&
13
+ allowedContentTypes.includes(contentType) &&
14
+ !isSensitive &&
15
+ isBrandSafe) {
16
+ return true;
17
+ }
18
+ return false;
19
+ };
20
+ exports.isEligibleForTeads = isEligibleForTeads;
@@ -0,0 +1,6 @@
1
+ export type False = 'f';
2
+ export type True = 't';
3
+ export type TrueOrFalse = True | False;
4
+ export type NotApplicable = 'na';
5
+ export type MaybeArray<T> = T | T[];
6
+ export type CustomParams = Record<string, MaybeArray<string | number | boolean>>;
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,48 @@
1
+ import type { False, True } from './types';
2
+ /**
3
+ * Viewport Targeting
4
+ *
5
+ * Includes values related to the viewport:
6
+ * - breakpoint (deprecated?)
7
+ * - whether a CMP banner will show
8
+ * - size of page skin
9
+ */
10
+ type ViewportTargeting = {
11
+ /**
12
+ * **B**reak**p**oint – [see on Ad Manager][gam]
13
+ *
14
+ * Type: _Predefined_
15
+ *
16
+ * TODO: remove 'wide'
17
+ *
18
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=180327
19
+ */
20
+ bp: 'mobile' | 'tablet' | 'desktop';
21
+ /**
22
+ * InSkin (CMP Banner shown) – [see on Ad Manager][gam]
23
+ *
24
+ * Australia-specific (via Bonzai?)
25
+ *
26
+ * Type: _Predefined_
27
+ *
28
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=11916570
29
+ * */
30
+ inskin: True | False;
31
+ /**
32
+ * **Skin size** – [see on Ad Manager][gam]
33
+ *
34
+ * Large or Small. Used for InSkin page skins
35
+ *
36
+ * Type: _Predefined_
37
+ *
38
+ * [gam]: https://admanager.google.com/59666047#inventory/custom_targeting/detail/custom_key_id=12312030
39
+ */
40
+ skinsize: 'l' | 's';
41
+ };
42
+ type Viewport = {
43
+ viewPortWidth: number;
44
+ cmpBannerWillShow: boolean;
45
+ };
46
+ declare const getViewportTargeting: ({ viewPortWidth, cmpBannerWillShow, }: Viewport) => ViewportTargeting;
47
+ export type { ViewportTargeting };
48
+ export { getViewportTargeting };
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getViewportTargeting = void 0;
4
+ /* -- Methods -- */
5
+ const findBreakpoint = (width) => {
6
+ if (width >= 980)
7
+ return 'desktop';
8
+ if (width >= 660)
9
+ return 'tablet';
10
+ return 'mobile';
11
+ };
12
+ const getViewportTargeting = ({ viewPortWidth, cmpBannerWillShow, }) => {
13
+ // Don’t show inskin if if a privacy message will be shown or on preview
14
+ const isPreview = window.guardian.config.page.isPreview;
15
+ const inskin = cmpBannerWillShow || isPreview ? 'f' : 't';
16
+ return {
17
+ bp: findBreakpoint(viewPortWidth),
18
+ skinsize: viewPortWidth >= 1560 ? 'l' : 's',
19
+ inskin,
20
+ };
21
+ };
22
+ exports.getViewportTargeting = getViewportTargeting;
@@ -0,0 +1,12 @@
1
+ import type { Participations } from '@guardian/ab-core';
2
+ import type { ConsentState } from '@guardian/libs';
3
+ import type { CustomParams } from './types';
4
+ type BuildImaAdTagUrl = {
5
+ adUnit: string;
6
+ customParams: CustomParams;
7
+ consentState: ConsentState;
8
+ clientSideParticipations: Participations;
9
+ isSignedIn: boolean;
10
+ };
11
+ declare const buildImaAdTagUrl: ({ adUnit, clientSideParticipations, consentState, customParams, isSignedIn, }: BuildImaAdTagUrl) => string;
12
+ export { buildImaAdTagUrl };