prebid.js 7.29.0 → 7.31.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.
Files changed (173) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/adkernelBidAdapter.js +1 -1
  7. package/dist/adrelevantisBidAdapter.js +1 -1
  8. package/dist/adtrgtmeBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/ajaBidAdapter.js +1 -1
  11. package/dist/amxBidAdapter.js +1 -1
  12. package/dist/amxIdSystem.js +1 -1
  13. package/dist/appierAnalyticsAdapter.js +1 -1
  14. package/dist/appnexusBidAdapter.js +1 -1
  15. package/dist/asoBidAdapter.js +1 -1
  16. package/dist/axonixBidAdapter.js +1 -1
  17. package/dist/bidViewability.js +1 -1
  18. package/dist/bidglassBidAdapter.js +1 -1
  19. package/dist/big-richmediaBidAdapter.js +1 -1
  20. package/dist/bridgewellBidAdapter.js +1 -1
  21. package/dist/brightMountainMediaBidAdapter.js +1 -1
  22. package/dist/byDataAnalyticsAdapter.js +1 -1
  23. package/dist/carodaBidAdapter.js +1 -1
  24. package/dist/ccxBidAdapter.js +1 -1
  25. package/dist/chtnwBidAdapter.js +1 -1
  26. package/dist/colossussspBidAdapter.js +1 -1
  27. package/dist/concertBidAdapter.js +1 -1
  28. package/dist/confiantRtdProvider.js +1 -0
  29. package/dist/connectadBidAdapter.js +1 -1
  30. package/dist/consentManagement.js +1 -1
  31. package/dist/consentManagementGpp.js +1 -0
  32. package/dist/consumableBidAdapter.js +1 -1
  33. package/dist/conversantBidAdapter.js +1 -1
  34. package/dist/craftBidAdapter.js +1 -1
  35. package/dist/criteoBidAdapter.js +1 -1
  36. package/dist/datawrkzBidAdapter.js +1 -1
  37. package/dist/dfpAdServerVideo.js +1 -1
  38. package/dist/dspxBidAdapter.js +1 -1
  39. package/dist/eplanningBidAdapter.js +1 -1
  40. package/dist/feedadBidAdapter.js +1 -1
  41. package/dist/finativeBidAdapter.js +1 -1
  42. package/dist/glimpseBidAdapter.js +1 -1
  43. package/dist/gmosspBidAdapter.js +1 -1
  44. package/dist/goldbachBidAdapter.js +1 -1
  45. package/dist/gridBidAdapter.js +1 -1
  46. package/dist/gridNMBidAdapter.js +1 -1
  47. package/dist/gumgumBidAdapter.js +1 -1
  48. package/dist/h12mediaBidAdapter.js +1 -1
  49. package/dist/id5IdSystem.js +1 -1
  50. package/dist/improvedigitalBidAdapter.js +1 -1
  51. package/dist/inmarBidAdapter.js +1 -1
  52. package/dist/insticatorBidAdapter.js +1 -1
  53. package/dist/ixBidAdapter.js +1 -1
  54. package/dist/justpremiumBidAdapter.js +1 -1
  55. package/dist/konduitAnalyticsAdapter.js +1 -1
  56. package/dist/kueezBidAdapter.js +1 -1
  57. package/dist/kueezRtbBidAdapter.js +1 -1
  58. package/dist/lassoBidAdapter.js +1 -1
  59. package/dist/lifestreetBidAdapter.js +1 -1
  60. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  61. package/dist/logicadBidAdapter.js +1 -1
  62. package/dist/loglyliftBidAdapter.js +1 -1
  63. package/dist/magniteAnalyticsAdapter.js +1 -1
  64. package/dist/malltvAnalyticsAdapter.js +1 -1
  65. package/dist/marsmediaBidAdapter.js +1 -1
  66. package/dist/mediafuseBidAdapter.js +1 -1
  67. package/dist/mediasquareBidAdapter.js +1 -1
  68. package/dist/mgidBidAdapter.js +1 -1
  69. package/dist/minutemediaBidAdapter.js +1 -1
  70. package/dist/nexx360BidAdapter.js +1 -1
  71. package/dist/not-for-prod/prebid.js +127 -124
  72. package/dist/oguryBidAdapter.js +1 -1
  73. package/dist/onetagBidAdapter.js +1 -1
  74. package/dist/ooloAnalyticsAdapter.js +1 -1
  75. package/dist/outbrainBidAdapter.js +1 -1
  76. package/dist/parrableIdSystem.js +1 -1
  77. package/dist/pbsExtensions.js +1 -1
  78. package/dist/pixfutureBidAdapter.js +1 -1
  79. package/dist/prebid-core.js +1 -1
  80. package/dist/prebidServerBidAdapter.js +1 -1
  81. package/dist/publinkIdSystem.js +1 -1
  82. package/dist/pubmaticBidAdapter.js +1 -1
  83. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  84. package/dist/pxyzBidAdapter.js +1 -1
  85. package/dist/quantcastBidAdapter.js +1 -1
  86. package/dist/readpeakBidAdapter.js +1 -1
  87. package/dist/relaidoBidAdapter.js +1 -1
  88. package/dist/rhythmoneBidAdapter.js +1 -1
  89. package/dist/riseBidAdapter.js +1 -1
  90. package/dist/rtdModule.js +1 -1
  91. package/dist/rubiconAnalyticsAdapter.js +1 -1
  92. package/dist/rubiconBidAdapter.js +1 -1
  93. package/dist/seedingAllianceBidAdapter.js +1 -1
  94. package/dist/seedtagBidAdapter.js +1 -1
  95. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  96. package/dist/sharethroughBidAdapter.js +1 -1
  97. package/dist/shinezBidAdapter.js +1 -1
  98. package/dist/smaatoBidAdapter.js +1 -1
  99. package/dist/smartadserverBidAdapter.js +1 -1
  100. package/dist/smartxBidAdapter.js +1 -1
  101. package/dist/smilewantedBidAdapter.js +1 -1
  102. package/dist/sonobiBidAdapter.js +1 -1
  103. package/dist/sovrnAnalyticsAdapter.js +1 -1
  104. package/dist/sovrnBidAdapter.js +1 -1
  105. package/dist/sspBCBidAdapter.js +1 -1
  106. package/dist/sublimeBidAdapter.js +1 -1
  107. package/dist/synacormediaBidAdapter.js +1 -1
  108. package/dist/targetVideoBidAdapter.js +1 -1
  109. package/dist/teadsBidAdapter.js +1 -1
  110. package/dist/trionBidAdapter.js +1 -1
  111. package/dist/tripleliftBidAdapter.js +1 -1
  112. package/dist/ttdBidAdapter.js +1 -1
  113. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  114. package/dist/uid2IdSystem.js +1 -1
  115. package/dist/underdogmediaBidAdapter.js +1 -1
  116. package/dist/undertoneBidAdapter.js +1 -1
  117. package/dist/vidazooBidAdapter.js +1 -1
  118. package/dist/videobyteBidAdapter.js +1 -1
  119. package/dist/viouslyBidAdapter.js +1 -0
  120. package/dist/visxBidAdapter.js +1 -1
  121. package/dist/vuukleBidAdapter.js +1 -1
  122. package/dist/widespaceBidAdapter.js +1 -1
  123. package/dist/winrBidAdapter.js +1 -1
  124. package/dist/yahoosspBidAdapter.js +1 -1
  125. package/dist/yieldmoBidAdapter.js +1 -1
  126. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  127. package/integrationExamples/gpt/gpp_us_hello_world.html +124 -0
  128. package/integrationExamples/gpt/gpp_us_hello_world_iframe.html +12 -0
  129. package/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html +140 -0
  130. package/karma.conf.maker.js +1 -1
  131. package/libraries/pbsExtensions/processors/adUnitCode.js +13 -0
  132. package/libraries/pbsExtensions/processors/pbs.js +5 -0
  133. package/modules/.submodules.json +1 -0
  134. package/modules/adkernelBidAdapter.js +2 -1
  135. package/modules/appnexusBidAdapter.js +23 -2
  136. package/modules/bidViewability.js +6 -1
  137. package/modules/ccxBidAdapter.js +3 -2
  138. package/modules/colossussspBidAdapter.js +8 -0
  139. package/modules/confiantRtdProvider.js +128 -0
  140. package/modules/confiantRtdProvider.md +45 -0
  141. package/modules/consentManagement.js +4 -4
  142. package/modules/consentManagementGpp.js +386 -0
  143. package/modules/datawrkzBidAdapter.js +24 -4
  144. package/modules/dfpAdServerVideo.js +6 -1
  145. package/modules/feedadBidAdapter.js +11 -3
  146. package/modules/gridBidAdapter.js +1 -2
  147. package/modules/lassoBidAdapter.js +2 -2
  148. package/modules/magniteAnalyticsAdapter.js +9 -1
  149. package/modules/onetagBidAdapter.js +20 -29
  150. package/modules/prebidServerBidAdapter/index.js +19 -8
  151. package/modules/prebidServerBidAdapter/ortbConverter.js +1 -0
  152. package/modules/rtdModule/index.js +2 -1
  153. package/modules/viouslyBidAdapter.js +209 -0
  154. package/modules/viouslyBidAdapter.md +35 -0
  155. package/package.json +1 -1
  156. package/src/adapterManager.js +11 -10
  157. package/src/adapters/bidderFactory.js +5 -5
  158. package/src/adloader.js +2 -1
  159. package/src/consentHandler.js +11 -0
  160. package/src/prebid.js +9 -9
  161. package/test/helpers/hookSetup.js +5 -0
  162. package/test/spec/modules/ViouslyBidAdapter_spec.js +378 -0
  163. package/test/spec/modules/appnexusBidAdapter_spec.js +46 -0
  164. package/test/spec/modules/colossussspBidAdapter_spec.js +89 -2
  165. package/test/spec/modules/confiantRtdProvider_spec.js +107 -0
  166. package/test/spec/modules/consentManagementGpp_spec.js +577 -0
  167. package/test/spec/modules/feedadBidAdapter_spec.js +38 -13
  168. package/test/spec/modules/gridBidAdapter_spec.js +0 -18
  169. package/test/spec/modules/magniteAnalyticsAdapter_spec.js +36 -14
  170. package/test/spec/modules/onetagBidAdapter_spec.js +29 -23
  171. package/test/spec/modules/topicsFpdModule_spec.js +41 -22
  172. package/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js +23 -0
  173. package/test/spec/unit/pbjs_api_spec.js +11 -0
