prebid.js 7.14.0 → 7.16.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 (239) hide show
  1. package/.circleci/config.yml +3 -0
  2. package/dist/1plusXRtdProvider.js +1 -1
  3. package/dist/33acrossBidAdapter.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adfBidAdapter.js +1 -1
  7. package/dist/adgenerationBidAdapter.js +1 -1
  8. package/dist/adkernelAdnBidAdapter.js +1 -1
  9. package/dist/adkernelBidAdapter.js +1 -1
  10. package/dist/adlooxAdServerVideo.js +1 -1
  11. package/dist/adlooxRtdProvider.js +1 -1
  12. package/dist/adrelevantisBidAdapter.js +1 -1
  13. package/dist/adtrgtmeBidAdapter.js +1 -1
  14. package/dist/adtrueBidAdapter.js +1 -1
  15. package/dist/adxcgBidAdapter.js +1 -1
  16. package/dist/airgridRtdProvider.js +1 -1
  17. package/dist/ajaBidAdapter.js +1 -1
  18. package/dist/amxBidAdapter.js +1 -1
  19. package/dist/amxIdSystem.js +1 -1
  20. package/dist/aolBidAdapter.js +1 -1
  21. package/dist/appierAnalyticsAdapter.js +1 -1
  22. package/dist/appnexusBidAdapter.js +1 -1
  23. package/dist/asoBidAdapter.js +1 -1
  24. package/dist/axonixBidAdapter.js +1 -1
  25. package/dist/beachfrontBidAdapter.js +1 -1
  26. package/dist/bidglassBidAdapter.js +1 -1
  27. package/dist/big-richmediaBidAdapter.js +1 -1
  28. package/dist/bizzclickBidAdapter.js +1 -1
  29. package/dist/bliinkBidAdapter.js +1 -1
  30. package/dist/bluebillywigBidAdapter.js +1 -1
  31. package/dist/brandmetricsRtdProvider.js +1 -1
  32. package/dist/bridgewellBidAdapter.js +1 -1
  33. package/dist/brightMountainMediaBidAdapter.js +1 -1
  34. package/dist/brightcomBidAdapter.js +1 -1
  35. package/dist/browsiRtdProvider.js +1 -1
  36. package/dist/categoryTranslation.js +1 -1
  37. package/dist/concertBidAdapter.js +1 -1
  38. package/dist/connectadBidAdapter.js +1 -1
  39. package/dist/consentManagement.js +1 -1
  40. package/dist/consentManagementUsp.js +1 -1
  41. package/dist/consumableBidAdapter.js +1 -1
  42. package/dist/conversantBidAdapter.js +1 -1
  43. package/dist/cpmstarBidAdapter.js +1 -1
  44. package/dist/craftBidAdapter.js +1 -1
  45. package/dist/criteoBidAdapter.js +1 -1
  46. package/dist/currency.js +1 -1
  47. package/dist/dataControllerModule.js +1 -1
  48. package/dist/dchain.js +1 -1
  49. package/dist/deepintentBidAdapter.js +1 -1
  50. package/dist/dependencies.json +3 -0
  51. package/dist/dgkeywordRtdProvider.js +1 -1
  52. package/dist/dianomiBidAdapter.js +1 -1
  53. package/dist/distroscaleBidAdapter.js +1 -1
  54. package/dist/dspxBidAdapter.js +1 -1
  55. package/dist/eplanningBidAdapter.js +1 -1
  56. package/dist/etargetBidAdapter.js +1 -1
  57. package/dist/feedadBidAdapter.js +1 -1
  58. package/dist/finativeBidAdapter.js +1 -1
  59. package/dist/fpdModule.js +1 -1
  60. package/dist/gamoshiBidAdapter.js +1 -1
  61. package/dist/glimpseBidAdapter.js +1 -1
  62. package/dist/gmosspBidAdapter.js +1 -1
  63. package/dist/goldbachBidAdapter.js +1 -1
  64. package/dist/gothamadsBidAdapter.js +1 -1
  65. package/dist/gridBidAdapter.js +1 -1
  66. package/dist/gridNMBidAdapter.js +1 -1
  67. package/dist/gumgumBidAdapter.js +1 -1
  68. package/dist/h12mediaBidAdapter.js +1 -1
  69. package/dist/iasRtdProvider.js +1 -1
  70. package/dist/id5IdSystem.js +1 -1
  71. package/dist/imRtdProvider.js +1 -1
  72. package/dist/impactifyBidAdapter.js +1 -1
  73. package/dist/improvedigitalBidAdapter.js +1 -1
  74. package/dist/inmarBidAdapter.js +1 -1
  75. package/dist/insticatorBidAdapter.js +1 -1
  76. package/dist/ixBidAdapter.js +1 -1
  77. package/dist/justpremiumBidAdapter.js +1 -1
  78. package/dist/konduitAnalyticsAdapter.js +1 -1
  79. package/dist/kueezBidAdapter.js +1 -1
  80. package/dist/lassoBidAdapter.js +1 -1
  81. package/dist/lifestreetBidAdapter.js +1 -1
  82. package/dist/liveIntentAnalyticsAdapter.js +1 -0
  83. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  84. package/dist/logicadBidAdapter.js +1 -1
  85. package/dist/loglyliftBidAdapter.js +1 -1
  86. package/dist/luponmediaBidAdapter.js +1 -1
  87. package/dist/malltvAnalyticsAdapter.js +1 -1
  88. package/dist/marsmediaBidAdapter.js +1 -1
  89. package/dist/mass.js +1 -1
  90. package/dist/mediafuseBidAdapter.js +1 -1
  91. package/dist/mediakeysBidAdapter.js +1 -1
  92. package/dist/mediasniperBidAdapter.js +1 -1
  93. package/dist/mediasquareBidAdapter.js +1 -1
  94. package/dist/mgidBidAdapter.js +1 -1
  95. package/dist/minutemediaBidAdapter.js +1 -1
  96. package/dist/multibid.js +1 -1
  97. package/dist/naveggIdSystem.js +1 -1
  98. package/dist/newspassidBidAdapter.js +1 -1
  99. package/dist/nextMillenniumBidAdapter.js +1 -1
  100. package/dist/not-for-prod/prebid.js +172 -171
  101. package/dist/oguryBidAdapter.js +1 -1
  102. package/dist/oneKeyRtdProvider.js +1 -1
  103. package/dist/onetagBidAdapter.js +1 -1
  104. package/dist/ooloAnalyticsAdapter.js +1 -1
  105. package/dist/openxBidAdapter.js +1 -1
  106. package/dist/openxOrtbBidAdapter.js +1 -1
  107. package/dist/operaadsBidAdapter.js +1 -1
  108. package/dist/outbrainBidAdapter.js +1 -1
  109. package/dist/ozoneBidAdapter.js +1 -1
  110. package/dist/parrableIdSystem.js +1 -1
  111. package/dist/permutiveRtdProvider.js +1 -1
  112. package/dist/pixfutureBidAdapter.js +1 -1
  113. package/dist/prebid-core.js +2 -2
  114. package/dist/prebidServerBidAdapter.js +1 -1
  115. package/dist/priceFloors.js +1 -1
  116. package/dist/pubCommonId.js +1 -1
  117. package/dist/pubgeniusBidAdapter.js +1 -1
  118. package/dist/publinkIdSystem.js +1 -1
  119. package/dist/pubmaticBidAdapter.js +1 -1
  120. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  121. package/dist/pubwiseBidAdapter.js +1 -1
  122. package/dist/pubxBidAdapter.js +1 -1
  123. package/dist/pxyzBidAdapter.js +1 -1
  124. package/dist/quantcastBidAdapter.js +1 -1
  125. package/dist/readpeakBidAdapter.js +1 -1
  126. package/dist/relaidoBidAdapter.js +1 -1
  127. package/dist/rhythmoneBidAdapter.js +1 -1
  128. package/dist/riseBidAdapter.js +1 -1
  129. package/dist/rtdModule.js +1 -1
  130. package/dist/rubiconAnalyticsAdapter.js +1 -1
  131. package/dist/rubiconBidAdapter.js +1 -1
  132. package/dist/seedingAllianceBidAdapter.js +1 -1
  133. package/dist/seedtagBidAdapter.js +1 -1
  134. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  135. package/dist/sharethroughBidAdapter.js +1 -1
  136. package/dist/shinezBidAdapter.js +1 -1
  137. package/dist/sirdataRtdProvider.js +1 -1
  138. package/dist/smaatoBidAdapter.js +1 -1
  139. package/dist/smartadserverBidAdapter.js +1 -1
  140. package/dist/smartxBidAdapter.js +1 -1
  141. package/dist/smilewantedBidAdapter.js +1 -1
  142. package/dist/sonobiBidAdapter.js +1 -1
  143. package/dist/sovrnAnalyticsAdapter.js +1 -1
  144. package/dist/sovrnBidAdapter.js +1 -1
  145. package/dist/spotxBidAdapter.js +1 -1
  146. package/dist/sspBCBidAdapter.js +1 -1
  147. package/dist/stroeerCoreBidAdapter.js +1 -1
  148. package/dist/sublimeBidAdapter.js +1 -1
  149. package/dist/synacormediaBidAdapter.js +1 -1
  150. package/dist/targetVideoBidAdapter.js +1 -1
  151. package/dist/teadsBidAdapter.js +1 -1
  152. package/dist/trionBidAdapter.js +1 -1
  153. package/dist/tripleliftBidAdapter.js +1 -1
  154. package/dist/ttdBidAdapter.js +1 -1
  155. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  156. package/dist/ucfunnelBidAdapter.js +1 -1
  157. package/dist/underdogmediaBidAdapter.js +1 -1
  158. package/dist/undertoneBidAdapter.js +1 -1
  159. package/dist/userId.js +1 -1
  160. package/dist/vidazooBidAdapter.js +1 -1
  161. package/dist/videobyteBidAdapter.js +1 -1
  162. package/dist/viewability.js +1 -1
  163. package/dist/visxBidAdapter.js +1 -1
  164. package/dist/vuukleBidAdapter.js +1 -1
  165. package/dist/weboramaRtdProvider.js +1 -1
  166. package/dist/widespaceBidAdapter.js +1 -1
  167. package/dist/winrBidAdapter.js +1 -1
  168. package/dist/yahoosspBidAdapter.js +1 -1
  169. package/dist/yieldliftBidAdapter.js +1 -1
  170. package/dist/yieldmoBidAdapter.js +1 -1
  171. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  172. package/dist/zeta_global_sspBidAdapter.js +1 -1
  173. package/modules/amxBidAdapter.js +98 -78
  174. package/modules/appnexusBidAdapter.js +73 -12
  175. package/modules/categoryTranslation.js +9 -8
  176. package/modules/consentManagement.js +4 -2
  177. package/modules/consentManagementUsp.js +17 -14
  178. package/modules/cpmstarBidAdapter.js +2 -1
  179. package/modules/currency.js +4 -3
  180. package/modules/dataControllerModule/index.js +4 -3
  181. package/modules/dchain.js +3 -2
  182. package/modules/dianomiBidAdapter.js +17 -14
  183. package/modules/dianomiBidAdapter.md +1 -1
  184. package/modules/feedadBidAdapter.js +40 -8
  185. package/modules/fpdModule/index.js +3 -2
  186. package/modules/iasRtdProvider.js +17 -3
  187. package/modules/ixBidAdapter.js +2 -5
  188. package/modules/liveIntentAnalyticsAdapter.js +148 -0
  189. package/modules/liveIntentAnalyticsAdapter.md +22 -0
  190. package/modules/mass.js +5 -3
  191. package/modules/multibid/index.js +4 -2
  192. package/modules/naveggIdSystem.js +53 -22
  193. package/modules/nextMillenniumBidAdapter.js +168 -55
  194. package/modules/openxOrtbBidAdapter.js +1 -1
  195. package/modules/prebidServerBidAdapter/index.js +18 -4
  196. package/modules/priceFloors.js +5 -4
  197. package/modules/pubCommonId.js +3 -2
  198. package/modules/rtdModule/index.js +3 -2
  199. package/modules/sharethroughBidAdapter.js +8 -6
  200. package/modules/spotxBidAdapter.js +1 -0
  201. package/modules/stroeerCoreBidAdapter.js +129 -92
  202. package/modules/stroeerCoreBidAdapter.md +52 -14
  203. package/modules/teadsBidAdapter.js +32 -10
  204. package/modules/ucfunnelBidAdapter.js +9 -10
  205. package/modules/userId/index.js +73 -48
  206. package/modules/viewability.js +2 -170
  207. package/package.json +3 -3
  208. package/src/adapterManager.js +21 -13
  209. package/src/adapters/bidderFactory.js +28 -6
  210. package/src/auction.js +17 -4
  211. package/src/auctionManager.js +5 -0
  212. package/src/constants.json +2 -0
  213. package/src/native.js +5 -2
  214. package/src/prebid.js +52 -23
  215. package/src/secureCreatives.js +1 -1
  216. package/src/utils/perfMetrics.js +386 -0
  217. package/src/utils.js +1 -1
  218. package/test/helpers/testing-utils.js +4 -3
  219. package/test/spec/modules/adriverIdSystem_spec.js +7 -3
  220. package/test/spec/modules/amxBidAdapter_spec.js +250 -192
  221. package/test/spec/modules/appnexusBidAdapter_spec.js +61 -6
  222. package/test/spec/modules/consentManagementUsp_spec.js +6 -2
  223. package/test/spec/modules/dianomiBidAdapter_spec.js +326 -6
  224. package/test/spec/modules/feedadBidAdapter_spec.js +147 -11
  225. package/test/spec/modules/iasRtdProvider_spec.js +3 -1
  226. package/test/spec/modules/ixBidAdapter_spec.js +0 -64
  227. package/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +297 -0
  228. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +103 -1
  229. package/test/spec/modules/openxOrtbBidAdapter_spec.js +31 -0
  230. package/test/spec/modules/sharethroughBidAdapter_spec.js +23 -2
  231. package/test/spec/modules/spotxBidAdapter_spec.js +6 -0
  232. package/test/spec/modules/stroeerCoreBidAdapter_spec.js +315 -33
  233. package/test/spec/modules/teadsBidAdapter_spec.js +65 -11
  234. package/test/spec/modules/ucfunnelBidAdapter_spec.js +24 -10
  235. package/test/spec/native_spec.js +11 -0
  236. package/test/spec/unit/utils/perfMetrics_spec.js +394 -0
  237. package/wdio.conf.js +1 -0
  238. package/modules/viewability.md +0 -87
  239. package/test/spec/modules/viewability_spec.js +0 -280
