@highfivve/ad-tag 5.5.4

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 (132) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +149 -0
  3. package/lib/ads/a9.js +190 -0
  4. package/lib/ads/adPipeline.js +159 -0
  5. package/lib/ads/adService.js +251 -0
  6. package/lib/ads/adUnitPath.js +37 -0
  7. package/lib/ads/auctions/adRequestThrottling.js +22 -0
  8. package/lib/ads/auctions/biddersDisabling.js +90 -0
  9. package/lib/ads/auctions/frequencyCapping.js +189 -0
  10. package/lib/ads/auctions/interstitialContext.js +92 -0
  11. package/lib/ads/auctions/previousBidCpms.js +33 -0
  12. package/lib/ads/auctions/resume.js +3 -0
  13. package/lib/ads/bridge/bridge.js +62 -0
  14. package/lib/ads/consent.js +63 -0
  15. package/lib/ads/eventService.js +44 -0
  16. package/lib/ads/globalAuctionContext.js +98 -0
  17. package/lib/ads/googleAdManager.js +380 -0
  18. package/lib/ads/keyValues.js +1 -0
  19. package/lib/ads/labelConfigService.js +42 -0
  20. package/lib/ads/modules/ad-reload/adVisibilityService.js +158 -0
  21. package/lib/ads/modules/ad-reload/index.js +163 -0
  22. package/lib/ads/modules/ad-reload/userActivityService.js +70 -0
  23. package/lib/ads/modules/adex/adex-mapping.js +77 -0
  24. package/lib/ads/modules/adex/adexUtiq.js +15 -0
  25. package/lib/ads/modules/adex/index.js +142 -0
  26. package/lib/ads/modules/adex/sendAdvertisingId.js +20 -0
  27. package/lib/ads/modules/blocklist-url/index.js +118 -0
  28. package/lib/ads/modules/cleanup/index.js +93 -0
  29. package/lib/ads/modules/confiant/index.js +47 -0
  30. package/lib/ads/modules/emetriq/index.js +154 -0
  31. package/lib/ads/modules/emetriq/trackInApp.js +34 -0
  32. package/lib/ads/modules/emetriq/trackLoginEvent.js +59 -0
  33. package/lib/ads/modules/generic-skin/index.js +150 -0
  34. package/lib/ads/modules/identitylink/index.js +58 -0
  35. package/lib/ads/modules/interstitial/index.js +38 -0
  36. package/lib/ads/modules/interstitial/interstitialAd.js +111 -0
  37. package/lib/ads/modules/lazy-load/index.js +191 -0
  38. package/lib/ads/modules/lazy-load/selectInfiniteSlot.js +11 -0
  39. package/lib/ads/modules/prebid-first-party-data/index.js +115 -0
  40. package/lib/ads/modules/pubstack/index.js +59 -0
  41. package/lib/ads/modules/sticky-footer-ad/desktopFloorAd.js +63 -0
  42. package/lib/ads/modules/sticky-footer-ad/index.js +43 -0
  43. package/lib/ads/modules/sticky-footer-ad/mobileSticky.js +93 -0
  44. package/lib/ads/modules/sticky-footer-ad-v2/footerStickyAd.js +118 -0
  45. package/lib/ads/modules/sticky-footer-ad-v2/index.js +43 -0
  46. package/lib/ads/modules/sticky-header-ad/fadeOutCallback.js +25 -0
  47. package/lib/ads/modules/sticky-header-ad/index.js +103 -0
  48. package/lib/ads/modules/sticky-header-ad/renderResult.js +24 -0
  49. package/lib/ads/modules/utiq/index.js +79 -0
  50. package/lib/ads/modules/yield-optimization/dynamicFloorPrice.js +86 -0
  51. package/lib/ads/modules/yield-optimization/index.js +57 -0
  52. package/lib/ads/modules/yield-optimization/isYieldOptimizationConfigDynamic.js +6 -0
  53. package/lib/ads/modules/yield-optimization/yieldOptimizationService.js +169 -0
  54. package/lib/ads/modules/zeotap/index.js +111 -0
  55. package/lib/ads/moli.js +645 -0
  56. package/lib/ads/moliGlobal.js +11 -0
  57. package/lib/ads/prebid-outstream.js +13 -0
  58. package/lib/ads/prebid.js +406 -0
  59. package/lib/ads/sizeConfigService.js +49 -0
  60. package/lib/ads/spa.js +32 -0
  61. package/lib/bundle/adReload.js +2 -0
  62. package/lib/bundle/adex.js +2 -0
  63. package/lib/bundle/blocklistUrls.js +2 -0
  64. package/lib/bundle/cleanup.js +2 -0
  65. package/lib/bundle/confiant.js +2 -0
  66. package/lib/bundle/configureFromEndpoint.js +40 -0
  67. package/lib/bundle/emetriq.js +2 -0
  68. package/lib/bundle/identityLink.js +2 -0
  69. package/lib/bundle/init.js +2 -0
  70. package/lib/bundle/interstitialModule.js +2 -0
  71. package/lib/bundle/lazyLoad.js +2 -0
  72. package/lib/bundle/prebidFirstPartyData.js +2 -0
  73. package/lib/bundle/pubstack.js +2 -0
  74. package/lib/bundle/skin.js +2 -0
  75. package/lib/bundle/stickyFooterAd.js +2 -0
  76. package/lib/bundle/stickyFooterAds2.js +2 -0
  77. package/lib/bundle/stickyHeaderAd.js +2 -0
  78. package/lib/bundle/utiq.js +2 -0
  79. package/lib/bundle/yieldOptimization.js +2 -0
  80. package/lib/bundle/zeotap.js +2 -0
  81. package/lib/console/components/adSlotConfig.js +225 -0
  82. package/lib/console/components/consentConfig.js +138 -0
  83. package/lib/console/components/globalConfig.js +634 -0
  84. package/lib/console/components/labelConfigDebug.js +19 -0
  85. package/lib/console/components/sizeConfigDebug.js +34 -0
  86. package/lib/console/components/tag.js +4 -0
  87. package/lib/console/debug.js +38 -0
  88. package/lib/console/util/array.js +1 -0
  89. package/lib/console/util/calculateAdDensity.js +36 -0
  90. package/lib/console/util/debounce.js +12 -0
  91. package/lib/console/util/debugLogger.js +6 -0
  92. package/lib/console/util/extractPositionFromPath.js +8 -0
  93. package/lib/console/util/prebid.js +3 -0
  94. package/lib/console/util/stringUtils.js +23 -0
  95. package/lib/console/util/themingService.js +31 -0
  96. package/lib/console/util/windowResizeService.js +22 -0
  97. package/lib/console/validations/adReloadValidations.js +47 -0
  98. package/lib/console/validations/bucketValidations.js +78 -0
  99. package/lib/console/validations/sizesConfigValidations.js +97 -0
  100. package/lib/gen/packageJson.js +3 -0
  101. package/lib/index.js +3 -0
  102. package/lib/types/apstag.js +1 -0
  103. package/lib/types/dom.js +1 -0
  104. package/lib/types/emetriq.js +1 -0
  105. package/lib/types/googletag.js +1 -0
  106. package/lib/types/identitylink.js +1 -0
  107. package/lib/types/module.js +1 -0
  108. package/lib/types/moliConfig.js +1 -0
  109. package/lib/types/moliRuntime.js +1 -0
  110. package/lib/types/prebidjs.js +45 -0
  111. package/lib/types/supplyChainObject.js +1 -0
  112. package/lib/types/tcfapi.js +48 -0
  113. package/lib/util/addNewInfiniteSlotToConfig.js +11 -0
  114. package/lib/util/arrayUtils.js +9 -0
  115. package/lib/util/assetLoaderService.js +91 -0
  116. package/lib/util/browserStorageKeys.js +7 -0
  117. package/lib/util/debugDelay.js +12 -0
  118. package/lib/util/domready.js +15 -0
  119. package/lib/util/environmentOverride.js +16 -0
  120. package/lib/util/extractAdTagVersion.js +16 -0
  121. package/lib/util/extractTopPrivateDomainFromHostname.js +17 -0
  122. package/lib/util/localStorage.js +26 -0
  123. package/lib/util/logging.js +106 -0
  124. package/lib/util/objectUtils.js +29 -0
  125. package/lib/util/query.js +40 -0
  126. package/lib/util/queryParameters.js +5 -0
  127. package/lib/util/resolveOverrides.js +21 -0
  128. package/lib/util/resolveStoredRequestIdInOrtb2Object.js +12 -0
  129. package/lib/util/sizes.js +3 -0
  130. package/lib/util/test-slots.js +150 -0
  131. package/lib/util/uuid.js +10 -0
  132. package/package.json +127 -0