@@ -87,6 +87,11 @@ export const spec = {
87
87
  logMessage(e);
88
88
  }
89
89
 
90
+ const firstPartyData = bidderRequest.ortb2 || {};
91
+ const userObj = firstPartyData.user;
92
+ const siteObj = firstPartyData.site;
93
+ const appObj = firstPartyData.app;
94
+
90
95
  // TODO: does the fallback to window.location make sense?
91
96
  const location = refferLocation || winLocation;
92
97
  let placements = [];
@@ -97,6 +102,9 @@ export const spec = {
97
102
  secure: location.protocol === 'https:' ? 1 : 0,
98
103
  host: location.host,
99
104
  page: location.pathname,
105
+ userObj,
106
+ siteObj,
107
+ appObj,
100
108
  placements: placements
101
109
  };
102
110
 
@@ -0,0 +1,128 @@
1
+ /**
2
+ * This module provides comprehensive detection of security, quality, and privacy threats by Confiant Inc,
3
+ * the industry leader in real-time detecting and blocking of bad ads
4
+ *
5
+ * The {@link module:modules/realTimeData} module is required
6
+ * The module will inject a Confiant Inc. script into the page to monitor ad impressions
7
+ * @module modules/cleanioRtdProvider
8
+ * @requires module:modules/realTimeData
9
+ */
10
+
11
+ import { submodule } from '../src/hook.js';
12
+ import { logError, generateUUID } from '../src/utils.js';
13
+ import { loadExternalScript } from '../src/adloader.js';
14
+ import * as events from '../src/events.js';
15
+ import CONSTANTS from '../src/constants.json';
16
+
17
+ /**
18
+ * Injects the Confiant Inc. configuration script into the page, based on proprtyId provided
19
+ * @param {string} propertyId
20
+ */
21
+ function injectConfigScript(propertyId) {
22
+ const scriptSrc = `https://cdn.confiant-integrations.net/${propertyId}/gpt_and_prebid/config.js`;
23
+
24
+ loadExternalScript(scriptSrc, 'confiant', () => {});
25
+ }
26
+
27
+ /**
28
+ * Set up page with Confiant integration
29
+ * @param {Object} config
30
+ */
31
+ function setupPage(config) {
32
+ const propertyId = config?.params?.propertyId;
33
+ if (!propertyId) {
34
+ logError('Confiant pbjs module: no propertyId provided');
35
+ return false;
36
+ }
37
+
38
+ const confiant = window.confiant || Object.create(null);
39
+ confiant[propertyId] = confiant[propertyId] || Object.create(null);
40
+ confiant[propertyId].clientSettings = confiant[propertyId].clientSettings || Object.create(null);
41
+ confiant[propertyId].clientSettings.isMGBL = true;
42
+ confiant[propertyId].clientSettings.prebidExcludeBidders = config?.params?.prebidExcludeBidders;
43
+ confiant[propertyId].clientSettings.prebidNameSpace = config?.params?.prebidNameSpace;
44
+
45
+ if (config?.params?.shouldEmitBillableEvent) {
46
+ if (window.frames['cnftComm']) {
47
+ subscribeToConfiantCommFrame(window);
48
+ } else {
49
+ setUpMutationObserver();
50
+ }
51
+ }
52
+
53
+ injectConfigScript(propertyId);
54
+ return true;
55
+ }
56
+
57
+ /**
58
+ * Subscribe to window's message events to report Billable events
59
+ * @param {Window} targetWindow window instance to subscribe to
60
+ */
61
+ function subscribeToConfiantCommFrame(targetWindow) {
62
+ targetWindow.addEventListener('message', reportBillableEvents);
63
+ }
64
+
65
+ let mutationObserver;
66
+ /**
67
+ * Set up mutation observer to subscribe to Confiant's communication channel ASAP
68
+ */
69
+ function setUpMutationObserver() {
70
+ mutationObserver = new MutationObserver((mutations) => {
71
+ mutations.forEach((mutation) => {
72
+ mutation.addedNodes.forEach((addedNode) => {
73
+ if (addedNode.nodeName === 'IFRAME' && addedNode.name === 'cnftComm' && !addedNode.pbjsModuleSubscribed) {
74
+ addedNode.pbjsModuleSubscribed = true;
75
+ mutationObserver.disconnect();
76
+ mutationObserver = null;
77
+ const iframeWindow = addedNode.contentWindow;
78
+ subscribeToConfiantCommFrame(iframeWindow);
79
+ }
80
+ });
81
+ });
82
+ });
83
+ mutationObserver.observe(document.head, { childList: true, subtree: true });
84
+ }
85
+
86
+ /**
87
+ * Emit billable event when Confiant integration reports that it has monitored an impression
88
+ */
89
+ function reportBillableEvents (e) {
90
+ events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, {
91
+ auctionId: e.data.auctionId,
92
+ billingId: generateUUID(),
93
+ transactionId: e.data.transactionId,
94
+ type: 'impression',
95
+ vendor: 'confiant'
96
+ });
97
+ }
98
+
99
+ /**
100
+ * Confiant submodule registration
101
+ */
102
+ function registerConfiantSubmodule() {
103
+ submodule('realTimeData', {
104
+ name: 'confiant',
105
+ init: (config) => {
106
+ try {
107
+ return setupPage(config);
108
+ } catch (err) {
109
+ logError(err.message);
110
+ if (mutationObserver) {
111
+ mutationObserver.disconnect();
112
+ }
113
+ return false;
114
+ }
115
+ }
116
+ });
117
+ }
118
+
119
+ registerConfiantSubmodule();
120
+
121
+ export default {
122
+ injectConfigScript,
123
+ setupPage,
124
+ subscribeToConfiantCommFrame,
125
+ setUpMutationObserver,
126
+ reportBillableEvents,
127
+ registerConfiantSubmodule
128
+ };
@@ -0,0 +1,45 @@
1
+ # Overview
2
+
3
+ ```
4
+ Module Name: Confiant Inc. Rtd provider
5
+ Module Type: Rtd Provider
6
+ Maintainer:
7
+ ```
8
+
9
+ Confiant’s module provides comprehensive detection of security, quality, and privacy threats across your ad stack.
10
+ Confiant is the industry leader in real-time detecting and blocking of bad ads when it comes to protecting your users and brand reputation.
11
+
12
+ To start using this module, please contact [Confiant](https://www.confiant.com/contact) to get an account and customer key.
13
+
14
+
15
+ # Integration
16
+
17
+ 1) Build Prebid bundle with Confiant module included:
18
+
19
+
20
+ ```
21
+ gulp build --modules=confiantRtdProvider,...
22
+ ```
23
+
24
+ 2) Include the resulting bundle on your page.
25
+
26
+ # Configuration
27
+
28
+ Configuration of Confiant module is plain simple:
29
+
30
+ ```javascript
31
+ pbjs.setConfig({
32
+ realTimeData: {
33
+ dataProviders: [{
34
+ name: 'confiant',
35
+ params: {
36
+ // so please get in touch with us so we could help you to set up the module with proper parameters
37
+ propertyId: '', // required, string param, obtained from Confiant Inc.
38
+ prebidExcludeBidders: '', // optional, comma separated list of bidders to exclude from Confiant's prebid.js integration
39
+ prebidNameSpace: '', // optional, string param, namespace for prebid.js integration
40
+ shouldEmitBillableEvent: false, // optional, boolean param, upon being set to true enables firing of the BillableEvent upon Confiant's impression scanning
41
+ }
42
+ }]
43
+ }
44
+ });
45
+ ```
@@ -94,7 +94,7 @@ function lookupIabConsent({onSuccess, onError}) {
94
94
  const { cmpFrame, cmpFunction } = findCMP();
95
95
 
96
96
  if (!cmpFrame) {
97
- return onError('CMP not found.');
97
+ return onError('TCF2 CMP not found.');
98
98
  }
99
99
  // to collect the consent information from the user, we perform two calls to the CMP in parallel:
100
100
  // first to collect the user's consent choices represented in an encoded string (via getConsentData)
@@ -314,11 +314,11 @@ export function resetConsentData() {
314
314
  * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean)
315
315
  */
316
316
  export function setConsentConfig(config) {
317
- // if `config.gdpr` or `config.usp` exist, assume new config format.
317
+ // if `config.gdpr`, `config.usp` or `config.gpp` exist, assume new config format.
318
318
  // else for backward compatability, just use `config`
319
- config = config && (config.gdpr || config.usp ? config.gdpr : config);
319
+ config = config && (config.gdpr || config.usp || config.gpp ? config.gdpr : config);
320
320
  if (!config || typeof config !== 'object') {
321
- logWarn('consentManagement config not defined, exiting consent manager');
321
+ logWarn('consentManagement (gdpr) config not defined, exiting consent manager');
322
322
  return;
323
323
  }
324
324
  if (isStr(config.cmpApi)) {
@@ -0,0 +1,386 @@
1
+ /**
2
+ * This module adds GPP consentManagement support to prebid.js. It interacts with
3
+ * supported CMPs (Consent Management Platforms) to grab the user's consent information
4
+ * and make it available for any GPP supported adapters to read/pass this information to
5
+ * their system and for various other features/modules in Prebid.js.
6
+ */
7
+ import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
8
+ import {config} from '../src/config.js';
9
+ import {gppDataHandler} from '../src/adapterManager.js';
10
+ import {includes} from '../src/polyfill.js';
11
+ import {timedAuctionHook} from '../src/utils/perfMetrics.js';
12
+ import { enrichFPD } from '../src/fpd/enrichment.js';
13
+
14
+ const DEFAULT_CMP = 'iab';
15
+ const DEFAULT_CONSENT_TIMEOUT = 10000;
16
+ const CMP_VERSION = 1;
17
+
18
+ export let userCMP;
19
+ export let consentTimeout;
20
+ export let staticConsentData;
21
+
22
+ let consentData;
23
+ let addedConsentHook = false;
24
+
25
+ // add new CMPs here, with their dedicated lookup function
26
+ const cmpCallMap = {
27
+ 'iab': lookupIabConsent,
28
+ 'static': lookupStaticConsentData
29
+ };
30
+
31
+ /**
32
+ * This function checks the state of the IAB gppData's applicableSection field (to ensure it's populated and has a valid value).
33
+ * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section.
34
+ *
35
+ * TODO --- The initial version of the GPP CMP API spec used this naming convention, but it was later changed as an update to the spec.
36
+ * CMPs should adjust their logic to use the new format (applicableSecctions), but that may not be the case with the initial release.
37
+ * Added support just in case for this transition period, can likely be removed at a later date...
38
+ * @param gppData represents the IAB gppData object
39
+ * @returns true|false
40
+ */
41
+ function checkApplicableSectionIsReady(gppData) {
42
+ return gppData && Array.isArray(gppData.applicableSection) && gppData.applicableSection.length > 0 && gppData.applicableSection[0] !== 0;
43
+ }
44
+
45
+ /**
46
+ * This function checks the state of the IAB gppData's applicableSections field (to ensure it's populated and has a valid value).
47
+ * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section.
48
+ * @param gppData represents the IAB gppData object
49
+ * @returns true|false
50
+ */
51
+ function checkApplicableSectionsIsReady(gppData) {
52
+ return gppData && Array.isArray(gppData.applicableSections) && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== 0;
53
+ }
54
+
55
+ /**
56
+ * This function reads the consent string from the config to obtain the consent information of the user.
57
+ * @param {function({})} onSuccess acts as a success callback when the value is read from config; pass along consentObject from CMP
58
+ */
59
+ function lookupStaticConsentData({onSuccess, onError}) {
60
+ processCmpData(staticConsentData, {onSuccess, onError});
61
+ }
62
+
63
+ /**
64
+ * This function handles interacting with an IAB compliant CMP to obtain the consent information of the user.
65
+ * Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function
66
+ * based on the appropriate result.
67
+ * @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP
68
+ * @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging)
69
+ */
70
+ function lookupIabConsent({onSuccess, onError}) {
71
+ const cmpApiName = '__gpp';
72
+ const cmpCallbacks = {};
73
+ let registeredPostMessageResponseListener = false;
74
+
75
+ function findCMP() {
76
+ let f = window;
77
+ let cmpFrame;
78
+ let cmpDirectAccess = false;
79
+ while (true) {
80
+ try {
81
+ if (typeof f[cmpApiName] === 'function') {
82
+ cmpFrame = f;
83
+ cmpDirectAccess = true;
84
+ break;
85
+ }
86
+ } catch (e) {}
87
+
88
+ // need separate try/catch blocks due to the exception errors thrown when trying to check for a frame that doesn't exist in 3rd party env
89
+ try {
90
+ if (f.frames['__gppLocator']) {
91
+ cmpFrame = f;
92
+ break;
93
+ }
94
+ } catch (e) {}
95
+
96
+ if (f === window.top) break;
97
+ f = f.parent;
98
+ }
99
+
100
+ return {
101
+ cmpFrame,
102
+ cmpDirectAccess
103
+ };
104
+ }
105
+
106
+ const {cmpFrame, cmpDirectAccess} = findCMP();
107
+
108
+ if (!cmpFrame) {
109
+ return onError('GPP CMP not found.');
110
+ }
111
+
112
+ const invokeCMP = (cmpDirectAccess) ? invokeCMPDirect : invokeCMPFrame;
113
+
114
+ function invokeCMPDirect({command, callback, parameter, version = CMP_VERSION}, resultCb) {
115
+ if (typeof resultCb === 'function') {
116
+ resultCb(cmpFrame[cmpApiName](command, callback, parameter, version));
117
+ } else {
118
+ cmpFrame[cmpApiName](command, callback, parameter, version);
119
+ }
120
+ }
121
+
122
+ function invokeCMPFrame({command, callback, parameter, version = CMP_VERSION}, resultCb) {
123
+ const callName = `${cmpApiName}Call`;
124
+ if (!registeredPostMessageResponseListener) {
125
+ // when we get the return message, call the stashed callback;
126
+ window.addEventListener('message', readPostMessageResponse, false);
127
+ registeredPostMessageResponseListener = true;
128
+ }
129
+
130
+ // call CMP via postMessage
131
+ const callId = Math.random().toString();
132
+ const msg = {
133
+ [callName]: {
134
+ command: command,
135
+ parameter,
136
+ version,
137
+ callId: callId
138
+ }
139
+ };
140
+
141
+ // TODO? - add logic to check if random was already used in the same session, and roll another if so?
142
+ cmpCallbacks[callId] = (typeof callback === 'function') ? callback : resultCb;
143
+ cmpFrame.postMessage(msg, '*');
144
+
145
+ function readPostMessageResponse(event) {
146
+ const cmpDataPkgName = `${cmpApiName}Return`;
147
+ const json = (typeof event.data === 'string' && event.data.includes(cmpDataPkgName)) ? JSON.parse(event.data) : event.data;
148
+ if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) {
149
+ const payload = json[cmpDataPkgName];
150
+
151
+ if (cmpCallbacks.hasOwnProperty(payload.callId)) {
152
+ cmpCallbacks[payload.callId](payload.returnValue);
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ const startupMsg = (cmpDirectAccess) ? 'Detected GPP CMP API is directly accessible, calling it now...'
159
+ : 'Detected GPP CMP is outside the current iframe where Prebid.js is located, calling it now...';
160
+ logInfo(startupMsg);
161
+
162
+ invokeCMP({
163
+ command: 'addEventListener',
164
+ callback: function (evt) {
165
+ if (evt) {
166
+ logInfo(`Received a ${(cmpDirectAccess ? 'direct' : 'postmsg')} response from GPP CMP for event`, evt);
167
+ if (evt.eventName === 'sectionChange' || evt.pingData.cmpStatus === 'loaded') {
168
+ invokeCMP({command: 'getGPPData'}, function (gppData) {
169
+ logInfo(`Received a ${cmpDirectAccess ? 'direct' : 'postmsg'} response from GPP CMP for getGPPData`, gppData);
170
+ processCmpData(gppData, {onSuccess, onError});
171
+ });
172
+ } else if (evt.pingData.cmpStatus === 'error') {
173
+ onError('CMP returned with a cmpStatus:error response. Please check CMP setup.');
174
+ }
175
+ }
176
+ }
177
+ });
178
+ }
179
+
180
+ /**
181
+ * Look up consent data and store it in the `consentData` global as well as `adapterManager.js`' gdprDataHandler.
182
+ *
183
+ * @param cb A callback that takes: a boolean that is true if the auction should be canceled; an error message and extra
184
+ * error arguments that will be undefined if there's no error.
185
+ */
186
+ function loadConsentData(cb) {
187
+ let isDone = false;
188
+ let timer = null;
189
+
190
+ function done(consentData, shouldCancelAuction, errMsg, ...extraArgs) {
191
+ if (timer != null) {
192
+ clearTimeout(timer);
193
+ }
194
+ isDone = true;
195
+ gppDataHandler.setConsentData(consentData);
196
+ if (typeof cb === 'function') {
197
+ cb(shouldCancelAuction, errMsg, ...extraArgs);
198
+ }
199
+ }
200
+
201
+ if (!includes(Object.keys(cmpCallMap), userCMP)) {
202
+ done(null, false, `GPP CMP framework (${userCMP}) is not a supported framework. Aborting consentManagement module and resuming auction.`);
203
+ return;
204
+ }
205
+
206
+ const callbacks = {
207
+ onSuccess: (data) => done(data, false),
208
+ onError: function (msg, ...extraArgs) {
209
+ done(null, true, msg, ...extraArgs);
210
+ }
211
+ }
212
+ cmpCallMap[userCMP](callbacks);
213
+
214
+ if (!isDone) {
215
+ const onTimeout = () => {
216
+ const continueToAuction = (data) => {
217
+ done(data, false, 'GPP CMP did not load, continuing auction...');
218
+ }
219
+ processCmpData(consentData, {
220
+ onSuccess: continueToAuction,
221
+ onError: () => continueToAuction(storeConsentData(undefined))
222
+ })
223
+ }
224
+ if (consentTimeout === 0) {
225
+ onTimeout();
226
+ } else {
227
+ timer = setTimeout(onTimeout, consentTimeout);
228
+ }
229
+ }
230
+ }
231
+
232
+ /**
233
+ * Like `loadConsentData`, but cache and re-use previously loaded data.
234
+ * @param cb
235
+ */
236
+ function loadIfMissing(cb) {
237
+ if (consentData) {
238
+ logInfo('User consent information already known. Pulling internally stored information...');
239
+ // eslint-disable-next-line standard/no-callback-literal
240
+ cb(false);
241
+ } else {
242
+ loadConsentData(cb);
243
+ }
244
+ }
245
+
246
+ /**
247
+ * If consentManagement module is enabled (ie included in setConfig), this hook function will attempt to fetch the
248
+ * user's encoded consent string from the supported CMP. Once obtained, the module will store this
249
+ * data as part of a gppConsent object which gets transferred to adapterManager's gppDataHandler object.
250
+ * This information is later added into the bidRequest object for any supported adapters to read/pass along to their system.
251
+ * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
252
+ * @param {function} fn required; The next function in the chain, used by hook.js
253
+ */
254
+ export const requestBidsHook = timedAuctionHook('gpp', function requestBidsHook(fn, reqBidsConfigObj) {
255
+ loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) {
256
+ if (errMsg) {
257
+ let log = logWarn;
258
+ if (shouldCancelAuction) {
259
+ log = logError;
260
+ errMsg = `${errMsg} Canceling auction as per consentManagement config.`;
261
+ }
262
+ log(errMsg, ...extraArgs);
263
+ }
264
+
265
+ if (shouldCancelAuction) {
266
+ fn.stopTiming();
267
+ if (typeof reqBidsConfigObj.bidsBackHandler === 'function') {
268
+ reqBidsConfigObj.bidsBackHandler();
269
+ } else {
270
+ logError('Error executing bidsBackHandler');
271
+ }
272
+ } else {
273
+ fn.call(this, reqBidsConfigObj);
274
+ }
275
+ });
276
+ });
277
+
278
+ /**
279
+ * This function checks the consent data provided by CMP to ensure it's in an expected state.
280
+ * If it's bad, we call `onError`
281
+ * If it's good, then we store the value and call `onSuccess`
282
+ */
283
+ function processCmpData(consentObject, {onSuccess, onError}) {
284
+ function checkData() {
285
+ const gppString = consentObject && consentObject.gppString;
286
+ const gppSection = (checkApplicableSectionsIsReady(consentObject)) ? consentObject.applicableSections
287
+ : (checkApplicableSectionIsReady(consentObject)) ? consentObject.applicableSection : [];
288
+
289
+ return !!(
290
+ (!Array.isArray(gppSection)) ||
291
+ (Array.isArray(gppSection) && (!gppString || !isStr(gppString)))
292
+ );
293
+ }
294
+
295
+ if (checkData()) {
296
+ onError(`CMP returned unexpected value during lookup process.`, consentObject);
297
+ } else {
298
+ onSuccess(storeConsentData(consentObject));
299
+ }
300
+ }
301
+
302
+ /**
303
+ * Stores CMP data locally in module to make information available in adaptermanager.js for later in the auction
304
+ * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only)
305
+ */
306
+ function storeConsentData(cmpConsentObject) {
307
+ consentData = {
308
+ gppString: (cmpConsentObject) ? cmpConsentObject.gppString : undefined,
309
+
310
+ fullGppData: (cmpConsentObject) || undefined,
311
+ };
312
+ consentData.applicableSections = (checkApplicableSectionsIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSections
313
+ : (checkApplicableSectionIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSection : [];
314
+ consentData.apiVersion = CMP_VERSION;
315
+ return consentData;
316
+ }
317
+
318
+ /**
319
+ * Simply resets the module's consentData variable back to undefined, mainly for testing purposes
320
+ */
321
+ export function resetConsentData() {
322
+ consentData = undefined;
323
+ userCMP = undefined;
324
+ consentTimeout = undefined;
325
+ gppDataHandler.reset();
326
+ }
327
+
328
+ /**
329
+ * A configuration function that initializes some module variables, as well as add a hook into the requestBids function
330
+ * @param {{cmp:string, timeout:number, allowAuctionWithoutConsent:boolean, defaultGdprScope:boolean}} config required; consentManagement module config settings; cmp (string), timeout (int), allowAuctionWithoutConsent (boolean)
331
+ */
332
+ export function setConsentConfig(config) {
333
+ config = config && config.gpp;
334
+ if (!config || typeof config !== 'object') {
335
+ logWarn('consentManagement.gpp config not defined, exiting consent manager module');
336
+ return;
337
+ }
338
+
339
+ if (isStr(config.cmpApi)) {
340
+ userCMP = config.cmpApi;
341
+ } else {
342
+ userCMP = DEFAULT_CMP;
343
+ logInfo(`consentManagement.gpp config did not specify cmp. Using system default setting (${DEFAULT_CMP}).`);
344
+ }
345
+
346
+ if (isNumber(config.timeout)) {
347
+ consentTimeout = config.timeout;
348
+ } else {
349
+ consentTimeout = DEFAULT_CONSENT_TIMEOUT;
350
+ logInfo(`consentManagement.gpp config did not specify timeout. Using system default setting (${DEFAULT_CONSENT_TIMEOUT}).`);
351
+ }
352
+
353
+ if (userCMP === 'static') {
354
+ if (isPlainObject(config.consentData)) {
355
+ staticConsentData = config.consentData;
356
+ consentTimeout = 0;
357
+ } else {
358
+ logError(`consentManagement.gpp config with cmpApi: 'static' did not specify consentData. No consents will be available to adapters.`);
359
+ }
360
+ }
361
+
362
+ logInfo('consentManagement.gpp module has been activated...');
363
+
364
+ if (!addedConsentHook) {
365
+ $$PREBID_GLOBAL$$.requestBids.before(requestBidsHook, 50);
366
+ }
367
+ addedConsentHook = true;
368
+ gppDataHandler.enable();
369
+ loadConsentData(); // immediately look up consent data to make it available without requiring an auction
370
+ }
371
+ config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement));
372
+
373
+ export function enrichFPDHook(next, fpd) {
374
+ return next(fpd.then(ortb2 => {
375
+ const consent = gppDataHandler.getConsentData();
376
+ if (consent) {
377
+ if (Array.isArray(consent.applicableSections)) {
378
+ deepSetValue(ortb2, 'regs.gpp_sid', consent.applicableSections);
379
+ }
380
+ deepSetValue(ortb2, 'regs.gpp', consent.gppString);
381
+ }
382
+ return ortb2;
383
+ }));
384
+ }
385
+
386
+ enrichFPD.before(enrichFPDHook);
@@ -1,4 +1,4 @@
1
- import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains } from '../src/utils.js';
1
+ import { deepAccess, getBidIdParameter, isArray, getUniqueIdentifierStr, contains, isFn, isPlainObject } from '../src/utils.js';
2
2
  import { config } from '../src/config.js';
3
3
  import { Renderer } from '../src/Renderer.js';
4
4
  import { registerBidder } from '../src/adapters/bidderFactory.js';
@@ -84,7 +84,7 @@ export const spec = {
84
84
 
85
85
  /* Generate bid request for banner adunit */
86
86
  function buildBannerRequest(bidRequest, bidderRequest) {
87
- let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params));
87
+ let bidFloor = getBidFloor(bidRequest);
88
88
 
89
89
  let adW = 0;
90
90
  let adH = 0;
@@ -135,7 +135,7 @@ function buildNativeRequest(bidRequest, bidderRequest) {
135
135
  let counter = 0;
136
136
  let assets = [];
137
137
 
138
- let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params));
138
+ let bidFloor = getBidFloor(bidRequest);
139
139
 
140
140
  let title = deepAccess(bidRequest, 'mediaTypes.native.title');
141
141
  if (title && title.len) {
@@ -196,7 +196,7 @@ function buildNativeRequest(bidRequest, bidderRequest) {
196
196
 
197
197
  /* Generate bid request for video adunit */
198
198
  function buildVideoRequest(bidRequest, bidderRequest) {
199
- let bidFloor = Number(getBidIdParameter('bidfloor', bidRequest.params));
199
+ let bidFloor = getBidFloor(bidRequest);
200
200
 
201
201
  let sizeObj = getVideoAdUnitSize(bidRequest);
202
202
 
@@ -414,6 +414,7 @@ function buildBannerResponse(bidRequest, bidResponse) {
414
414
  }
415
415
  let bidSizes = (deepAccess(bidRequest, 'mediaTypes.banner.sizes')) ? deepAccess(bidRequest, 'mediaTypes.banner.sizes') : bidRequest.sizes;
416
416
  bidResponse.requestId = bidRequest.bidId;
417
+ bidResponse.auctionId = bidRequest.auctionId;
417
418
  bidResponse.transactionId = bidRequest.transactionId;
418
419
  bidResponse.placementCode = placementCode;
419
420
  bidResponse.cpm = responseCPM;
@@ -455,6 +456,7 @@ function buildNativeResponse(bidRequest, response) {
455
456
  return;
456
457
  }
457
458
  bidResponse.requestId = bidRequest.bidId;
459
+ bidResponse.auctionId = bidRequest.auctionId;
458
460
  bidResponse.transactionId = bidRequest.transactionId;
459
461
  bidResponse.placementCode = placementCode;
460
462
  bidResponse.cpm = responseCPM;
@@ -507,6 +509,7 @@ function buildVideoResponse(bidRequest, response) {
507
509
  let context = bidRequest.mediaTypes.video.context;
508
510
 
509
511
  bidResponse.requestId = bidRequest.bidId;
512
+ bidResponse.auctionId = bidRequest.auctionId;
510
513
  bidResponse.transactionId = bidRequest.transactionId;
511
514
  bidResponse.placementCode = placementCode;
512
515
  bidResponse.cpm = responseCPM;
@@ -630,4 +633,21 @@ function getNativeAssestObj(obj, assets) {
630
633
  }
631
634
  }
632
635
 
636
+ // BUILD REQUESTS: BIDFLOORS
637
+ function getBidFloor(bid) {
638
+ if (!isFn(bid.getFloor)) {
639
+ return (bid.params.bidfloor) ? bid.params.bidfloor : null;
640
+ }
641
+
642
+ let floor = bid.getFloor({
643
+ currency: 'USD',
644
+ mediaType: '*',
645
+ size: '*'
646
+ });
647
+ if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') {
648
+ return floor.floor;
649
+ }
650
+ return null;
651
+ }
652
+
633
653
  registerBidder(spec);