prebid.js 8.1.0 → 8.3.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 (214) hide show
  1. package/.devcontainer/devcontainer.json +3 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.js +1 -1
  7. package/dist/admanBidAdapter.js +1 -1
  8. package/dist/adqueryBidAdapter.js +1 -1
  9. package/dist/adrelevantisBidAdapter.js +1 -1
  10. package/dist/adtelligentBidAdapter.js +1 -1
  11. package/dist/adtrgtmeBidAdapter.js +1 -1
  12. package/dist/adxcgBidAdapter.js +1 -1
  13. package/dist/adyoulikeBidAdapter.js +1 -1
  14. package/dist/ajaBidAdapter.js +1 -1
  15. package/dist/amxBidAdapter.js +1 -1
  16. package/dist/amxIdSystem.js +1 -1
  17. package/dist/appierAnalyticsAdapter.js +1 -1
  18. package/dist/appnexusBidAdapter.js +1 -1
  19. package/dist/asoBidAdapter.js +1 -1
  20. package/dist/axonixBidAdapter.js +1 -1
  21. package/dist/beopBidAdapter.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/big-richmediaBidAdapter.js +1 -1
  24. package/dist/bridBidAdapter.js +1 -0
  25. package/dist/bridgewellBidAdapter.js +1 -1
  26. package/dist/brightMountainMediaBidAdapter.js +1 -1
  27. package/dist/carodaBidAdapter.js +1 -1
  28. package/dist/categoryTranslation.js +1 -1
  29. package/dist/chtnwBidAdapter.js +1 -1
  30. package/dist/cmp.js +1 -0
  31. package/dist/concertBidAdapter.js +1 -1
  32. package/dist/connectadBidAdapter.js +1 -1
  33. package/dist/consentManagement.js +1 -1
  34. package/dist/consentManagementGpp.js +1 -1
  35. package/dist/consentManagementUsp.js +1 -1
  36. package/dist/consumableBidAdapter.js +1 -1
  37. package/dist/conversantAnalyticsAdapter.js +1 -1
  38. package/dist/conversantBidAdapter.js +1 -1
  39. package/dist/craftBidAdapter.js +1 -1
  40. package/dist/criteoBidAdapter.js +1 -1
  41. package/dist/cwireBidAdapter.js +1 -1
  42. package/dist/dependencies.json +15 -0
  43. package/dist/discoveryBidAdapter.js +1 -1
  44. package/dist/dspxBidAdapter.js +1 -1
  45. package/dist/eplanningBidAdapter.js +1 -1
  46. package/dist/euidIdSystem.js +1 -1
  47. package/dist/feedadBidAdapter.js +1 -1
  48. package/dist/finativeBidAdapter.js +1 -1
  49. package/dist/freewheel-sspBidAdapter.js +1 -1
  50. package/dist/gmosspBidAdapter.js +1 -1
  51. package/dist/goldbachBidAdapter.js +1 -1
  52. package/dist/gppControl_usnat.js +1 -0
  53. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  54. package/dist/greenbidsRtdProvider.js +1 -1
  55. package/dist/gridBidAdapter.js +1 -1
  56. package/dist/gumgumBidAdapter.js +1 -1
  57. package/dist/h12mediaBidAdapter.js +1 -1
  58. package/dist/holidBidAdapter.js +1 -1
  59. package/dist/hypelabBidAdapter.js +1 -1
  60. package/dist/id5IdSystem.js +1 -1
  61. package/dist/imdsBidAdapter.js +1 -1
  62. package/dist/improvedigitalBidAdapter.js +1 -1
  63. package/dist/insticatorBidAdapter.js +1 -1
  64. package/dist/intentIqIdSystem.js +1 -1
  65. package/dist/ixBidAdapter.js +1 -1
  66. package/dist/justpremiumBidAdapter.js +1 -1
  67. package/dist/kargoBidAdapter.js +1 -1
  68. package/dist/konduitAnalyticsAdapter.js +1 -1
  69. package/dist/kueezBidAdapter.js +1 -1
  70. package/dist/kueezRtbBidAdapter.js +1 -1
  71. package/dist/kulturemediaBidAdapter.js +1 -1
  72. package/dist/lassoBidAdapter.js +1 -1
  73. package/dist/lifestreetBidAdapter.js +1 -1
  74. package/dist/liveIntentIdSystem.js +1 -1
  75. package/dist/livewrappedAnalyticsAdapter.js +1 -1
  76. package/dist/logicadBidAdapter.js +1 -1
  77. package/dist/loglyliftBidAdapter.js +1 -1
  78. package/dist/magniteAnalyticsAdapter.js +1 -1
  79. package/dist/malltvAnalyticsAdapter.js +1 -1
  80. package/dist/marsmediaBidAdapter.js +1 -1
  81. package/dist/mediafuseBidAdapter.js +1 -1
  82. package/dist/mediagoBidAdapter.js +1 -1
  83. package/dist/mediasquareBidAdapter.js +1 -1
  84. package/dist/mgidBidAdapter.js +1 -1
  85. package/dist/minutemediaBidAdapter.js +1 -1
  86. package/dist/minutemediaplusBidAdapter.js +1 -1
  87. package/dist/mspa.js +1 -0
  88. package/dist/nexx360BidAdapter.js +1 -1
  89. package/dist/not-for-prod/prebid.js +144 -140
  90. package/dist/oguryBidAdapter.js +1 -1
  91. package/dist/onetagBidAdapter.js +1 -1
  92. package/dist/ooloAnalyticsAdapter.js +1 -1
  93. package/dist/optidigitalBidAdapter.js +1 -1
  94. package/dist/outbrainBidAdapter.js +1 -1
  95. package/dist/oxxionRtdProvider.js +1 -1
  96. package/dist/parrableIdSystem.js +1 -1
  97. package/dist/pixfutureBidAdapter.js +1 -1
  98. package/dist/prebid-core.js +1 -1
  99. package/dist/publinkIdSystem.js +1 -1
  100. package/dist/pubmaticBidAdapter.js +1 -1
  101. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  102. package/dist/pxyzBidAdapter.js +1 -1
  103. package/dist/quantcastBidAdapter.js +1 -1
  104. package/dist/readpeakBidAdapter.js +1 -1
  105. package/dist/relaidoBidAdapter.js +1 -1
  106. package/dist/retailspotBidAdapter.js +1 -1
  107. package/dist/rhythmoneBidAdapter.js +1 -1
  108. package/dist/riseBidAdapter.js +1 -1
  109. package/dist/rubiconBidAdapter.js +1 -1
  110. package/dist/seedingAllianceBidAdapter.js +1 -1
  111. package/dist/seedtagBidAdapter.js +1 -1
  112. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  113. package/dist/sharethroughBidAdapter.js +1 -1
  114. package/dist/shinezBidAdapter.js +1 -1
  115. package/dist/smaatoBidAdapter.js +1 -1
  116. package/dist/smartadserverBidAdapter.js +1 -1
  117. package/dist/smartxBidAdapter.js +1 -1
  118. package/dist/smartyadsBidAdapter.js +1 -1
  119. package/dist/smilewantedBidAdapter.js +1 -1
  120. package/dist/sonobiBidAdapter.js +1 -1
  121. package/dist/sovrnAnalyticsAdapter.js +1 -1
  122. package/dist/sovrnBidAdapter.js +1 -1
  123. package/dist/sspBCBidAdapter.js +1 -1
  124. package/dist/stvBidAdapter.js +1 -1
  125. package/dist/sublimeBidAdapter.js +1 -1
  126. package/dist/targetVideoBidAdapter.js +1 -1
  127. package/dist/teadsBidAdapter.js +1 -1
  128. package/dist/trafficgateBidAdapter.js +1 -1
  129. package/dist/trionBidAdapter.js +1 -1
  130. package/dist/tripleliftBidAdapter.js +1 -1
  131. package/dist/ttdBidAdapter.js +1 -1
  132. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  133. package/dist/uid2IdSystem.js +1 -1
  134. package/dist/underdogmediaBidAdapter.js +1 -1
  135. package/dist/undertoneBidAdapter.js +1 -1
  136. package/dist/userId.js +1 -1
  137. package/dist/vidazooBidAdapter.js +1 -1
  138. package/dist/videobyteBidAdapter.js +1 -1
  139. package/dist/visxBidAdapter.js +1 -1
  140. package/dist/vuukleBidAdapter.js +1 -1
  141. package/dist/widespaceBidAdapter.js +1 -1
  142. package/dist/winrBidAdapter.js +1 -1
  143. package/dist/yahoosspBidAdapter.js +1 -1
  144. package/dist/yieldmoBidAdapter.js +1 -1
  145. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  146. package/libraries/cmp/cmpClient.js +139 -0
  147. package/libraries/mspa/activityControls.js +91 -0
  148. package/modules/adagioBidAdapter.js +2 -1
  149. package/modules/admanBidAdapter.js +5 -0
  150. package/modules/adtelligentBidAdapter.js +8 -0
  151. package/modules/beopBidAdapter.js +6 -6
  152. package/modules/beopBidAdapter.md +35 -1
  153. package/modules/bridBidAdapter.js +223 -0
  154. package/modules/cadentApertureMXBidAdapter.md +2 -2
  155. package/modules/categoryTranslation.js +3 -2
  156. package/modules/consentManagement.js +12 -86
  157. package/modules/consentManagementGpp.js +47 -126
  158. package/modules/consentManagementUsp.js +19 -97
  159. package/modules/discoveryBidAdapter.js +1 -1
  160. package/modules/gppControl_usnat.js +11 -0
  161. package/modules/holidBidAdapter.js +49 -30
  162. package/modules/intentIqIdSystem.js +6 -5
  163. package/modules/ixBidAdapter.js +2 -1
  164. package/modules/liveIntentIdSystem.js +8 -3
  165. package/modules/livewrappedAnalyticsAdapter.js +33 -33
  166. package/modules/mediagoBidAdapter.js +1 -0
  167. package/modules/mediasquareBidAdapter.js +19 -23
  168. package/modules/oxxionRtdProvider.js +124 -11
  169. package/modules/oxxionRtdProvider.md +19 -4
  170. package/modules/smartyadsBidAdapter.js +6 -3
  171. package/modules/sovrnBidAdapter.js +5 -0
  172. package/modules/trafficgateBidAdapter.js +126 -72
  173. package/modules/tripleliftBidAdapter.js +21 -1
  174. package/modules/userId/eids.js +29 -0
  175. package/modules/userId/eids.md +19 -2
  176. package/modules/userId/index.js +78 -29
  177. package/modules/userId/userId.md +3 -0
  178. package/modules/vidazooBidAdapter.js +68 -16
  179. package/package.json +1 -1
  180. package/src/activities/params.js +4 -1
  181. package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
  182. package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
  183. package/test/spec/modules/adagioBidAdapter_spec.js +2 -1
  184. package/test/spec/modules/admanBidAdapter_spec.js +8 -2
  185. package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
  186. package/test/spec/modules/adtelligentBidAdapter_spec.js +8 -0
  187. package/test/spec/modules/beopBidAdapter_spec.js +18 -2
  188. package/test/spec/modules/bridBidAdapter_spec.js +129 -0
  189. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
  190. package/test/spec/modules/cadentApertureMXBidAdapter_spec.js +1 -1
  191. package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
  192. package/test/spec/modules/consentManagementGpp_spec.js +84 -7
  193. package/test/spec/modules/consentManagement_spec.js +8 -18
  194. package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
  195. package/test/spec/modules/eids_spec.js +87 -0
  196. package/test/spec/modules/holidBidAdapter_spec.js +26 -6
  197. package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
  198. package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
  199. package/test/spec/modules/ixBidAdapter_spec.js +52 -18
  200. package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
  201. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
  202. package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
  203. package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
  204. package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
  205. package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
  206. package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
  207. package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
  208. package/test/spec/modules/smartyadsBidAdapter_spec.js +1 -1
  209. package/test/spec/modules/sovrnBidAdapter_spec.js +34 -0
  210. package/test/spec/modules/trafficgateBidAdapter_spec.js +1349 -199
  211. package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
  212. package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
  213. package/test/spec/modules/userId_spec.js +393 -6
  214. package/test/spec/modules/vidazooBidAdapter_spec.js +131 -0