@@ -0,0 +1,189 @@
1
+ import { remainingTime } from './resume';
2
+ import { resolveAdUnitPath } from '../adUnitPath';
3
+ import { formatKey } from 'ad-tag/ads/keyValues';
4
+ import { isGamInterstitial } from 'ad-tag/ads/auctions/interstitialContext';
5
+ const sessionStorageKey = 'h5v-fc';
6
+ const hasPacingInterval = (config) => !!config.conditions && !!config.conditions.pacingInterval;
7
+ export const createFrequencyCapping = (config, _window, now, logger) => {
8
+ const positionImpSchedules = new Map();
9
+ const positionLastImpressionNumberOfAdRequests = new Map();
10
+ const bidderImpSchedules = new Map();
11
+ const positionAdRequests = new Map();
12
+ let numAdRequests = 0;
13
+ const pacingIntervalConfigs = config.bidders?.filter(hasPacingInterval) ?? [];
14
+ const bidWonConfigs = pacingIntervalConfigs.filter(config => !config.conditions.pacingInterval?.events ||
15
+ config.conditions.pacingInterval?.events?.includes('bidWon')) ?? [];
16
+ const bidRequestedConfigs = pacingIntervalConfigs.filter(config => config.conditions.pacingInterval?.events?.includes('bidRequested')) ?? [];
17
+ let resolvedAdUnitPathPositionConfigs = config.positions || [];
18
+ const persist = () => {
19
+ if (config.persistent === true) {
20
+ const data = {
21
+ bCaps: Array.from(bidderImpSchedules.entries()).reduce((acc, [key, schedules]) => ({ ...acc, [key]: schedules }), {}),
22
+ pCaps: Array.from(positionImpSchedules.entries()).reduce((acc, [adUnitPath, schedules]) => ({ ...acc, [adUnitPath]: schedules }), {}),
23
+ pLastImpAdRequests: Array.from(positionLastImpressionNumberOfAdRequests.entries()).reduce((acc, [adUnitPath, numAdRequests]) => ({ ...acc, [adUnitPath]: numAdRequests }), {}),
24
+ requestAds: numAdRequests
25
+ };
26
+ _window.sessionStorage.setItem(sessionStorageKey, JSON.stringify(data));
27
+ }
28
+ };
29
+ const cap = (startTimestamp, config, intervalInMs, bid) => {
30
+ const bidders = config.bidders;
31
+ if ((!bidders || bidders.includes(bid.bidder)) && config.domId === bid.adUnitCode) {
32
+ const key = `${bid.adUnitCode}:${bid.bidder}`;
33
+ const currentSchedules = bidderImpSchedules.get(key) ?? [];
34
+ currentSchedules.push({
35
+ ts: startTimestamp,
36
+ wait: intervalInMs
37
+ });
38
+ bidderImpSchedules.set(key, currentSchedules);
39
+ _window.setTimeout(() => {
40
+ logger.debug('fc', `removing ${key} at ${startTimestamp}`);
41
+ const schedules = bidderImpSchedules.get(key);
42
+ if (schedules) {
43
+ bidderImpSchedules.set(key, schedules.filter(s => s.ts !== startTimestamp));
44
+ }
45
+ }, intervalInMs);
46
+ persist();
47
+ }
48
+ };
49
+ const capPosition = (startTimestamp, adUnitPath, pacingInterval) => {
50
+ const currentSchedules = positionImpSchedules.get(adUnitPath) ?? [];
51
+ currentSchedules.push({ ts: startTimestamp, wait: pacingInterval.intervalInMs });
52
+ positionImpSchedules.set(adUnitPath, currentSchedules);
53
+ _window.setTimeout(() => {
54
+ const schedules = positionImpSchedules.get(adUnitPath);
55
+ if (schedules) {
56
+ positionImpSchedules.set(adUnitPath, schedules.filter(s => s.ts !== startTimestamp));
57
+ }
58
+ }, pacingInterval.intervalInMs);
59
+ persist();
60
+ };
61
+ const onSlotRenderEndedOrImpressionViewable = (adUnitPath) => {
62
+ resolvedAdUnitPathPositionConfigs
63
+ .filter(config => config.adUnitPath === adUnitPath)
64
+ .forEach(config => {
65
+ if (config.conditions.pacingInterval) {
66
+ capPosition(now(), adUnitPath, config.conditions.pacingInterval);
67
+ }
68
+ if (config.conditions.pacingRequestAds) {
69
+ positionLastImpressionNumberOfAdRequests.set(adUnitPath, numAdRequests);
70
+ persist();
71
+ }
72
+ });
73
+ };
74
+ if (config.persistent === true) {
75
+ const storedData = _window.sessionStorage.getItem(sessionStorageKey);
76
+ if (storedData) {
77
+ try {
78
+ const parsedData = JSON.parse(storedData);
79
+ numAdRequests = parsedData.requestAds;
80
+ Object.entries(parsedData.bCaps).forEach(([adUnitBidderKey, schedules]) => {
81
+ schedules?.forEach(schedule => {
82
+ const [adUnitCode, bidder] = adUnitBidderKey.split(':');
83
+ const blockedForMs = remainingTime(schedule, now());
84
+ cap(now(), { domId: adUnitCode, bidders: [bidder] }, blockedForMs, {
85
+ bidder,
86
+ adUnitCode
87
+ });
88
+ });
89
+ });
90
+ Object.entries(parsedData.pCaps).forEach(([adUnitPath, schedules]) => {
91
+ schedules?.forEach(schedule => {
92
+ const blockedForMs = remainingTime(schedule, now());
93
+ capPosition(schedule.ts, adUnitPath, { intervalInMs: blockedForMs });
94
+ });
95
+ });
96
+ }
97
+ catch (e) {
98
+ logger.error('fc', 'failed to parse fc state', e);
99
+ }
100
+ }
101
+ }
102
+ return {
103
+ onSlotRequested(event) {
104
+ resolvedAdUnitPathPositionConfigs
105
+ .filter(config => config.adUnitPath === event.slot.getAdUnitPath())
106
+ .forEach(config => {
107
+ if (config.conditions.adRequestLimit) {
108
+ const adUnitPath = config.adUnitPath;
109
+ const currentAdRequests = positionAdRequests.get(adUnitPath) ?? 0;
110
+ positionAdRequests.set(adUnitPath, currentAdRequests + 1);
111
+ }
112
+ });
113
+ },
114
+ onAuctionEnd(auction) {
115
+ bidRequestedConfigs.forEach(config => {
116
+ auction.bidderRequests?.forEach(bidderRequests => {
117
+ bidderRequests?.bids?.forEach(bid => {
118
+ cap(now(), config, config.conditions.pacingInterval.intervalInMs, bid);
119
+ });
120
+ });
121
+ });
122
+ persist();
123
+ },
124
+ onBidWon(bid) {
125
+ bidWonConfigs.forEach(config => cap(now(), config, config.conditions.pacingInterval.intervalInMs, bid));
126
+ persist();
127
+ },
128
+ onSlotRenderEnded(event) {
129
+ const [format] = event.slot.getTargeting(formatKey);
130
+ if (!event.isEmpty &&
131
+ format !== 5..toString()) {
132
+ onSlotRenderEndedOrImpressionViewable(event.slot.getAdUnitPath());
133
+ }
134
+ },
135
+ onImpressionViewable(event) {
136
+ const [format] = event.slot.getTargeting(formatKey);
137
+ if (format === 5..toString()) {
138
+ onSlotRenderEndedOrImpressionViewable(event.slot.getAdUnitPath());
139
+ }
140
+ },
141
+ beforeRequestAds() {
142
+ positionAdRequests.clear();
143
+ },
144
+ afterRequestAds() {
145
+ numAdRequests++;
146
+ persist();
147
+ },
148
+ updateAdUnitPaths(adUnitPathVariables) {
149
+ resolvedAdUnitPathPositionConfigs = (config.positions ?? []).map(config => {
150
+ return { ...config, adUnitPath: resolveAdUnitPath(config.adUnitPath, adUnitPathVariables) };
151
+ });
152
+ },
153
+ isAdUnitCapped(slot) {
154
+ const adUnitPath = slot.getAdUnitPath();
155
+ const isGamInst = isGamInterstitial(slot, _window);
156
+ return resolvedAdUnitPathPositionConfigs
157
+ .filter(config => config.adUnitPath === adUnitPath)
158
+ .some(positionConfig => {
159
+ return ((positionConfig.adUnitPath === adUnitPath &&
160
+ positionConfig.conditions.delay &&
161
+ numAdRequests <
162
+ positionConfig.conditions.delay.minRequestAds - (isGamInst ? 1 : 0)) ||
163
+ (positionConfig.conditions.pacingRequestAds &&
164
+ positionLastImpressionNumberOfAdRequests.has(adUnitPath) &&
165
+ numAdRequests - (positionLastImpressionNumberOfAdRequests.get(adUnitPath) ?? 0) <
166
+ positionConfig.conditions.pacingRequestAds.requestAds) ||
167
+ (positionConfig.conditions.pacingInterval &&
168
+ (positionImpSchedules.get(adUnitPath) ?? []).length >=
169
+ positionConfig.conditions.pacingInterval.maxImpressions) ||
170
+ (positionConfig.conditions.adRequestLimit &&
171
+ (positionAdRequests.get(adUnitPath) ?? 0) >=
172
+ positionConfig.conditions.adRequestLimit.maxAdRequests));
173
+ });
174
+ },
175
+ isBidderCapped(slotId, bidder) {
176
+ if (!config.bidders) {
177
+ return false;
178
+ }
179
+ return config.bidders
180
+ .filter(c => c.domId === slotId && (!c.bidders || c.bidders.includes(bidder)))
181
+ .some(({ conditions: { pacingInterval, delay } }) => {
182
+ return ((pacingInterval &&
183
+ (bidderImpSchedules.get(`${slotId}:${bidder}`) ?? []).length >=
184
+ pacingInterval.maxImpressions) ||
185
+ (delay && numAdRequests < delay.minRequestAds));
186
+ });
187
+ }
188
+ };
189
+ };
@@ -0,0 +1,92 @@
1
+ import { resolveAdUnitPath } from 'ad-tag/ads/adUnitPath';
2
+ import { formatKey } from 'ad-tag/ads/keyValues';
3
+ export const isGamInterstitial = (slot, window) => {
4
+ const [value] = slot.getTargeting(formatKey);
5
+ return !!value && value === window.googletag.enums.OutOfPageFormat.INTERSTITIAL.toString();
6
+ };
7
+ export const createInterstitialContext = (config, window__, now, logger) => {
8
+ const sessionStorageKey = 'h5v_intstl';
9
+ const sessionStorageTimeToLive = config.ttlStorage ?? 30 * 60 * 1000;
10
+ const currentTime = now();
11
+ let interstitialAdUnitPath = config.adUnitPath;
12
+ let currentInterstitialState = {
13
+ priority: config.priority,
14
+ updatedAt: currentTime
15
+ };
16
+ try {
17
+ const sessionState = window__.sessionStorage.getItem(sessionStorageKey);
18
+ if (sessionState) {
19
+ const parsedState = JSON.parse(sessionState);
20
+ if (currentTime - parsedState.updatedAt < sessionStorageTimeToLive) {
21
+ currentInterstitialState = parsedState;
22
+ }
23
+ else {
24
+ currentInterstitialState.updatedAt = currentTime;
25
+ }
26
+ }
27
+ }
28
+ catch (e) {
29
+ logger.error('interstitial', 'failed to load interstitial state from session storage', e);
30
+ }
31
+ if (config.priority.length === 0) {
32
+ logger.error('interstitial', 'no interstitial priority configured');
33
+ }
34
+ const persistInterstitialState = () => {
35
+ currentInterstitialState.updatedAt = now();
36
+ try {
37
+ window.sessionStorage.setItem(sessionStorageKey, JSON.stringify(currentInterstitialState));
38
+ }
39
+ catch (e) {
40
+ logger.error('interstitial', 'failed to persist interstitial state to session storage', e);
41
+ }
42
+ };
43
+ const shiftDemandPriority = (arr) => {
44
+ if (arr.length === 0) {
45
+ return [];
46
+ }
47
+ return [...arr.slice(1), arr[0]];
48
+ };
49
+ const onSlotRenderEnded = (event) => {
50
+ if (event.slot.getAdUnitPath() !== interstitialAdUnitPath) {
51
+ return;
52
+ }
53
+ if (event.isEmpty) {
54
+ currentInterstitialState.priority = shiftDemandPriority(currentInterstitialState.priority);
55
+ persistInterstitialState();
56
+ }
57
+ };
58
+ const onImpressionViewable = (event) => {
59
+ if (event.slot.getAdUnitPath() !== interstitialAdUnitPath) {
60
+ return;
61
+ }
62
+ if (isGamInterstitial(event.slot, window__)) {
63
+ currentInterstitialState.priority = shiftDemandPriority(currentInterstitialState.priority);
64
+ persistInterstitialState();
65
+ }
66
+ };
67
+ const onAuctionEnd = (event) => {
68
+ if (!event.adUnitCodes.includes(config.domId)) {
69
+ return;
70
+ }
71
+ const interstitialBids = event.bidsReceived?.filter(bid => bid.adUnitCode === config.domId);
72
+ if ((interstitialBids?.length ?? 0) === 0) {
73
+ currentInterstitialState.priority = shiftDemandPriority(currentInterstitialState.priority);
74
+ persistInterstitialState();
75
+ }
76
+ };
77
+ const interstitialChannel = () => {
78
+ return currentInterstitialState.priority[0];
79
+ };
80
+ return {
81
+ interstitialChannel,
82
+ onSlotRenderEnded,
83
+ onImpressionViewable,
84
+ onAuctionEnd,
85
+ interstitialState: () => {
86
+ return currentInterstitialState;
87
+ },
88
+ updateAdUnitPaths: (variables) => {
89
+ interstitialAdUnitPath = resolveAdUnitPath(config.adUnitPath, variables);
90
+ }
91
+ };
92
+ };
@@ -0,0 +1,33 @@
1
+ export const createPreviousBidCpms = () => {
2
+ const lastBidCpms = new Map();
3
+ const groupReceivedBidsByAdUnitCode = (bidsReceived) => {
4
+ return bidsReceived.reduce((result, current) => {
5
+ const { adUnitCode, cpm } = current;
6
+ if (!result[adUnitCode]) {
7
+ result[adUnitCode] = [];
8
+ }
9
+ result[adUnitCode].push(cpm);
10
+ return result;
11
+ }, {});
12
+ };
13
+ const onAuctionEnd = (bidsReceived) => {
14
+ const bidsOfLastAuction = groupReceivedBidsByAdUnitCode(bidsReceived);
15
+ lastBidCpms.forEach((_, key) => {
16
+ if (!bidsOfLastAuction[key]) {
17
+ lastBidCpms.delete(key);
18
+ }
19
+ });
20
+ Object.entries(bidsOfLastAuction).forEach(([adUnitCode, cpmsOfLastAuction]) => {
21
+ const earlierCpmsOnPosition = getLastBidCpms(adUnitCode) ?? [];
22
+ lastBidCpms.set(adUnitCode, Array.from(new Set([...cpmsOfLastAuction, ...earlierCpmsOnPosition])));
23
+ });
24
+ };
25
+ const getLastBidCpms = (adUnitCode) => {
26
+ return lastBidCpms.get(adUnitCode) ?? null;
27
+ };
28
+ return {
29
+ groupReceivedBidsByAdUnitCode,
30
+ onAuctionEnd,
31
+ getLastBidCpms
32
+ };
33
+ };
@@ -0,0 +1,3 @@
1
+ export const remainingTime = (data, now) => {
2
+ return Math.max(data.wait - (now - data.ts), 0);
3
+ };
@@ -0,0 +1,62 @@
1
+ import { mkInitStep } from 'ad-tag/ads/adPipeline';
2
+ import { isPlainObject } from 'ad-tag/util/objectUtils';
3
+ const findAdSlot = (message, googletag) => googletag
4
+ .pubads()
5
+ .getSlots()
6
+ .find(slot => slot.getSlotElementId() === message.domId || slot.getAdUnitPath() === message.adUnitPath);
7
+ const parseMessageData = (data) => {
8
+ try {
9
+ const message = typeof data === 'string' ? JSON.parse(data) : isPlainObject(data) ? data : null;
10
+ switch (message?.event) {
11
+ case 'h5.adunit.passback':
12
+ return message.passbackOrigin && (message.domId || message.adUnitPath) ? message : null;
13
+ case 'h5.adunit.refresh':
14
+ return message;
15
+ default:
16
+ return null;
17
+ }
18
+ }
19
+ catch (err) {
20
+ return null;
21
+ }
22
+ };
23
+ const handleRefresh = (message, context) => {
24
+ const backfillMoliSlot = context.config__.slots.find(slot => slot.domId === message.domId && slot.behaviour.loaded === 'backfill');
25
+ const adSlot = findAdSlot(message, context.window__.googletag);
26
+ if (backfillMoliSlot && adSlot) {
27
+ context.logger__.debug('bridge', `Refresh ad slot ${message.domId}`);
28
+ context.window__.googletag.destroySlots([adSlot]);
29
+ context.window__.moli
30
+ .refreshAdSlot(message.domId, { loaded: 'backfill' })
31
+ .catch(e => context.logger__.error('bridge', `failed to refresh ${message.domId}`, e));
32
+ }
33
+ };
34
+ const handlePassback = (message, context) => {
35
+ const adSlot = findAdSlot(message, context.window__.googletag);
36
+ const passbackKey = 'passback';
37
+ if (adSlot && adSlot.getTargeting(passbackKey).length === 0) {
38
+ context.logger__.debug('passback', `Process passback for ad slot ${adSlot.getAdUnitPath()}`);
39
+ adSlot.setTargeting(passbackKey, 'true');
40
+ adSlot.setTargeting('passbackOrigin', message.passbackOrigin);
41
+ context.window__.googletag.pubads().refresh([adSlot]);
42
+ }
43
+ };
44
+ export const bridgeInitStep = () => mkInitStep('bridge', (context) => {
45
+ if (context.config__.bridge?.enabled) {
46
+ context.logger__.debug('bridge', 'add message listener');
47
+ context.window__.addEventListener('message', (event) => {
48
+ const message = parseMessageData(event.data);
49
+ if (message) {
50
+ switch (message.event) {
51
+ case 'h5.adunit.passback':
52
+ handlePassback(message, context);
53
+ break;
54
+ case 'h5.adunit.refresh':
55
+ handleRefresh(message, context);
56
+ break;
57
+ }
58
+ }
59
+ });
60
+ }
61
+ return Promise.resolve();
62
+ });
@@ -0,0 +1,63 @@
1
+ import { tcfapi } from '../types/tcfapi';
2
+ var EventStatus = tcfapi.status.EventStatus;
3
+ var CmpStatus = tcfapi.status.CmpStatus;
4
+ const allPurposes = [
5
+ tcfapi.responses.TCPurpose.STORE_INFORMATION_ON_DEVICE,
6
+ tcfapi.responses.TCPurpose.SELECT_BASIC_ADS,
7
+ tcfapi.responses.TCPurpose.CREATE_PERSONALISED_ADS_PROFILE,
8
+ tcfapi.responses.TCPurpose.SELECT_PERSONALISED_ADS,
9
+ tcfapi.responses.TCPurpose.CREATE_PERSONALISED_CONTENT_PROFILE,
10
+ tcfapi.responses.TCPurpose.SELECT_PERSONALISED_CONTENT,
11
+ tcfapi.responses.TCPurpose.MEASURE_AD_PERFORMANCE,
12
+ tcfapi.responses.TCPurpose.MEASURE_CONTENT_PERFORMANCE,
13
+ tcfapi.responses.TCPurpose.APPLY_MARKET_RESEARCH,
14
+ tcfapi.responses.TCPurpose.DEVELOP_IMPROVE_PRODUCTS
15
+ ];
16
+ export const missingPurposeConsent = (tcData) => {
17
+ return (!!tcData.gdprApplies &&
18
+ allPurposes.some(p => !tcData.purpose.consents[p]));
19
+ };
20
+ export const consentReady = (consentConfig, window, log, env) => {
21
+ if (env === 'test') {
22
+ log.info('gdprApplies is set to false in test mode!');
23
+ }
24
+ if (env === 'test' || consentConfig.enabled === false) {
25
+ return Promise.resolve({
26
+ gdprApplies: false,
27
+ eventStatus: EventStatus.TC_LOADED,
28
+ cmpStatus: CmpStatus.LOADED,
29
+ cmpId: 0,
30
+ cmpVersion: 0,
31
+ tcfPolicyVersion: undefined,
32
+ listenerId: null
33
+ });
34
+ }
35
+ return new Promise((resolve, reject) => {
36
+ if (window.__tcfapi) {
37
+ const listener = (tcData) => {
38
+ if (tcData.cmpStatus === 'error') {
39
+ reject(tcData);
40
+ }
41
+ else if (tcData.eventStatus === 'useractioncomplete' ||
42
+ tcData.eventStatus === 'tcloaded') {
43
+ log.debug('Consent', 'consent ready', tcData);
44
+ if (consentConfig.disableLegitimateInterest && missingPurposeConsent(tcData)) {
45
+ reject('user consent is missing for some purposes');
46
+ }
47
+ else {
48
+ resolve(tcData);
49
+ }
50
+ if (tcData.listenerId) {
51
+ window.__tcfapi('removeEventListener', 2, () => {
52
+ return;
53
+ }, tcData.listenerId);
54
+ }
55
+ }
56
+ };
57
+ window.__tcfapi('addEventListener', 2, listener);
58
+ }
59
+ else {
60
+ reject('window.__tcfapi is not defined. Make sure that the stub code is inlined in the head tag');
61
+ }
62
+ });
63
+ };
@@ -0,0 +1,44 @@
1
+ export const createEventService = () => {
2
+ const eventListeners = new Map();
3
+ const oneTimeListeners = new Map();
4
+ return {
5
+ addEventListener(event, listener, options = {}) {
6
+ const targetMap = options.once ? oneTimeListeners : eventListeners;
7
+ if (!targetMap.has(event)) {
8
+ targetMap.set(event, new Set());
9
+ }
10
+ targetMap.get(event)?.add(listener);
11
+ },
12
+ removeEventListener(event, listener) {
13
+ eventListeners.get(event)?.delete(listener);
14
+ oneTimeListeners.get(event)?.delete(listener);
15
+ },
16
+ emit(event, data) {
17
+ eventListeners.get(event)?.forEach(listener => {
18
+ try {
19
+ listener(data);
20
+ }
21
+ catch (error) {
22
+ console.error(`Error in event listener for ${String(event)}:`, error);
23
+ }
24
+ });
25
+ const oneTimeListenersForEvent = oneTimeListeners.get(event);
26
+ if (oneTimeListenersForEvent) {
27
+ oneTimeListenersForEvent.forEach(listener => {
28
+ try {
29
+ listener(data);
30
+ }
31
+ catch (error) {
32
+ console.error(`Error in one-time event listener for ${String(event)}:`, error);
33
+ }
34
+ finally {
35
+ oneTimeListenersForEvent.delete(listener);
36
+ }
37
+ });
38
+ if (oneTimeListenersForEvent.size === 0) {
39
+ oneTimeListeners.delete(event);
40
+ }
41
+ }
42
+ }
43
+ };
44
+ };
@@ -0,0 +1,98 @@
1
+ import { createBiddersDisabling } from './auctions/biddersDisabling';
2
+ import { createAdRequestThrottling } from './auctions/adRequestThrottling';
3
+ import { createFrequencyCapping } from './auctions/frequencyCapping';
4
+ import { createPreviousBidCpms } from './auctions/previousBidCpms';
5
+ import { mkConfigureStep } from './adPipeline';
6
+ import { createInterstitialContext } from 'ad-tag/ads/auctions/interstitialContext';
7
+ export const createGlobalAuctionContext = (window, logger, eventService, config = {}) => {
8
+ const biddersDisabling = config.biddersDisabling?.enabled
9
+ ? createBiddersDisabling(config.biddersDisabling, window)
10
+ : undefined;
11
+ const adRequestThrottling = config.adRequestThrottling?.enabled
12
+ ? createAdRequestThrottling(config.adRequestThrottling, window)
13
+ : undefined;
14
+ const frequencyCapping = config.frequencyCap?.enabled
15
+ ? createFrequencyCapping(config.frequencyCap, window, window.Date.now, logger)
16
+ : undefined;
17
+ const previousBidCpms = config.previousBidCpms?.enabled ? createPreviousBidCpms() : undefined;
18
+ const interstitial = config.interstitial?.enabled
19
+ ? createInterstitialContext(config.interstitial, window, window.Date.now, logger)
20
+ : undefined;
21
+ window.pbjs = window.pbjs || { que: [] };
22
+ window.googletag = window.googletag || {};
23
+ window.googletag.cmd = window.googletag.cmd || [];
24
+ if (config.biddersDisabling?.enabled ||
25
+ config.previousBidCpms?.enabled ||
26
+ config.frequencyCap?.enabled ||
27
+ config.interstitial?.enabled) {
28
+ window.pbjs.que.push(() => {
29
+ window.pbjs.onEvent('auctionEnd', auction => {
30
+ biddersDisabling?.onAuctionEnd(auction);
31
+ interstitial?.onAuctionEnd(auction);
32
+ if (config.previousBidCpms?.enabled && auction.bidsReceived) {
33
+ previousBidCpms?.onAuctionEnd(auction.bidsReceived);
34
+ }
35
+ frequencyCapping?.onAuctionEnd(auction);
36
+ });
37
+ });
38
+ }
39
+ if (config.adRequestThrottling?.enabled || config.frequencyCap?.enabled) {
40
+ window.googletag.cmd.push(() => {
41
+ window.googletag.pubads().addEventListener('slotRequested', event => {
42
+ adRequestThrottling?.onSlotRequested(event);
43
+ frequencyCapping?.onSlotRequested(event);
44
+ });
45
+ });
46
+ }
47
+ if (config.frequencyCap?.enabled) {
48
+ window.pbjs.que.push(() => {
49
+ window.pbjs.onEvent('bidWon', bid => {
50
+ if (config.frequencyCap) {
51
+ frequencyCapping?.onBidWon(bid);
52
+ }
53
+ });
54
+ });
55
+ eventService.addEventListener('beforeRequestAds', () => {
56
+ frequencyCapping?.beforeRequestAds();
57
+ });
58
+ eventService.addEventListener('afterRequestAds', () => {
59
+ frequencyCapping?.afterRequestAds();
60
+ });
61
+ }
62
+ if (config.frequencyCap?.enabled || config.interstitial?.enabled) {
63
+ window.googletag.cmd.push(() => {
64
+ window.googletag.pubads().addEventListener('slotRenderEnded', event => {
65
+ frequencyCapping?.onSlotRenderEnded(event);
66
+ interstitial?.onSlotRenderEnded(event);
67
+ });
68
+ window.googletag.pubads().addEventListener('impressionViewable', event => {
69
+ frequencyCapping?.onImpressionViewable(event);
70
+ });
71
+ });
72
+ }
73
+ const configureStep = mkConfigureStep('GlobalAuctionContext', context => {
74
+ frequencyCapping?.updateAdUnitPaths(context.adUnitPathVariables__);
75
+ return Promise.resolve();
76
+ });
77
+ return {
78
+ isSlotThrottled(slot) {
79
+ return !!(adRequestThrottling?.isThrottled(slot.getSlotElementId()) ||
80
+ frequencyCapping?.isAdUnitCapped(slot));
81
+ },
82
+ isBidderFrequencyCappedOnSlot(slotId, bidder) {
83
+ return frequencyCapping?.isBidderCapped(slotId, bidder) ?? false;
84
+ },
85
+ getLastBidCpmsOfAdUnit(slotId) {
86
+ return previousBidCpms?.getLastBidCpms(slotId) ?? [];
87
+ },
88
+ isBidderDisabled(domId, bidder) {
89
+ return biddersDisabling?.isBidderDisabled(domId, bidder) ?? false;
90
+ },
91
+ interstitialChannel: () => {
92
+ return interstitial?.interstitialChannel();
93
+ },
94
+ configureStep() {
95
+ return configureStep;
96
+ }
97
+ };
98
+ };