@@ -22,6 +22,7 @@ import {
22
22
  logInfo,
23
23
  logMessage,
24
24
  logWarn,
25
+ mergeDeep,
25
26
  transformBidderParamKeywords,
26
27
  getWindowFromDocument
27
28
  } from '../src/utils.js';
@@ -230,15 +231,32 @@ export const spec = {
230
231
  payload.app = appIdObj;
231
232
  }
232
233
 
233
- let auctionKeywords = config.getConfig('appnexusAuctionKeywords');
234
- if (isPlainObject(auctionKeywords)) {
235
- let aucKeywords = transformBidderParamKeywords(auctionKeywords);
234
+ function grabOrtb2Keywords(ortb2Obj) {
235
+ const fields = ['site.keywords', 'site.content.keywords', 'user.keywords', 'app.keywords', 'app.content.keywords'];
236
+ let result = [];
236
237
 
237
- if (aucKeywords.length > 0) {
238
- aucKeywords.forEach(deleteValues);
239
- }
238
+ fields.forEach(path => {
239
+ let keyStr = deepAccess(ortb2Obj, path);
240
+ if (isStr(keyStr)) result.push(keyStr);
241
+ });
242
+ return result;
243
+ }
240
244
 
241
- payload.keywords = aucKeywords;
245
+ // grab the ortb2 keyword data (if it exists) and convert from the comma list string format to object format
246
+ let ortb2 = deepClone(bidderRequest && bidderRequest.ortb2);
247
+ let ortb2KeywordsObjList = grabOrtb2Keywords(ortb2).map(keyStr => convertStringToKeywordsObj(keyStr));
248
+
249
+ let anAuctionKeywords = deepClone(config.getConfig('appnexusAuctionKeywords')) || {};
250
+ // need to convert the string values into array of strings, to properly merge values with other existing keys later
251
+ Object.keys(anAuctionKeywords).forEach(k => { if (isStr(anAuctionKeywords[k]) || isNumber(anAuctionKeywords[k])) anAuctionKeywords[k] = [anAuctionKeywords[k]] });
252
+ // combine all sources of keywords (converted from string comma list to object format) into one object (that combines the values for shared keys)
253
+ let mergedAuctionKeywrds = mergeDeep({}, anAuctionKeywords, ...ortb2KeywordsObjList);
254
+
255
+ // convert to final format used by adserver
256
+ let auctionKeywords = transformBidderParamKeywords(mergedAuctionKeywrds);
257
+ if (auctionKeywords.length > 0) {
258
+ auctionKeywords.forEach(deleteValues);
259
+ payload.keywords = auctionKeywords;
242
260
  }
243
261
 
244
262
  if (config.getConfig('adpod.brandCategoryExclusion')) {
@@ -763,13 +781,25 @@ function bidToTag(bid) {
763
781
  if (bid.params.externalImpId) {
764
782
  tag.external_imp_id = bid.params.externalImpId;
765
783
  }
766
- if (!isEmpty(bid.params.keywords)) {
767
- let keywords = transformBidderParamKeywords(bid.params.keywords);
768
784
 
769
- if (keywords.length > 0) {
770
- keywords.forEach(deleteValues);
785
+ let ortb2ImpKwStr = deepAccess(bid, 'ortb2Imp.ext.data.keywords');
786
+ if ((isStr(ortb2ImpKwStr) && ortb2ImpKwStr !== '') || !isEmpty(bid.params.keywords)) {
787
+ // convert ortb2 from comma list string format to bid param object format
788
+ let ortb2ImpKwObj = convertStringToKeywordsObj(ortb2ImpKwStr);
789
+
790
+ let bidParamsKwObj = (isPlainObject(bid.params.keywords)) ? deepClone(bid.params.keywords) : {};
791
+ // need to convert the string values into an array of strings, to properly merge values with other existing keys later
792
+ Object.keys(bidParamsKwObj).forEach(k => { if (isStr(bidParamsKwObj[k]) || isNumber(bidParamsKwObj[k])) bidParamsKwObj[k] = [bidParamsKwObj[k]] });
793
+
794
+ // combine both sources of keywords into one merged object (that combines the values for shared keys)
795
+ let keywordsObj = mergeDeep({}, bidParamsKwObj, ortb2ImpKwObj);
796
+
797
+ // convert to final format used by adserver
798
+ let keywordsUt = transformBidderParamKeywords(keywordsObj);
799
+ if (keywordsUt.length > 0) {
800
+ keywordsUt.forEach(deleteValues);
801
+ tag.keywords = keywordsUt;
771
802
  }
772
- tag.keywords = keywords;
773
803
  }
774
804
 
775
805
  let gpid = deepAccess(bid, 'ortb2Imp.ext.data.pbadslot');
@@ -1167,4 +1197,35 @@ function convertKeywordsToString(keywords) {
1167
1197
  return result;
1168
1198
  }
1169
1199
 
1200
+ // converts a comma separated list of keywords into the standard keyword object format used in appnexus bid params
1201
+ // 'genre=rock,genre=pop,pets=dog,music' goes to { 'genre': ['rock', 'pop'], 'pets': ['dog'], 'music': [''] }
1202
+ function convertStringToKeywordsObj(keyStr) {
1203
+ let result = {};
1204
+
1205
+ // will split based on commas and will eat white space before/after the comma
1206
+ let keywordList = keyStr.split(/\s*(?:,)\s*/);
1207
+ keywordList.forEach(kw => {
1208
+ // if = exists, then split
1209
+ if (kw.indexOf('=') !== -1) {
1210
+ let kwPair = kw.split('=');
1211
+ let key = kwPair[0];
1212
+ let val = kwPair[1];
1213
+
1214
+ // then check for existing key in result > if so add value to the array > if not, add new key and create value array
1215
+ if (result.hasOwnProperty(key)) {
1216
+ result[key].push(val);
1217
+ } else {
1218
+ result[key] = [val];
1219
+ }
1220
+ } else {
1221
+ // make a key with '' value; if key already exists > don't add
1222
+ if (!result.hasOwnProperty(kw)) {
1223
+ result[kw] = [''];
1224
+ }
1225
+ }
1226
+ });
1227
+
1228
+ return result;
1229
+ }
1230
+
1170
1231
  registerBidder(spec);
@@ -11,12 +11,13 @@
11
11
  * If publisher has not defined translation file than prebid will use default prebid translation file provided here //cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json
12
12
  */
13
13
 
14
- import { config } from '../src/config.js';
15
- import { setupBeforeHookFnOnce, hook } from '../src/hook.js';
16
- import { ajax } from '../src/ajax.js';
17
- import { timestamp, logError } from '../src/utils.js';
18
- import { addBidResponse } from '../src/auction.js';
19
- import { getCoreStorageManager } from '../src/storageManager.js';
14
+ import {config} from '../src/config.js';
15
+ import {hook, setupBeforeHookFnOnce} from '../src/hook.js';
16
+ import {ajax} from '../src/ajax.js';
17
+ import {logError, timestamp} from '../src/utils.js';
18
+ import {addBidResponse} from '../src/auction.js';
19
+ import {getCoreStorageManager} from '../src/storageManager.js';
20
+ import {timedBidResponseHook} from '../src/utils/perfMetrics.js';
20
21
 
21
22
  export const storage = getCoreStorageManager('categoryTranslation');
22
23
  const DEFAULT_TRANSLATION_FILE_URL = 'https://cdn.jsdelivr.net/gh/prebid/category-mapping-file@1/freewheel-mapping.json';
@@ -33,7 +34,7 @@ export const registerAdserver = hook('async', function(adServer) {
33
34
  }, 'registerAdserver');
34
35
  registerAdserver();
35
36
 
36
- export function getAdserverCategoryHook(fn, adUnitCode, bid) {
37
+ export const getAdserverCategoryHook = timedBidResponseHook('categoryTranslation', function getAdserverCategoryHook(fn, adUnitCode, bid) {
37
38
  if (!bid) {
38
39
  return fn.call(this, adUnitCode); // if no bid, call original and let it display warnings
39
40
  }
@@ -63,7 +64,7 @@ export function getAdserverCategoryHook(fn, adUnitCode, bid) {
63
64
  }
64
65
  }
65
66
  fn.call(this, adUnitCode, bid);
66
- }
67
+ });
67
68
 
68
69
  export function initTranslation(url, localStorageKey) {
69
70
  setupBeforeHookFnOnce(addBidResponse, getAdserverCategoryHook, 50);
@@ -8,6 +8,7 @@ import {isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src
8
8
  import {config} from '../src/config.js';
9
9
  import {gdprDataHandler} from '../src/adapterManager.js';
10
10
  import {includes} from '../src/polyfill.js';
11
+ import {timedAuctionHook} from '../src/utils/perfMetrics.js';
11
12
 
12
13
  const DEFAULT_CMP = 'iab';
13
14
  const DEFAULT_CONSENT_TIMEOUT = 10000;
@@ -227,7 +228,7 @@ function loadIfMissing(cb) {
227
228
  * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
228
229
  * @param {function} fn required; The next function in the chain, used by hook.js
229
230
  */
230
- export function requestBidsHook(fn, reqBidsConfigObj) {
231
+ export const requestBidsHook = timedAuctionHook('gdpr', function requestBidsHook(fn, reqBidsConfigObj) {
231
232
  loadIfMissing(function (shouldCancelAuction, errMsg, ...extraArgs) {
232
233
  if (errMsg) {
233
234
  let log = logWarn;
@@ -239,6 +240,7 @@ export function requestBidsHook(fn, reqBidsConfigObj) {
239
240
  }
240
241
 
241
242
  if (shouldCancelAuction) {
243
+ fn.stopTiming();
242
244
  if (typeof reqBidsConfigObj.bidsBackHandler === 'function') {
243
245
  reqBidsConfigObj.bidsBackHandler();
244
246
  } else {
@@ -248,7 +250,7 @@ export function requestBidsHook(fn, reqBidsConfigObj) {
248
250
  fn.call(this, reqBidsConfigObj);
249
251
  }
250
252
  });
251
- }
253
+ });
252
254
 
253
255
  /**
254
256
  * This function checks the consent data provided by CMP to ensure it's in an expected state.
@@ -4,10 +4,11 @@
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 { isFn, logInfo, logWarn, isStr, isNumber, isPlainObject, logError } from '../src/utils.js';
8
- import { config } from '../src/config.js';
9
- import { uspDataHandler } from '../src/adapterManager.js';
10
- import {getGlobal} from '../src/prebidGlobal.js';
7
+ import {isFn, isNumber, isPlainObject, isStr, logError, logInfo, logWarn} from '../src/utils.js';
8
+ import {config} from '../src/config.js';
9
+ import {uspDataHandler} from '../src/adapterManager.js';
10
+ import {timedAuctionHook} from '../src/utils/perfMetrics.js';
11
+ import {getHook} from '../src/hook.js';
11
12
 
12
13
  const DEFAULT_CONSENT_API = 'iab';
13
14
  const DEFAULT_CONSENT_TIMEOUT = 50;
@@ -18,7 +19,7 @@ export let consentTimeout = DEFAULT_CONSENT_TIMEOUT;
18
19
  export let staticConsentData;
19
20
 
20
21
  let consentData;
21
- let addedConsentHook = false;
22
+ let enabled = false;
22
23
 
23
24
  // consent APIs
24
25
  const uspCallMap = {
@@ -211,14 +212,17 @@ function loadConsentData(cb) {
211
212
  * @param {object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
212
213
  * @param {function} fn required; The next function in the chain, used by hook.js
213
214
  */
214
- export function requestBidsHook(fn, reqBidsConfigObj) {
215
+ export const requestBidsHook = timedAuctionHook('usp', function requestBidsHook(fn, reqBidsConfigObj) {
216
+ if (!enabled) {
217
+ enableConsentManagement();
218
+ }
215
219
  loadConsentData((errMsg, ...extraArgs) => {
216
220
  if (errMsg != null) {
217
221
  logWarn(errMsg, ...extraArgs);
218
222
  }
219
223
  fn.call(this, reqBidsConfigObj);
220
224
  });
221
- }
225
+ });
222
226
 
223
227
  /**
224
228
  * This function checks the consent data provided by USPAPI to ensure it's in an expected state.
@@ -257,8 +261,7 @@ export function resetConsentData() {
257
261
  consentAPI = undefined;
258
262
  consentTimeout = undefined;
259
263
  uspDataHandler.reset();
260
- getGlobal().requestBids.getHooks({hook: requestBidsHook}).remove();
261
- addedConsentHook = false;
264
+ enabled = false;
262
265
  }
263
266
 
264
267
  /**
@@ -295,13 +298,13 @@ export function setConsentConfig(config) {
295
298
  }
296
299
 
297
300
  function enableConsentManagement(configFromUser = false) {
298
- if (!addedConsentHook) {
301
+ if (!enabled) {
299
302
  logInfo(`USPAPI consentManagement module has been activated${configFromUser ? '' : ` using default values (api: '${consentAPI}', timeout: ${consentTimeout}ms)`}`);
300
- getGlobal().requestBids.before(requestBidsHook, 50);
303
+ enabled = true;
304
+ uspDataHandler.enable();
301
305
  }
302
- addedConsentHook = true;
303
- uspDataHandler.enable();
304
306
  loadConsentData(); // immediately look up consent data to make it available without requiring an auction
305
307
  }
306
308
  config.getConfig('consentManagement', config => setConsentConfig(config.consentManagement));
307
- setTimeout(() => !addedConsentHook && enableConsentManagement());
309
+
310
+ getHook('requestBids').before(requestBidsHook, 50);
@@ -47,7 +47,8 @@ export const spec = {
47
47
 
48
48
  for (var i = 0; i < validBidRequests.length; i++) {
49
49
  var bidRequest = validBidRequests[i];
50
- var referer = encodeURIComponent(bidderRequest.refererInfo.referer);
50
+ var referer = bidderRequest.refererInfo.page ? bidderRequest.refererInfo.page : bidderRequest.refererInfo.domain;
51
+ referer = encodeURIComponent(referer);
51
52
  var e = utils.getBidIdParameter('endpoint', bidRequest.params);
52
53
  var ENDPOINT = e == 'dev' ? ENDPOINT_DEV : e == 'staging' ? ENDPOINT_STAGING : ENDPOINT_PRODUCTION;
53
54
  var mediaType = spec.getMediaType(bidRequest);
@@ -6,6 +6,7 @@ import { ajax } from '../src/ajax.js';
6
6
  import { config } from '../src/config.js';
7
7
  import { getHook } from '../src/hook.js';
8
8
  import {defer} from '../src/utils/promise.js';
9
+ import {timedBidResponseHook} from '../src/utils/perfMetrics.js';
9
10
 
10
11
  const DEFAULT_CURRENCY_RATE_URL = 'https://cdn.jsdelivr.net/gh/prebid/currency-file@1/latest.json?date=$$TODAY$$';
11
12
  const CURRENCY_RATE_PRECISION = 4;
@@ -180,7 +181,7 @@ function resetCurrency() {
180
181
  bidderCurrencyDefault = {};
181
182
  }
182
183
 
183
- export function addBidResponseHook(fn, adUnitCode, bid) {
184
+ export const addBidResponseHook = timedBidResponseHook('currency', function addBidResponseHook(fn, adUnitCode, bid) {
184
185
  if (!bid) {
185
186
  return fn.call(this, adUnitCode); // if no bid, call original and let it display warnings
186
187
  }
@@ -215,9 +216,9 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
215
216
  if (!currencySupportEnabled || currencyRatesLoaded) {
216
217
  processBidResponseQueue();
217
218
  } else {
218
- fn.bail(ready.promise());
219
+ fn.untimed.bail(ready.promise());
219
220
  }
220
- }
221
+ });
221
222
 
222
223
  function processBidResponseQueue() {
223
224
  while (bidResponseQueue.length > 0) {
@@ -6,6 +6,7 @@ import {config} from '../../src/config.js';
6
6
  import {getHook, module} from '../../src/hook.js';
7
7
  import {deepAccess, deepSetValue, prefixLog} from '../../src/utils.js';
8
8
  import {startAuction} from '../../src/prebid.js';
9
+ import {timedAuctionHook} from '../../src/utils/perfMetrics.js';
9
10
 
10
11
  const LOG_PRE_FIX = 'Data_Controller : ';
11
12
  const ALL = '*';
@@ -18,7 +19,7 @@ const _logger = prefixLog(LOG_PRE_FIX);
18
19
  /**
19
20
  * BidderRequests hook to intiate module and reset data object
20
21
  */
21
- export function filterBidData(fn, req) {
22
+ export const filterBidData = timedAuctionHook('dataController', function filterBidData(fn, req) {
22
23
  if (_dataControllerConfig.filterEIDwhenSDA) {
23
24
  filterEIDs(req.adUnits, req.ortb2Fragments);
24
25
  }
@@ -28,7 +29,7 @@ export function filterBidData(fn, req) {
28
29
  }
29
30
  fn.call(this, req);
30
31
  return req;
31
- }
32
+ });
32
33
 
33
34
  function containsConfiguredEIDS(eidSourcesMap, bidderCode) {
34
35
  if (_dataControllerConfig.filterSDAwhenEID.includes(ALL)) {
@@ -111,7 +112,7 @@ function constructSegment(userData) {
111
112
  function getEIDsSource(adUnits) {
112
113
  let bidderEIDSMap = new Map();
113
114
  adUnits.forEach(adUnit => {
114
- adUnit.bids.forEach(bid => {
115
+ (adUnit.bids || []).forEach(bid => {
115
116
  let userEIDs = deepAccess(bid, 'userIdAsEids') || [];
116
117
 
117
118
  if (userEIDs) {
package/modules/dchain.js CHANGED
@@ -2,6 +2,7 @@ import {includes} from '../src/polyfill.js';
2
2
  import {config} from '../src/config.js';
3
3
  import {getHook} from '../src/hook.js';
4
4
  import {_each, deepAccess, deepClone, hasOwn, isArray, isPlainObject, isStr, logError, logWarn} from '../src/utils.js';
5
+ import {timedBidResponseHook} from '../src/utils/perfMetrics.js';
5
6
 
6
7
  const shouldBeAString = ' should be a string';
7
8
  const shouldBeAnObject = ' should be an object';
@@ -108,7 +109,7 @@ function isValidDchain(bid) {
108
109
  }
109
110
  }
110
111
 
111
- export function addBidResponseHook(fn, adUnitCode, bid) {
112
+ export const addBidResponseHook = timedBidResponseHook('dchain', function addBidResponseHook(fn, adUnitCode, bid) {
112
113
  const basicDchain = {
113
114
  ver: '1.0',
114
115
  complete: 0,
@@ -140,7 +141,7 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
140
141
  }
141
142
 
142
143
  fn(adUnitCode, bid);
143
- }
144
+ });
144
145
 
145
146
  export function init() {
146
147
  getHook('addBidResponse').before(addBidResponseHook, 35);
@@ -301,27 +301,30 @@ export const spec = {
301
301
  .filter(Boolean);
302
302
  },
303
303
  getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent) => {
304
- if (syncOptions.iframeEnabled) {
305
- // data is only assigned if params are available to pass to syncEndpoint
306
- const params = {};
307
-
308
- if (gdprConsent) {
309
- if (typeof gdprConsent.gdprApplies === 'boolean') {
310
- params['gdpr'] = Number(gdprConsent.gdprApplies);
311
- }
312
- if (typeof gdprConsent.consentString === 'string') {
313
- params['gdpr_consent'] = gdprConsent.consentString;
314
- }
304
+ const params = {};
305
+ if (gdprConsent) {
306
+ if (typeof gdprConsent.gdprApplies === 'boolean') {
307
+ params['gdpr'] = Number(gdprConsent.gdprApplies);
315
308
  }
316
-
317
- if (uspConsent) {
318
- params['us_privacy'] = encodeURIComponent(uspConsent);
309
+ if (typeof gdprConsent.consentString === 'string') {
310
+ params['gdpr_consent'] = gdprConsent.consentString;
319
311
  }
312
+ }
320
313
 
314
+ if (uspConsent) {
315
+ params['us_privacy'] = encodeURIComponent(uspConsent);
316
+ }
317
+ if (syncOptions.iframeEnabled) {
318
+ // data is only assigned if params are available to pass to syncEndpoint
321
319
  return {
322
320
  type: 'iframe',
323
321
  url: `https://${endpoint}/prebid/usersync/index.html?${formatQS(params)}`,
324
322
  };
323
+ } else if (syncOptions.pixelEnabled) {
324
+ return {
325
+ type: 'image',
326
+ url: `https://${endpoint.includes('dev') ? 'dev-' : ''}data.dianomi.com/frontend/usync?${formatQS(params)}`,
327
+ };
325
328
  }
326
329
  },
327
330
  };
@@ -3,7 +3,7 @@
3
3
  ```
4
4
  Module Name: Dianomi Bidder Adapter
5
5
  Module Type: Bidder Adapter
6
- Maintainer: eng@dianomi.com
6
+ Maintainer: prebid-maintainer@dianomi.com
7
7
  ```
8
8
 
9
9
  # Description
@@ -1,4 +1,4 @@
1
- import { deepAccess, logWarn } from '../src/utils.js';
1
+ import {deepAccess, isArray, logWarn} from '../src/utils.js';
2
2
  import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import {BANNER} from '../src/mediaTypes.js';
4
4
  import {ajax} from '../src/ajax.js';
@@ -7,7 +7,7 @@ import {ajax} from '../src/ajax.js';
7
7
  * Version of the FeedAd bid adapter
8
8
  * @type {string}
9
9
  */
10
- const VERSION = '1.0.2';
10
+ const VERSION = '1.0.3';
11
11
 
12
12
  /**
13
13
  * @typedef {object} FeedAdApiBidRequest
@@ -31,7 +31,7 @@ const VERSION = '1.0.2';
31
31
  * @typedef {object} FeedAdApiBidResponse
32
32
  * @inner
33
33
  *
34
- * @property {string} ad - Ad HTML payload
34
+ * @property {string} [ad] - Ad HTML payload
35
35
  * @property {number} cpm - number / float
36
36
  * @property {string} creativeId - ID of creative for tracking
37
37
  * @property {string} currency - 3-letter ISO 4217 currency-code
@@ -40,6 +40,7 @@ const VERSION = '1.0.2';
40
40
  * @property {string} requestId - bids[].bidId
41
41
  * @property {number} ttl - Time to live for this ad
42
42
  * @property {number} width - Width of creative returned in [].ad
43
+ * @property {object} [ext] - an extension object
43
44
  */
44
45
 
45
46
  /**
@@ -231,10 +232,16 @@ function buildRequests(validBidRequests, bidderRequest) {
231
232
  * @returns {Bid[]} the FeedAd bids
232
233
  */
233
234
  function interpretResponse(serverResponse, request) {
234
- /**
235
- * @type FeedAdApiBidResponse[]
236
- */
237
- return typeof serverResponse.body === 'string' ? JSON.parse(serverResponse.body) : serverResponse.body;
235
+ const response = typeof serverResponse.body === 'string' ? JSON.parse(serverResponse.body) : serverResponse.body;
236
+ if (!isArray(response)) {
237
+ return [];
238
+ }
239
+ return response.filter(bid => Object.prototype.hasOwnProperty.call(bid, 'ad'))
240
+ .map(bid => {
241
+ const copy = Object.assign({}, bid);
242
+ delete copy.ext;
243
+ return copy;
244
+ });
238
245
  }
239
246
 
240
247
  /**
@@ -284,6 +291,30 @@ function trackingHandlerFactory(klass) {
284
291
  }
285
292
  }
286
293
 
294
+ /**
295
+ * Reads the user syncs off the server responses and converts them into Prebid.JS format
296
+ * @param {SyncOptions} syncOptions
297
+ * @param {FeedAdApiBidResponse[]} serverResponses
298
+ * @param gdprConsent
299
+ * @param uspConsent
300
+ */
301
+ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
302
+ return serverResponses.map(response => response.ext)
303
+ .flatMap(extension => {
304
+ // extract user syncs from extension
305
+ const pixels = syncOptions.pixelEnabled && extension.pixels ? extension.pixels : [];
306
+ const iframes = syncOptions.iframeEnabled && extension.iframes ? extension.iframes : [];
307
+ return pixels.concat(...iframes);
308
+ })
309
+ .reduce((syncs, sync) => {
310
+ // remove duplicates
311
+ if (!syncs.find(it => it.type === sync.type && it.url === sync.url)) {
312
+ syncs.push(sync);
313
+ }
314
+ return syncs;
315
+ }, []);
316
+ }
317
+
287
318
  /**
288
319
  * @type {BidderSpec}
289
320
  */
@@ -295,7 +326,8 @@ export const spec = {
295
326
  buildRequests,
296
327
  interpretResponse,
297
328
  onTimeout: trackingHandlerFactory('prebid_bidTimeout'),
298
- onBidWon: trackingHandlerFactory('prebid_bidWon')
329
+ onBidWon: trackingHandlerFactory('prebid_bidWon'),
330
+ getUserSyncs
299
331
  };
300
332
 
301
333
  registerBidder(spec);
@@ -6,6 +6,7 @@ import { config } from '../../src/config.js';
6
6
  import { module, getHook } from '../../src/hook.js';
7
7
  import {logError} from '../../src/utils.js';
8
8
  import {GreedyPromise} from '../../src/utils/promise.js';
9
+ import {timedAuctionHook} from '../../src/utils/perfMetrics.js';
9
10
 
10
11
  let submodules = [];
11
12
 
@@ -35,12 +36,12 @@ export function processFpd({global = {}, bidder = {}} = {}) {
35
36
  return result;
36
37
  }
37
38
 
38
- export function startAuctionHook(fn, req) {
39
+ export const startAuctionHook = timedAuctionHook('fpd', function startAuctionHook(fn, req) {
39
40
  processFpd(req.ortb2Fragments).then((ortb2Fragments) => {
40
41
  Object.assign(req.ortb2Fragments, ortb2Fragments);
41
42
  fn.call(this, req);
42
43
  })
43
- }
44
+ });
44
45
 
45
46
  function setupHook() {
46
47
  getHook('startAuction').before(startAuctionHook, 10);
@@ -119,7 +119,7 @@ function formatTargetingData(adUnit) {
119
119
  return renameKeyValues(result);
120
120
  }
121
121
 
122
- function constructQueryString(anId, adUnits) {
122
+ function constructQueryString(anId, adUnits, pageUrl) {
123
123
  let queries = [];
124
124
  queries.push(['anId', anId]);
125
125
 
@@ -130,7 +130,7 @@ function constructQueryString(anId, adUnits) {
130
130
 
131
131
  queries.push(['wr', stringifyWindowSize()]);
132
132
  queries.push(['sr', stringifyScreenSize()]);
133
- queries.push(['url', encodeURIComponent(window.location.href)]);
133
+ queries.push(['url', encodeURIComponent(pageUrl)]);
134
134
 
135
135
  return encodeURI(queries.map(qs => qs.join('=')).join('&'));
136
136
  }
@@ -160,6 +160,16 @@ function getTargetingData(adUnits, config, userConsent) {
160
160
  return targeting;
161
161
  }
162
162
 
163
+ function isValidHttpUrl(string) {
164
+ let url;
165
+ try {
166
+ url = new URL(string);
167
+ } catch (_) {
168
+ return false;
169
+ }
170
+ return url.protocol === 'http:' || url.protocol === 'https:';
171
+ }
172
+
163
173
  export function getApiCallback() {
164
174
  return {
165
175
  success: function (response, req) {
@@ -180,7 +190,11 @@ export function getApiCallback() {
180
190
  function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) {
181
191
  const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits;
182
192
  const { pubId } = config.params;
183
- const queryString = constructQueryString(pubId, adUnits);
193
+ let { pageUrl } = config.params;
194
+ if (!isValidHttpUrl(pageUrl)) {
195
+ pageUrl = document.location.href;
196
+ }
197
+ const queryString = constructQueryString(pubId, adUnits, pageUrl);
184
198
  ajax(
185
199
  `${IAS_HOST}?${queryString}`,
186
200
  getApiCallback(),
@@ -755,14 +755,10 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
755
755
  currentImpressionSize = encodeURIComponent(JSON.stringify({ impressionObjects })).length;
756
756
  }
757
757
 
758
- let gpid = impressions[transactionIds[adUnitIndex]].gpid;
758
+ const gpid = impressions[transactionIds[adUnitIndex]].gpid;
759
759
  const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code;
760
760
  const tid = impressions[transactionIds[adUnitIndex]].tid;
761
- const divId = impressions[transactionIds[adUnitIndex]].divId;
762
761
 
763
- if (!gpid && dfpAdUnitCode && divId) {
764
- gpid = `${dfpAdUnitCode}#${divId}`;
765
- }
766
762
  if (impressionObjects.length && BANNER in impressionObjects[0]) {
767
763
  const { id, banner: { topframe } } = impressionObjects[0];
768
764
  const _bannerImpression = {
@@ -845,6 +841,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
845
841
  const pbaAdSlot = impressions[transactionIds[adUnitIndex]].pbadslot;
846
842
  const tagId = impressions[transactionIds[adUnitIndex]].tagId;
847
843
  const adUnitCode = impressions[transactionIds[adUnitIndex]].adUnitCode;
844
+ const divId = impressions[transactionIds[adUnitIndex]].divId;
848
845
  if (pbaAdSlot || tagId || adUnitCode || divId) {
849
846
  const clonedRObject = deepClone(r);
850
847
  const requestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(clonedRObject) })}`.length;