@@ -12,7 +12,7 @@
12
12
  */
13
13
 
14
14
  import {config} from '../src/config.js';
15
- import {hook, setupBeforeHookFnOnce} from '../src/hook.js';
15
+ import {hook, setupBeforeHookFnOnce, ready} from '../src/hook.js';
16
16
  import {ajax} from '../src/ajax.js';
17
17
  import {logError, timestamp} from '../src/utils.js';
18
18
  import {addBidResponse} from '../src/auction.js';
@@ -32,7 +32,8 @@ export const registerAdserver = hook('async', function(adServer) {
32
32
  initTranslation(url, DEFAULT_IAB_TO_FW_MAPPING_KEY);
33
33
  }
34
34
  }, 'registerAdserver');
35
- registerAdserver();
35
+
36
+ ready.then(() => registerAdserver());
36
37
 
37
38
  export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation', function getAdserverCategoryHook(fn, adUnitCode, bid, reject) {
38
39
  if (!bid) {
@@ -12,6 +12,7 @@ import {timedAuctionHook} from '../src/utils/perfMetrics.js';
12
12
  import {registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js';
13
13
  import {enrichFPD} from '../src/fpd/enrichment.js';
14
14
  import {getGlobal} from '../src/prebidGlobal.js';
15
+ import {cmpClient} from '../libraries/cmp/cmpClient.js';
15
16
 
16
17
  const DEFAULT_CMP = 'iab';
17
18
  const DEFAULT_CONSENT_TIMEOUT = 10000;
@@ -48,36 +49,6 @@ function lookupStaticConsentData({onSuccess, onError}) {
48
49
  * @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)
49
50
  */
50
51
  function lookupIabConsent({onSuccess, onError, onEvent}) {
51
- function findCMP() {
52
- let f = window;
53
- let cmpFrame;
54
- let cmpFunction;
55
- while (true) {
56
- try {
57
- if (typeof f.__tcfapi === 'function') {
58
- cmpFunction = f.__tcfapi;
59
- cmpFrame = f;
60
- break;
61
- }
62
- } catch (e) { }
63
-
64
- // 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
65
- try {
66
- if (f.frames['__tcfapiLocator']) {
67
- cmpFrame = f;
68
- break;
69
- }
70
- } catch (e) { }
71
-
72
- if (f === window.top) break;
73
- f = f.parent;
74
- }
75
- return {
76
- cmpFrame,
77
- cmpFunction
78
- };
79
- }
80
-
81
52
  function cmpResponseCallback(tcfData, success) {
82
53
  logInfo('Received a response from CMP', tcfData);
83
54
  if (success) {
@@ -90,70 +61,25 @@ function lookupIabConsent({onSuccess, onError, onEvent}) {
90
61
  }
91
62
  }
92
63
 
93
- const cmpCallbacks = {};
94
- const { cmpFrame, cmpFunction } = findCMP();
64
+ const cmp = cmpClient({
65
+ apiName: '__tcfapi',
66
+ apiVersion: CMP_VERSION,
67
+ apiArgs: ['command', 'version', 'callback', 'parameter'],
68
+ });
95
69
 
96
- if (!cmpFrame) {
70
+ if (!cmp) {
97
71
  return onError('TCF2 CMP not found.');
98
72
  }
99
- // to collect the consent information from the user, we perform two calls to the CMP in parallel:
100
- // first to collect the user's consent choices represented in an encoded string (via getConsentData)
101
- // second to collect the user's full unparsed consent information (via getVendorConsents)
102
-
103
- // the following code also determines where the CMP is located and uses the proper workflow to communicate with it:
104
- // check to see if CMP is found on the same window level as prebid and call it directly if so
105
- // check to see if prebid is in a safeframe (with CMP support)
106
- // else assume prebid may be inside an iframe and use the IAB CMP locator code to see if CMP's located in a higher parent window. this works in cross domain iframes
107
- // if the CMP is not found, the iframe function will call the cmpError exit callback to abort the rest of the CMP workflow
108
-
109
- if (typeof cmpFunction === 'function') {
73
+ if (cmp.isDirect) {
110
74
  logInfo('Detected CMP API is directly accessible, calling it now...');
111
- cmpFunction('addEventListener', CMP_VERSION, cmpResponseCallback);
112
75
  } else {
113
76
  logInfo('Detected CMP is outside the current iframe where Prebid.js is located, calling it now...');
114
- callCmpWhileInIframe('addEventListener', cmpFrame, cmpResponseCallback);
115
77
  }
116
78
 
117
- function callCmpWhileInIframe(commandName, cmpFrame, moduleCallback) {
118
- const apiName = '__tcfapi';
119
-
120
- const callName = `${apiName}Call`;
121
-
122
- /* Setup up a __cmp function to do the postMessage and stash the callback.
123
- This function behaves (from the caller's perspective identicially to the in-frame __cmp call */
124
- window[apiName] = function (cmd, cmpVersion, callback, arg) {
125
- const callId = Math.random() + '';
126
- const msg = {
127
- [callName]: {
128
- command: cmd,
129
- version: cmpVersion,
130
- parameter: arg,
131
- callId: callId
132
- }
133
- };
134
-
135
- cmpCallbacks[callId] = callback;
136
- cmpFrame.postMessage(msg, '*');
137
- }
138
-
139
- /** when we get the return message, call the stashed callback */
140
- window.addEventListener('message', readPostMessageResponse, false);
141
-
142
- // call CMP
143
- window[apiName](commandName, CMP_VERSION, moduleCallback);
144
-
145
- function readPostMessageResponse(event) {
146
- const cmpDataPkgName = `${apiName}Return`;
147
- const json = (typeof event.data === 'string' && includes(event.data, cmpDataPkgName)) ? JSON.parse(event.data) : event.data;
148
- if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) {
149
- const payload = json[cmpDataPkgName];
150
- // TODO - clean up this logic (move listeners?); we have duplicate messages responses because 2 eventlisteners are active from the 2 cmp requests running in parallel
151
- if (cmpCallbacks.hasOwnProperty(payload.callId)) {
152
- cmpCallbacks[payload.callId](payload.returnValue, payload.success);
153
- }
154
- }
155
- }
156
- }
79
+ cmp({
80
+ command: 'addEventListener',
81
+ callback: cmpResponseCallback
82
+ })
157
83
  }
158
84
 
159
85
  /**
@@ -7,10 +7,12 @@
7
7
  import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
8
8
  import {config} from '../src/config.js';
9
9
  import {gppDataHandler} from '../src/adapterManager.js';
10
- import {includes} from '../src/polyfill.js';
11
10
  import {timedAuctionHook} from '../src/utils/perfMetrics.js';
12
11
  import { enrichFPD } from '../src/fpd/enrichment.js';
13
12
  import {getGlobal} from '../src/prebidGlobal.js';
13
+ import {cmpClient} from '../libraries/cmp/cmpClient.js';
14
+ import {GreedyPromise} from '../src/utils/promise.js';
15
+ import {buildActivityParams} from '../src/activities/params.js';
14
16
 
15
17
  const DEFAULT_CMP = 'iab';
16
18
  const DEFAULT_CONSENT_TIMEOUT = 10000;
@@ -18,7 +20,7 @@ const CMP_VERSION = 1;
18
20
 
19
21
  export let userCMP;
20
22
  export let consentTimeout;
21
- export let staticConsentData;
23
+ let staticConsentData;
22
24
 
23
25
  let consentData;
24
26
  let addedConsentHook = false;
@@ -29,28 +31,16 @@ const cmpCallMap = {
29
31
  'static': lookupStaticConsentData
30
32
  };
31
33
 
32
- /**
33
- * This function checks the state of the IAB gppData's applicableSection field (to ensure it's populated and has a valid value).
34
- * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section.
35
- *
36
- * 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.
37
- * CMPs should adjust their logic to use the new format (applicableSecctions), but that may not be the case with the initial release.
38
- * Added support just in case for this transition period, can likely be removed at a later date...
39
- * @param gppData represents the IAB gppData object
40
- * @returns true|false
41
- */
42
- function checkApplicableSectionIsReady(gppData) {
43
- return gppData && Array.isArray(gppData.applicableSection) && gppData.applicableSection.length > 0 && gppData.applicableSection[0] !== 0;
44
- }
45
-
46
34
  /**
47
35
  * This function checks the state of the IAB gppData's applicableSections field (to ensure it's populated and has a valid value).
48
36
  * section === 0 represents a CMP's default value when CMP is loading, it shoud not be used a real user's section.
49
37
  * @param gppData represents the IAB gppData object
50
- * @returns true|false
38
+ * @returns {Array}
51
39
  */
52
- function checkApplicableSectionsIsReady(gppData) {
53
- return gppData && Array.isArray(gppData.applicableSections) && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== 0;
40
+ function applicableSections(gppData) {
41
+ return gppData && Array.isArray(gppData.applicableSections) && gppData.applicableSections.length > 0 && gppData.applicableSections[0] !== 0
42
+ ? gppData.applicableSections
43
+ : [];
54
44
  }
55
45
 
56
46
  /**
@@ -68,107 +58,36 @@ function lookupStaticConsentData({onSuccess, onError}) {
68
58
  * @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP
69
59
  * @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)
70
60
  */
71
- function lookupIabConsent({onSuccess, onError}) {
72
- const cmpApiName = '__gpp';
73
- const cmpCallbacks = {};
74
- let registeredPostMessageResponseListener = false;
75
-
76
- function findCMP() {
77
- let f = window;
78
- let cmpFrame;
79
- let cmpDirectAccess = false;
80
- while (true) {
81
- try {
82
- if (typeof f[cmpApiName] === 'function') {
83
- cmpFrame = f;
84
- cmpDirectAccess = true;
85
- break;
86
- }
87
- } catch (e) {}
88
-
89
- // 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
90
- try {
91
- if (f.frames['__gppLocator']) {
92
- cmpFrame = f;
93
- break;
94
- }
95
- } catch (e) {}
96
-
97
- if (f === window.top) break;
98
- f = f.parent;
99
- }
100
-
101
- return {
102
- cmpFrame,
103
- cmpDirectAccess
104
- };
105
- }
106
-
107
- const {cmpFrame, cmpDirectAccess} = findCMP();
108
-
109
- if (!cmpFrame) {
61
+ export function lookupIabConsent({onSuccess, onError}, mkClient = cmpClient) {
62
+ const cmp = mkClient({
63
+ apiName: '__gpp',
64
+ apiVersion: CMP_VERSION,
65
+ });
66
+ if (!cmp) {
110
67
  return onError('GPP CMP not found.');
111
68
  }
112
69
 
113
- const invokeCMP = (cmpDirectAccess) ? invokeCMPDirect : invokeCMPFrame;
114
-
115
- function invokeCMPDirect({command, callback, parameter, version = CMP_VERSION}, resultCb) {
116
- if (typeof resultCb === 'function') {
117
- resultCb(cmpFrame[cmpApiName](command, callback, parameter, version));
118
- } else {
119
- cmpFrame[cmpApiName](command, callback, parameter, version);
120
- }
121
- }
122
-
123
- function invokeCMPFrame({command, callback, parameter, version = CMP_VERSION}, resultCb) {
124
- const callName = `${cmpApiName}Call`;
125
- if (!registeredPostMessageResponseListener) {
126
- // when we get the return message, call the stashed callback;
127
- window.addEventListener('message', readPostMessageResponse, false);
128
- registeredPostMessageResponseListener = true;
129
- }
130
-
131
- // call CMP via postMessage
132
- const callId = Math.random().toString();
133
- const msg = {
134
- [callName]: {
135
- command: command,
136
- parameter,
137
- version,
138
- callId: callId
139
- }
140
- };
141
-
142
- // TODO? - add logic to check if random was already used in the same session, and roll another if so?
143
- cmpCallbacks[callId] = (typeof callback === 'function') ? callback : resultCb;
144
- cmpFrame.postMessage(msg, '*');
145
-
146
- function readPostMessageResponse(event) {
147
- const cmpDataPkgName = `${cmpApiName}Return`;
148
- const json = (typeof event.data === 'string' && event.data.includes(cmpDataPkgName)) ? JSON.parse(event.data) : event.data;
149
- if (json[cmpDataPkgName] && json[cmpDataPkgName].callId) {
150
- const payload = json[cmpDataPkgName];
151
-
152
- if (cmpCallbacks.hasOwnProperty(payload.callId)) {
153
- cmpCallbacks[payload.callId](payload.returnValue);
154
- }
155
- }
156
- }
157
- }
158
-
159
- const startupMsg = (cmpDirectAccess) ? 'Detected GPP CMP API is directly accessible, calling it now...'
70
+ const startupMsg = (cmp.isDirect) ? 'Detected GPP CMP API is directly accessible, calling it now...'
160
71
  : 'Detected GPP CMP is outside the current iframe where Prebid.js is located, calling it now...';
161
72
  logInfo(startupMsg);
162
73
 
163
- invokeCMP({
74
+ cmp({
164
75
  command: 'addEventListener',
165
76
  callback: function (evt) {
166
77
  if (evt) {
167
- logInfo(`Received a ${(cmpDirectAccess ? 'direct' : 'postmsg')} response from GPP CMP for event`, evt);
78
+ logInfo(`Received a ${(cmp.isDirect ? 'direct' : 'postmsg')} response from GPP CMP for event`, evt);
168
79
  if (evt.eventName === 'sectionChange' || evt.pingData.cmpStatus === 'loaded') {
169
- invokeCMP({command: 'getGPPData'}, function (gppData) {
170
- logInfo(`Received a ${cmpDirectAccess ? 'direct' : 'postmsg'} response from GPP CMP for getGPPData`, gppData);
171
- processCmpData(gppData, {onSuccess, onError});
80
+ cmp({command: 'getGPPData'}).then((gppData) => {
81
+ logInfo(`Received a ${cmp.isDirect ? 'direct' : 'postmsg'} response from GPP CMP for getGPPData`, gppData);
82
+ return GreedyPromise.all(
83
+ (gppData?.pingData?.supportedAPIs || [])
84
+ .map((name) => cmp({command: 'getSection', parameter: name})
85
+ .catch(() => { logError(`Could not retrieve section data for GPP section '${name}'`) })
86
+ .then((res) => [name, res]))
87
+ ).then((sections) => {
88
+ const sectionData = Object.fromEntries(sections.filter(([_, val]) => val != null));
89
+ processCmpData({gppData, sectionData}, {onSuccess, onError});
90
+ })
172
91
  });
173
92
  } else if (evt.pingData.cmpStatus === 'error') {
174
93
  onError('CMP returned with a cmpStatus:error response. Please check CMP setup.');
@@ -199,7 +118,7 @@ function loadConsentData(cb) {
199
118
  }
200
119
  }
201
120
 
202
- if (!includes(Object.keys(cmpCallMap), userCMP)) {
121
+ if (!cmpCallMap.hasOwnProperty(userCMP)) {
203
122
  done(null, false, `GPP CMP framework (${userCMP}) is not a supported framework. Aborting consentManagement module and resuming auction.`);
204
123
  return;
205
124
  }
@@ -219,7 +138,7 @@ function loadConsentData(cb) {
219
138
  }
220
139
  processCmpData(consentData, {
221
140
  onSuccess: continueToAuction,
222
- onError: () => continueToAuction(storeConsentData(undefined))
141
+ onError: () => continueToAuction(storeConsentData())
223
142
  })
224
143
  }
225
144
  if (consentTimeout === 0) {
@@ -281,11 +200,10 @@ export const requestBidsHook = timedAuctionHook('gpp', function requestBidsHook(
281
200
  * If it's bad, we call `onError`
282
201
  * If it's good, then we store the value and call `onSuccess`
283
202
  */
284
- function processCmpData(consentObject, {onSuccess, onError}) {
203
+ function processCmpData(consentData, {onSuccess, onError}) {
285
204
  function checkData() {
286
- const gppString = consentObject && consentObject.gppString;
287
- const gppSection = (checkApplicableSectionsIsReady(consentObject)) ? consentObject.applicableSections
288
- : (checkApplicableSectionIsReady(consentObject)) ? consentObject.applicableSection : [];
205
+ const gppString = consentData?.gppData?.gppString;
206
+ const gppSection = consentData?.gppData?.applicableSections;
289
207
 
290
208
  return !!(
291
209
  (!Array.isArray(gppSection)) ||
@@ -294,25 +212,25 @@ function processCmpData(consentObject, {onSuccess, onError}) {
294
212
  }
295
213
 
296
214
  if (checkData()) {
297
- onError(`CMP returned unexpected value during lookup process.`, consentObject);
215
+ onError(`CMP returned unexpected value during lookup process.`, consentData);
298
216
  } else {
299
- onSuccess(storeConsentData(consentObject));
217
+ onSuccess(storeConsentData(consentData));
300
218
  }
301
219
  }
302
220
 
303
221
  /**
304
222
  * Stores CMP data locally in module to make information available in adaptermanager.js for later in the auction
305
- * @param {object} cmpConsentObject required; an object representing user's consent choices (can be undefined in certain use-cases for this function only)
223
+ * @param {{}} gppData the result of calling a CMP's `getGPPData` (or equivalent)
224
+ * @param {{}} sectionData map from GPP section name to the result of calling a CMP's `getSection` (or equivalent)
306
225
  */
307
- function storeConsentData(cmpConsentObject) {
226
+ export function storeConsentData({gppData, sectionData} = {}) {
308
227
  consentData = {
309
- gppString: (cmpConsentObject) ? cmpConsentObject.gppString : undefined,
310
-
311
- fullGppData: (cmpConsentObject) || undefined,
228
+ gppString: (gppData) ? gppData.gppString : undefined,
229
+ gppData: (gppData) || undefined,
312
230
  };
313
- consentData.applicableSections = (checkApplicableSectionsIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSections
314
- : (checkApplicableSectionIsReady(cmpConsentObject)) ? cmpConsentObject.applicableSection : [];
231
+ consentData.applicableSections = applicableSections(gppData);
315
232
  consentData.apiVersion = CMP_VERSION;
233
+ consentData.sectionData = sectionData;
316
234
  return consentData;
317
235
  }
318
236
 
@@ -353,7 +271,7 @@ export function setConsentConfig(config) {
353
271
 
354
272
  if (userCMP === 'static') {
355
273
  if (isPlainObject(config.consentData)) {
356
- staticConsentData = config.consentData;
274
+ staticConsentData = {gppData: config.consentData, sectionData: config.sectionData};
357
275
  consentTimeout = 0;
358
276
  } else {
359
277
  logError(`consentManagement.gpp config with cmpApi: 'static' did not specify consentData. No consents will be available to adapters.`);
@@ -364,6 +282,9 @@ export function setConsentConfig(config) {
364
282
 
365
283
  if (!addedConsentHook) {
366
284
  getGlobal().requestBids.before(requestBidsHook, 50);
285
+ buildActivityParams.before((next, params) => {
286
+ return next(Object.assign({gppConsent: gppDataHandler.getConsentData()}, params));
287
+ });
367
288
  }
368
289
  addedConsentHook = true;
369
290
  gppDataHandler.enable();
@@ -4,12 +4,13 @@
4
4
  * information and make it available for any USP (CCPA) supported adapters to
5
5
  * read/pass this information to their system.
6
6
  */
7
- import {deepSetValue, isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
7
+ import {deepSetValue, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
8
8
  import {config} from '../src/config.js';
9
9
  import adapterManager, {uspDataHandler} from '../src/adapterManager.js';
10
10
  import {timedAuctionHook} from '../src/utils/perfMetrics.js';
11
11
  import {getHook} from '../src/hook.js';
12
12
  import {enrichFPD} from '../src/fpd/enrichment.js';
13
+ import {cmpClient} from '../libraries/cmp/cmpClient.js';
13
14
 
14
15
  const DEFAULT_CONSENT_API = 'iab';
15
16
  const DEFAULT_CONSENT_TIMEOUT = 50;
@@ -41,35 +42,6 @@ function lookupStaticConsentData({onSuccess, onError}) {
41
42
  * based on the appropriate result.
42
43
  */
43
44
  function lookupUspConsent({onSuccess, onError}) {
44
- function findUsp() {
45
- let f = window;
46
- let uspapiFrame;
47
- let uspapiFunction;
48
-
49
- while (true) {
50
- try {
51
- if (typeof f.__uspapi === 'function') {
52
- uspapiFunction = f.__uspapi;
53
- uspapiFrame = f;
54
- break;
55
- }
56
- } catch (e) {}
57
-
58
- try {
59
- if (f.frames['__uspapiLocator']) {
60
- uspapiFrame = f;
61
- break;
62
- }
63
- } catch (e) {}
64
- if (f === window.top) break;
65
- f = f.parent;
66
- }
67
- return {
68
- uspapiFrame,
69
- uspapiFunction,
70
- };
71
- }
72
-
73
45
  function handleUspApiResponseCallbacks() {
74
46
  const uspResponse = {};
75
47
 
@@ -92,86 +64,36 @@ function lookupUspConsent({onSuccess, onError}) {
92
64
  }
93
65
 
94
66
  let callbackHandler = handleUspApiResponseCallbacks();
95
- let uspapiCallbacks = {};
96
67
 
97
- let { uspapiFrame, uspapiFunction } = findUsp();
68
+ const cmp = cmpClient({
69
+ apiName: '__uspapi',
70
+ apiVersion: USPAPI_VERSION,
71
+ apiArgs: ['command', 'version', 'callback'],
72
+ });
98
73
 
99
- if (!uspapiFrame) {
74
+ if (!cmp) {
100
75
  return onError('USP CMP not found.');
101
76
  }
102
77
 
103
- function registerDataDelHandler(invoker, arg2) {
104
- try {
105
- invoker('registerDeletion', arg2, adapterManager.callDataDeletionRequest);
106
- } catch (e) {
107
- logError('Error invoking CMP `registerDeletion`:', e);
108
- }
109
- }
110
-
111
- // to collect the consent information from the user, we perform a call to USPAPI
112
- // to collect the user's consent choices represented as a string (via getUSPData)
113
-
114
- // the following code also determines where the USPAPI is located and uses the proper workflow to communicate with it:
115
- // - use the USPAPI locator code to see if USP's located in the current window or an ancestor window.
116
- // - else assume prebid is in an iframe, and use the locator to see if the CMP is located in a higher parent window. This works in cross domain iframes.
117
- // - if USPAPI is not found, the iframe function will call the uspError exit callback to abort the rest of the USPAPI workflow
118
-
119
- if (isFn(uspapiFunction)) {
78
+ if (cmp.isDirect) {
120
79
  logInfo('Detected USP CMP is directly accessible, calling it now...');
121
- uspapiFunction(
122
- 'getUSPData',
123
- USPAPI_VERSION,
124
- callbackHandler.consentDataCallback
125
- );
126
- registerDataDelHandler(uspapiFunction, USPAPI_VERSION);
127
80
  } else {
128
81
  logInfo(
129
82
  'Detected USP CMP is outside the current iframe where Prebid.js is located, calling it now...'
130
83
  );
131
- callUspApiWhileInIframe(
132
- 'getUSPData',
133
- uspapiFrame,
134
- callbackHandler.consentDataCallback
135
- );
136
- registerDataDelHandler(callUspApiWhileInIframe, uspapiFrame);
137
84
  }
138
85
 
139
- let listening = false;
140
-
141
- function callUspApiWhileInIframe(commandName, uspapiFrame, moduleCallback) {
142
- function callUsp(cmd, ver, callback) {
143
- let callId = Math.random() + '';
144
- let msg = {
145
- __uspapiCall: {
146
- command: cmd,
147
- version: ver,
148
- callId: callId,
149
- },
150
- };
151
-
152
- uspapiCallbacks[callId] = callback;
153
- uspapiFrame.postMessage(msg, '*');
154
- };
155
-
156
- /** when we get the return message, call the stashed callback */
157
- if (!listening) {
158
- window.addEventListener('message', readPostMessageResponse, false);
159
- listening = true;
160
- }
161
-
162
- // call uspapi
163
- callUsp(commandName, USPAPI_VERSION, moduleCallback);
86
+ cmp({
87
+ command: 'getUSPData',
88
+ callback: callbackHandler.consentDataCallback
89
+ });
164
90
 
165
- function readPostMessageResponse(event) {
166
- const res = event && event.data && event.data.__uspapiReturn;
167
- if (res && res.callId) {
168
- if (uspapiCallbacks.hasOwnProperty(res.callId)) {
169
- uspapiCallbacks[res.callId](res.returnValue, res.success);
170
- delete uspapiCallbacks[res.callId];
171
- }
172
- }
173
- }
174
- }
91
+ cmp({
92
+ command: 'registerDeletion',
93
+ callback: adapterManager.callDataDeletionRequest
94
+ }).catch(e => {
95
+ logError('Error invoking CMP `registerDeletion`:', e);
96
+ });
175
97
  }
176
98
 
177
99
  /**
@@ -258,7 +258,7 @@ function getItems(validBidRequests, bidderRequest) {
258
258
  format: sizes,
259
259
  },
260
260
  ext: {},
261
- tagid: globals['tagid'],
261
+ tagid: req.params && req.params.tagid
262
262
  };
263
263
  }
264
264
  itemMaps[id] = {
@@ -0,0 +1,11 @@
1
+ import {config} from '../src/config.js';
2
+ import {setupRules} from '../libraries/mspa/activityControls.js';
3
+
4
+ let setupDone = false;
5
+
6
+ config.getConfig('consentManagement', (cfg) => {
7
+ if (cfg?.consentManagement?.gpp != null && !setupDone) {
8
+ setupRules('usnat', [7]);
9
+ setupDone = true;
10
+ }
11
+ })