prebid.js 8.0.0 → 8.2.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 (232) 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/adtrgtmeBidAdapter.js +1 -1
  11. package/dist/adxcgBidAdapter.js +1 -1
  12. package/dist/adyoulikeBidAdapter.js +1 -1
  13. package/dist/ajaBidAdapter.js +1 -1
  14. package/dist/amxBidAdapter.js +1 -1
  15. package/dist/amxIdSystem.js +1 -1
  16. package/dist/appierAnalyticsAdapter.js +1 -1
  17. package/dist/appnexusBidAdapter.js +1 -1
  18. package/dist/asoBidAdapter.js +1 -1
  19. package/dist/axonixBidAdapter.js +1 -1
  20. package/dist/bedigitechBidAdapter.js +1 -1
  21. package/dist/beopBidAdapter.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/bidwatchAnalyticsAdapter.js +1 -1
  24. package/dist/big-richmediaBidAdapter.js +1 -1
  25. package/dist/bridBidAdapter.js +1 -0
  26. package/dist/bridgewellBidAdapter.js +1 -1
  27. package/dist/brightMountainMediaBidAdapter.js +1 -1
  28. package/dist/carodaBidAdapter.js +1 -1
  29. package/dist/categoryTranslation.js +1 -1
  30. package/dist/chtnwBidAdapter.js +1 -1
  31. package/dist/cmp.js +1 -0
  32. package/dist/colossussspBidAdapter.js +1 -1
  33. package/dist/conceptxBidAdapter.js +1 -1
  34. package/dist/concertBidAdapter.js +1 -1
  35. package/dist/connectadBidAdapter.js +1 -1
  36. package/dist/consentManagement.js +1 -1
  37. package/dist/consentManagementGpp.js +1 -1
  38. package/dist/consentManagementUsp.js +1 -1
  39. package/dist/consumableBidAdapter.js +1 -1
  40. package/dist/conversantAnalyticsAdapter.js +1 -1
  41. package/dist/conversantBidAdapter.js +1 -1
  42. package/dist/craftBidAdapter.js +1 -1
  43. package/dist/criteoBidAdapter.js +1 -1
  44. package/dist/cwireBidAdapter.js +1 -1
  45. package/dist/dependencies.json +15 -0
  46. package/dist/dspxBidAdapter.js +1 -1
  47. package/dist/eplanningBidAdapter.js +1 -1
  48. package/dist/euidIdSystem.js +1 -1
  49. package/dist/feedadBidAdapter.js +1 -1
  50. package/dist/finativeBidAdapter.js +1 -1
  51. package/dist/freepassBidAdapter.js +1 -0
  52. package/dist/freewheel-sspBidAdapter.js +1 -1
  53. package/dist/gmosspBidAdapter.js +1 -1
  54. package/dist/goldbachBidAdapter.js +1 -1
  55. package/dist/gppControl_usnat.js +1 -0
  56. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  57. package/dist/greenbidsRtdProvider.js +1 -1
  58. package/dist/gridBidAdapter.js +1 -1
  59. package/dist/gumgumBidAdapter.js +1 -1
  60. package/dist/h12mediaBidAdapter.js +1 -1
  61. package/dist/hypelabBidAdapter.js +1 -1
  62. package/dist/id5IdSystem.js +1 -1
  63. package/dist/imdsBidAdapter.js +1 -1
  64. package/dist/improvedigitalBidAdapter.js +1 -1
  65. package/dist/insticatorBidAdapter.js +1 -1
  66. package/dist/intentIqIdSystem.js +1 -1
  67. package/dist/ixBidAdapter.js +1 -1
  68. package/dist/justpremiumBidAdapter.js +1 -1
  69. package/dist/kargoBidAdapter.js +1 -1
  70. package/dist/kiviadsBidAdapter.js +1 -0
  71. package/dist/konduitAnalyticsAdapter.js +1 -1
  72. package/dist/kueezBidAdapter.js +1 -1
  73. package/dist/kueezRtbBidAdapter.js +1 -1
  74. package/dist/kulturemediaBidAdapter.js +1 -1
  75. package/dist/lassoBidAdapter.js +1 -1
  76. package/dist/lifestreetBidAdapter.js +1 -1
  77. package/dist/liveIntentIdSystem.js +1 -1
  78. package/dist/logicadBidAdapter.js +1 -1
  79. package/dist/loglyliftBidAdapter.js +1 -1
  80. package/dist/magniteAnalyticsAdapter.js +1 -1
  81. package/dist/malltvAnalyticsAdapter.js +1 -1
  82. package/dist/marsmediaBidAdapter.js +1 -1
  83. package/dist/mediafuseBidAdapter.js +1 -1
  84. package/dist/mediasquareBidAdapter.js +1 -1
  85. package/dist/mgidBidAdapter.js +1 -1
  86. package/dist/mgidXBidAdapter.js +1 -0
  87. package/dist/minutemediaBidAdapter.js +1 -1
  88. package/dist/minutemediaplusBidAdapter.js +1 -1
  89. package/dist/mspa.js +1 -0
  90. package/dist/nexx360BidAdapter.js +1 -1
  91. package/dist/not-for-prod/prebid.js +146 -139
  92. package/dist/oguryBidAdapter.js +1 -1
  93. package/dist/onetagBidAdapter.js +1 -1
  94. package/dist/ooloAnalyticsAdapter.js +1 -1
  95. package/dist/optidigitalBidAdapter.js +1 -1
  96. package/dist/outbrainBidAdapter.js +1 -1
  97. package/dist/oxxionAnalyticsAdapter.js +1 -1
  98. package/dist/oxxionRtdProvider.js +1 -1
  99. package/dist/parrableIdSystem.js +1 -1
  100. package/dist/pixfutureBidAdapter.js +1 -1
  101. package/dist/prebid-core.js +1 -1
  102. package/dist/publinkIdSystem.js +1 -1
  103. package/dist/pubmaticBidAdapter.js +1 -1
  104. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  105. package/dist/pxyzBidAdapter.js +1 -1
  106. package/dist/quantcastBidAdapter.js +1 -1
  107. package/dist/readpeakBidAdapter.js +1 -1
  108. package/dist/relaidoBidAdapter.js +1 -1
  109. package/dist/retailspotBidAdapter.js +1 -1
  110. package/dist/rhythmoneBidAdapter.js +1 -1
  111. package/dist/riseBidAdapter.js +1 -1
  112. package/dist/rtbhouseBidAdapter.js +1 -1
  113. package/dist/rubiconBidAdapter.js +1 -1
  114. package/dist/seedingAllianceBidAdapter.js +1 -1
  115. package/dist/seedtagBidAdapter.js +1 -1
  116. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  117. package/dist/sharethroughBidAdapter.js +1 -1
  118. package/dist/shinezBidAdapter.js +1 -1
  119. package/dist/smaatoBidAdapter.js +1 -1
  120. package/dist/smartadserverBidAdapter.js +1 -1
  121. package/dist/smartxBidAdapter.js +1 -1
  122. package/dist/smilewantedBidAdapter.js +1 -1
  123. package/dist/sonobiBidAdapter.js +1 -1
  124. package/dist/sovrnAnalyticsAdapter.js +1 -1
  125. package/dist/sovrnBidAdapter.js +1 -1
  126. package/dist/sspBCBidAdapter.js +1 -1
  127. package/dist/stvBidAdapter.js +1 -1
  128. package/dist/sublimeBidAdapter.js +1 -1
  129. package/dist/targetVideoBidAdapter.js +1 -1
  130. package/dist/teadsBidAdapter.js +1 -1
  131. package/dist/trionBidAdapter.js +1 -1
  132. package/dist/tripleliftBidAdapter.js +1 -1
  133. package/dist/ttdBidAdapter.js +1 -1
  134. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  135. package/dist/uid2IdSystem.js +1 -1
  136. package/dist/underdogmediaBidAdapter.js +1 -1
  137. package/dist/undertoneBidAdapter.js +1 -1
  138. package/dist/userId.js +1 -1
  139. package/dist/vidazooBidAdapter.js +1 -1
  140. package/dist/videobyteBidAdapter.js +1 -1
  141. package/dist/visxBidAdapter.js +1 -1
  142. package/dist/vuukleBidAdapter.js +1 -1
  143. package/dist/widespaceBidAdapter.js +1 -1
  144. package/dist/winrBidAdapter.js +1 -1
  145. package/dist/yahoosspBidAdapter.js +1 -1
  146. package/dist/yieldmoBidAdapter.js +1 -1
  147. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  148. package/libraries/cmp/cmpClient.js +139 -0
  149. package/libraries/mspa/activityControls.js +91 -0
  150. package/modules/admanBidAdapter.js +5 -0
  151. package/modules/amxBidAdapter.js +11 -12
  152. package/modules/bedigitechBidAdapter.js +15 -12
  153. package/modules/bedigitechBidAdapter.md +2 -2
  154. package/modules/beopBidAdapter.js +0 -4
  155. package/modules/bidwatchAnalyticsAdapter.js +33 -5
  156. package/modules/bridBidAdapter.js +223 -0
  157. package/modules/categoryTranslation.js +3 -2
  158. package/modules/colossussspBidAdapter.js +9 -0
  159. package/modules/conceptxBidAdapter.js +6 -3
  160. package/modules/consentManagement.js +12 -86
  161. package/modules/consentManagementGpp.js +47 -126
  162. package/modules/consentManagementUsp.js +19 -97
  163. package/modules/freepassBidAdapter.js +98 -0
  164. package/modules/freepassBidAdapter.md +31 -0
  165. package/modules/freepassIdSystem.md +1 -1
  166. package/modules/gppControl_usnat.js +11 -0
  167. package/modules/greenbidsAnalyticsAdapter.js +7 -13
  168. package/modules/gridBidAdapter.js +3 -4
  169. package/modules/intentIqIdSystem.js +11 -9
  170. package/modules/ixBidAdapter.js +284 -55
  171. package/modules/kiviadsBidAdapter.js +212 -0
  172. package/modules/kiviadsBidAdapter.md +79 -0
  173. package/modules/liveIntentIdSystem.js +8 -3
  174. package/modules/mediasquareBidAdapter.js +19 -23
  175. package/modules/mgidXBidAdapter.js +263 -0
  176. package/modules/mgidXBidAdapter.md +79 -0
  177. package/modules/oxxionAnalyticsAdapter.js +33 -5
  178. package/modules/oxxionRtdProvider.js +124 -11
  179. package/modules/oxxionRtdProvider.md +19 -4
  180. package/modules/pubmaticBidAdapter.js +18 -2
  181. package/modules/rtbhouseBidAdapter.js +9 -2
  182. package/modules/rtbhouseBidAdapter.md +27 -8
  183. package/modules/rubiconBidAdapter.js +13 -1
  184. package/modules/sharethroughBidAdapter.js +14 -0
  185. package/modules/sonobiBidAdapter.js +4 -7
  186. package/modules/tripleliftBidAdapter.js +21 -1
  187. package/modules/userId/eids.js +29 -0
  188. package/modules/userId/eids.md +19 -2
  189. package/modules/userId/index.js +78 -29
  190. package/modules/userId/userId.md +3 -0
  191. package/package.json +1 -1
  192. package/src/activities/params.js +4 -1
  193. package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
  194. package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
  195. package/test/spec/modules/admanBidAdapter_spec.js +8 -2
  196. package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
  197. package/test/spec/modules/amxBidAdapter_spec.js +6 -3
  198. package/test/spec/modules/bedigitechBidAdapter_spec.js +25 -36
  199. package/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +21 -1
  200. package/test/spec/modules/bridBidAdapter_spec.js +129 -0
  201. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
  202. package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
  203. package/test/spec/modules/colossussspBidAdapter_spec.js +29 -0
  204. package/test/spec/modules/consentManagementGpp_spec.js +84 -7
  205. package/test/spec/modules/consentManagement_spec.js +8 -18
  206. package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
  207. package/test/spec/modules/eids_spec.js +87 -0
  208. package/test/spec/modules/freepassBidAdapter_spec.js +161 -0
  209. package/test/spec/modules/greenbidsAnalyticsAdapter_spec.js +0 -15
  210. package/test/spec/modules/gridBidAdapter_spec.js +29 -28
  211. package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
  212. package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
  213. package/test/spec/modules/ixBidAdapter_spec.js +785 -15
  214. package/test/spec/modules/kiviadsBidAdapter_spec.js +404 -0
  215. package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
  216. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
  217. package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
  218. package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
  219. package/test/spec/modules/mgidXBidAdapter_spec.js +426 -0
  220. package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
  221. package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
  222. package/test/spec/modules/oxxionAnalyticsAdapter_spec.js +21 -2
  223. package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
  224. package/test/spec/modules/pubmaticBidAdapter_spec.js +25 -0
  225. package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
  226. package/test/spec/modules/rtbhouseBidAdapter_spec.js +35 -0
  227. package/test/spec/modules/rubiconBidAdapter_spec.js +41 -0
  228. package/test/spec/modules/sharethroughBidAdapter_spec.js +75 -0
  229. package/test/spec/modules/sonobiBidAdapter_spec.js +15 -15
  230. package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
  231. package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
  232. package/test/spec/modules/userId_spec.js +393 -6
@@ -104,7 +104,9 @@ let hasRegisteredHandler = false;
104
104
  export const storage = getStorageManager({ bidderCode: BIDDER_CODE });
105
105
  export const FEATURE_TOGGLES = {
106
106
  // Update with list of CFTs to be requested from Exchange
107
- REQUESTED_FEATURE_TOGGLES: [],
107
+ REQUESTED_FEATURE_TOGGLES: [
108
+ 'pbjs_enable_multiformat'
109
+ ],
108
110
 
109
111
  featureToggles: {},
110
112
  isFeatureEnabled: function (ft) {
@@ -183,7 +185,7 @@ function bidToBannerImp(bid) {
183
185
  * @param {object} bid A valid bid request config object.
184
186
  * @return {object} A impression object that will be sent to ad server.
185
187
  */
186
- function bidToVideoImp(bid) {
188
+ export function bidToVideoImp(bid) {
187
189
  const imp = bidToImp(bid, VIDEO);
188
190
  const videoAdUnitRef = deepAccess(bid, 'mediaTypes.video');
189
191
  const videoParamRef = deepAccess(bid, 'params.video');
@@ -266,7 +268,7 @@ function verifyVideoPlcmt(imp) {
266
268
  * @param {object} bid A valid bid request config object.
267
269
  * @return {object} A impression object that will be sent to ad server.
268
270
  */
269
- function bidToNativeImp(bid) {
271
+ export function bidToNativeImp(bid) {
270
272
  const imp = bidToImp(bid, NATIVE);
271
273
 
272
274
  const request = bid.nativeOrtbRequest
@@ -364,14 +366,30 @@ function _applyFloor(bid, imp, mediaType) {
364
366
  }
365
367
 
366
368
  // Prioritize module floor over bidder.param floor
369
+ let setFloor = false;
367
370
  if (moduleFloor) {
368
371
  imp.bidfloor = moduleFloor.floor;
369
372
  imp.bidfloorcur = moduleFloor.currency;
370
373
  imp.ext.fl = FLOOR_SOURCE.PBJS;
374
+ setFloor = true;
371
375
  } else if (adapterFloor) {
372
376
  imp.bidfloor = adapterFloor.floor;
373
377
  imp.bidfloorcur = adapterFloor.currency;
374
378
  imp.ext.fl = FLOOR_SOURCE.IX;
379
+ setFloor = true;
380
+ }
381
+
382
+ if (setFloor) {
383
+ if (mediaType == BANNER) {
384
+ deepSetValue(imp, 'banner.ext.bidfloor', imp.bidfloor);
385
+ deepSetValue(imp, 'banner.ext.fl', imp.ext.fl);
386
+ } else if (mediaType == VIDEO) {
387
+ deepSetValue(imp, 'video.ext.bidfloor', imp.bidfloor);
388
+ deepSetValue(imp, 'video.ext.fl', imp.ext.fl);
389
+ } else {
390
+ deepSetValue(imp, 'native.ext.bidfloor', imp.bidfloor);
391
+ deepSetValue(imp, 'native.ext.fl', imp.ext.fl);
392
+ }
375
393
  }
376
394
  }
377
395
 
@@ -512,7 +530,6 @@ function checkVideoParams(mediaTypeVideoRef, paramsVideoRef) {
512
530
  if (!(protocolMediaType || protocolsMediaType || protocolVideoRef || protocolsVideoRef)) {
513
531
  errorList.push('IX Bid Adapter: protocol/protcols is not included in either the adunit or params level');
514
532
  }
515
-
516
533
  return errorList;
517
534
  }
518
535
 
@@ -680,6 +697,9 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
680
697
 
681
698
  const isLastAdUnit = adUnitIndex === impKeys.length - 1;
682
699
 
700
+ r = deduplicateImpExtFields(r);
701
+ r = removeSiteIDs(r);
702
+
683
703
  if (isLastAdUnit) {
684
704
  requests.push({
685
705
  method: 'POST',
@@ -889,63 +909,115 @@ function addImpressions(impressions, impKeys, r, adUnitIndex) {
889
909
  const gpid = impressions[impKeys[adUnitIndex]].gpid;
890
910
  const dfpAdUnitCode = impressions[impKeys[adUnitIndex]].dfp_ad_unit_code;
891
911
  const tid = impressions[impKeys[adUnitIndex]].tid;
892
- const sid = impressions[impKeys[adUnitIndex]].sid
893
-
894
- if (impressionObjects.length && BANNER in impressionObjects[0]) {
895
- const { id, banner: { topframe } } = impressionObjects[0];
896
- const _bannerImpression = {
897
- id,
898
- banner: {
899
- topframe,
900
- format: impressionObjects.map(({ banner: { w, h }, ext }) => ({ w, h, ext }))
901
- },
902
- };
903
-
904
- for (let i = 0; i < _bannerImpression.banner.format.length; i++) {
905
- // We add sid in imp.ext.sid therefore, remove from banner.format[].ext
906
- if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) {
907
- delete _bannerImpression.banner.format[i].ext.sid;
912
+ const sid = impressions[impKeys[adUnitIndex]].sid;
913
+ const bannerImpressions = impressionObjects.filter(impression => BANNER in impression);
914
+ const otherImpressions = impressionObjects.filter(impression => !(BANNER in impression));
915
+
916
+ if (bannerImpressions.length > 0) {
917
+ const bannerImpsKeyed = bannerImpressions.reduce((acc, bannerImp) => {
918
+ if (!acc[bannerImp.id]) {
919
+ acc[bannerImp.id] = []
908
920
  }
921
+ acc[bannerImp.id].push(bannerImp);
922
+ return acc;
923
+ }, {});
924
+ for (const impId in bannerImpsKeyed) {
925
+ const bannerImps = bannerImpsKeyed[impId];
926
+ const { id, banner: { topframe } } = bannerImps[0];
927
+ const _bannerImpression = {
928
+ id,
929
+ banner: {
930
+ topframe,
931
+ format: bannerImps.map(({ banner: { w, h }, ext }) => ({ w, h, ext }))
932
+ },
933
+ };
934
+
935
+ for (let i = 0; i < _bannerImpression.banner.format.length; i++) {
936
+ // We add sid in imp.ext.sid therefore, remove from banner.format[].ext
937
+ if (_bannerImpression.banner.format[i].ext != null && _bannerImpression.banner.format[i].ext.sid != null) {
938
+ delete _bannerImpression.banner.format[i].ext.sid;
939
+ }
909
940
 
910
- // add floor per size
911
- if ('bidfloor' in impressionObjects[i]) {
912
- _bannerImpression.banner.format[i].ext.bidfloor = impressionObjects[i].bidfloor;
941
+ // add floor per size
942
+ if ('bidfloor' in bannerImps[i]) {
943
+ _bannerImpression.banner.format[i].ext.bidfloor = bannerImps[i].bidfloor;
944
+ }
913
945
  }
914
- }
915
946
 
916
- const position = impressions[impKeys[adUnitIndex]].pos;
917
- if (isInteger(position)) {
918
- _bannerImpression.banner.pos = position;
919
- }
947
+ const position = impressions[impKeys[adUnitIndex]].pos;
948
+ if (isInteger(position)) {
949
+ _bannerImpression.banner.pos = position;
950
+ }
920
951
 
921
- if (dfpAdUnitCode || gpid || tid || sid) {
922
- _bannerImpression.ext = {};
923
- _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode;
924
- _bannerImpression.ext.gpid = gpid;
925
- _bannerImpression.ext.tid = tid;
926
- _bannerImpression.ext.sid = sid;
927
- }
952
+ if (dfpAdUnitCode || gpid || tid || sid) {
953
+ _bannerImpression.ext = {};
954
+ _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode;
955
+ _bannerImpression.ext.gpid = gpid;
956
+ _bannerImpression.ext.tid = tid;
957
+ _bannerImpression.ext.sid = sid;
958
+ }
928
959
 
929
- if ('bidfloor' in impressionObjects[0]) {
930
- _bannerImpression.bidfloor = impressionObjects[0].bidfloor;
931
- }
960
+ if ('bidfloor' in bannerImps[0]) {
961
+ _bannerImpression.bidfloor = bannerImps[0].bidfloor;
962
+ }
932
963
 
933
- if ('bidfloorcur' in impressionObjects[0]) {
934
- _bannerImpression.bidfloorcur = impressionObjects[0].bidfloorcur;
935
- }
964
+ if ('bidfloorcur' in bannerImps[0]) {
965
+ _bannerImpression.bidfloorcur = bannerImps[0].bidfloorcur;
966
+ }
936
967
 
937
- const adUnitFPD = impressions[impKeys[adUnitIndex]].adUnitFPD
938
- if (adUnitFPD) {
939
- _bannerImpression.ext.data = adUnitFPD;
968
+ const adUnitFPD = impressions[impKeys[adUnitIndex]].adUnitFPD
969
+ if (adUnitFPD) {
970
+ deepSetValue(_bannerImpression, 'ext.data', adUnitFPD);
971
+ }
972
+ r.imp.push(_bannerImpression);
940
973
  }
941
-
942
- r.imp.push(_bannerImpression);
943
- } else {
944
- // set imp.ext.gpid to resolved gpid for each imp
945
- impressionObjects.forEach(imp => deepSetValue(imp, 'ext.gpid', gpid));
946
- r.imp.push(...impressionObjects);
947
974
  }
948
-
975
+ if (otherImpressions.length > 0) {
976
+ // Creates multiformat imp if they have the same ID
977
+ // if not same ID, just add the imp to the imp array
978
+ // Removes imp.ext.bidfloor
979
+ // Sets imp.ext.siteID to one of the other [video/native].ext.siteid if imp.ext.siteID doesnt exist
980
+ otherImpressions.forEach(imp => {
981
+ deepSetValue(imp, 'ext.gpid', gpid);
982
+ if (r.imp.length > 0) {
983
+ let matchFound = false;
984
+ r.imp.forEach((rImp, index) => {
985
+ if (imp.id === rImp.id && VIDEO in imp) {
986
+ rImp.video = imp.video;
987
+ rImp.video.ext = Object.assign({}, imp.video.ext, imp.ext);
988
+ if (deepAccess(rImp, 'video.ext.bidfloor', false) && deepAccess(rImp, 'bidfloor', false)) {
989
+ if (rImp.video.ext.bidfloor < rImp.bidfloor) {
990
+ rImp.bidfloor = rImp.video.ext.bidfloor;
991
+ }
992
+ }
993
+ if (!deepAccess(rImp, 'ext.siteID', false) && deepAccess(imp, 'video.ext.siteID')) {
994
+ deepSetValue(rImp, 'ext.siteID', imp.video.ext.siteID);
995
+ deepSetValue(r, 'ext.ixdiag.usid', true);
996
+ }
997
+ matchFound = true;
998
+ } else if (imp.id === rImp.id && NATIVE in imp) {
999
+ rImp.native = imp.native;
1000
+ rImp.native.ext = Object.assign({}, imp.native.ext, imp.ext);
1001
+ if (deepAccess(rImp, 'native.ext.bidfloor', false) && deepAccess(rImp, 'bidfloor', false)) {
1002
+ if (rImp.native.ext.bidfloor < rImp.bidfloor) {
1003
+ rImp.bidfloor = rImp.native.ext.bidfloor;
1004
+ }
1005
+ }
1006
+ if (!deepAccess(rImp, 'ext.siteID', false) && deepAccess(imp, 'native.ext.siteID', false)) {
1007
+ deepSetValue(rImp, 'ext.siteID', imp.native.ext.siteID);
1008
+ deepSetValue(r, 'ext.ixdiag.usid', true);
1009
+ }
1010
+ matchFound = true;
1011
+ }
1012
+ });
1013
+ if (!matchFound) {
1014
+ r.imp.push(imp);
1015
+ }
1016
+ } else {
1017
+ r.imp.push(imp);
1018
+ }
1019
+ });
1020
+ }
949
1021
  return r;
950
1022
  }
951
1023
 
@@ -1642,17 +1714,31 @@ export const spec = {
1642
1714
  }
1643
1715
  }
1644
1716
 
1645
- // Step 4: Build banner, video & native requests
1717
+ // Step 3: Build banner, video & native requests
1718
+ let allImps = [];
1646
1719
  if (Object.keys(bannerImps).length > 0) {
1647
- reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION));
1720
+ allImps.push(bannerImps);
1648
1721
  }
1649
1722
  if (Object.keys(videoImps).length > 0) {
1650
- reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION));
1723
+ allImps.push(videoImps);
1651
1724
  }
1652
1725
  if (Object.keys(nativeImps).length > 0) {
1653
- reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps));
1726
+ allImps.push(nativeImps);
1654
1727
  }
1655
1728
 
1729
+ if (FEATURE_TOGGLES.isFeatureEnabled('pbjs_enable_multiformat')) {
1730
+ reqs.push(...buildRequest(validBidRequests, bidderRequest, combineImps(allImps)));
1731
+ } else {
1732
+ if (Object.keys(bannerImps).length > 0) {
1733
+ reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION));
1734
+ }
1735
+ if (Object.keys(videoImps).length > 0) {
1736
+ reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION));
1737
+ }
1738
+ if (Object.keys(nativeImps).length > 0) {
1739
+ reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps));
1740
+ }
1741
+ }
1656
1742
  return reqs;
1657
1743
  },
1658
1744
 
@@ -1788,4 +1874,147 @@ function buildImgSyncUrl(syncsPerBidder, index) {
1788
1874
  return IMG_USER_SYNC_URL + '&site_id=' + siteID.toString() + '&p=' + syncsPerBidder.toString() + '&i=' + index.toString() + '&gdpr=' + gdprApplies + '&gdpr_consent=' + consentString + '&us_privacy=' + (usPrivacy || '');
1789
1875
  }
1790
1876
 
1877
+ /**
1878
+ * Combines all imps into a single object
1879
+ * @param {array} imps array of imps
1880
+ * @returns object
1881
+ */
1882
+ export function combineImps(imps) {
1883
+ const result = {}
1884
+ imps.forEach((imp) => {
1885
+ Object.keys(imp).forEach((key) => {
1886
+ if (Object.keys(result).includes(key)) {
1887
+ if (result[key].hasOwnProperty('ixImps') && imp[key].hasOwnProperty('ixImps')) {
1888
+ result[key].ixImps = [...result[key].ixImps, ...imp[key].ixImps];
1889
+ } else if (result[key].hasOwnProperty('missingImps') && imp[key].hasOwnProperty('missingImps')) {
1890
+ result[key].missingImps = [...result[key].missingImps, ...imp[key].missingImps];
1891
+ } else if (imp[key].hasOwnProperty('ixImps')) {
1892
+ result[key].ixImps = imp[key].ixImps;
1893
+ } else if (imp[key].hasOwnProperty('missingImps')) {
1894
+ result[key].missingImps = imp[key].missingImps
1895
+ }
1896
+ } else {
1897
+ result[key] = imp[key];
1898
+ }
1899
+ });
1900
+ });
1901
+ return result;
1902
+ }
1903
+
1904
+ /**
1905
+ * Deduplicates ext fields. For example if imp.ext.tid exists, removes imp.banner.ext.tid
1906
+ *
1907
+ * @param {object} r request object
1908
+ * @returns object
1909
+ */
1910
+ export function deduplicateImpExtFields(r) {
1911
+ r.imp.forEach((imp, index) => {
1912
+ const impExt = imp.ext;
1913
+ if (impExt == undefined) {
1914
+ return r;
1915
+ }
1916
+ if (getFormatCount(imp) < 2) {
1917
+ return;
1918
+ }
1919
+ Object.keys(impExt).forEach((key) => {
1920
+ if (BANNER in imp) {
1921
+ const bannerExt = imp.banner.ext;
1922
+ if (bannerExt !== undefined && bannerExt[key] !== undefined && bannerExt[key] == impExt[key]) {
1923
+ delete r.imp[index].banner.ext[key];
1924
+ }
1925
+ if (imp.banner.format !== undefined) {
1926
+ for (let i = 0; i < imp.banner.format.length; i++) {
1927
+ if (imp.banner.format[i].ext != undefined && imp.banner.format[i].ext[key] != undefined && imp.banner.format[i].ext[key] == impExt[key]) {
1928
+ delete r.imp[index].banner.format[i].ext[key];
1929
+ }
1930
+ }
1931
+ }
1932
+ }
1933
+ if (VIDEO in imp) {
1934
+ const videoExt = imp.video.ext;
1935
+ if (videoExt !== undefined && videoExt[key] !== undefined && videoExt[key] == impExt[key]) {
1936
+ delete r.imp[index].video.ext[key];
1937
+ }
1938
+ }
1939
+
1940
+ if (NATIVE in imp) {
1941
+ const nativeExt = imp.native.ext;
1942
+ if (nativeExt !== undefined && nativeExt[key] !== undefined && nativeExt[key] == impExt[key]) {
1943
+ delete r.imp[index].native.ext[key];
1944
+ }
1945
+ }
1946
+ });
1947
+ });
1948
+ return r;
1949
+ }
1950
+
1951
+ /**
1952
+ * Removes ext.siteids in multiformat scenario
1953
+ * Site id will be set only at imp.ext.siteId
1954
+ *
1955
+ * @param {object} r request object
1956
+ * @returns object
1957
+ */
1958
+ export function removeSiteIDs(r) {
1959
+ r.imp.forEach((imp, index) => {
1960
+ const impExt = imp.ext;
1961
+ if (impExt == undefined) {
1962
+ return r;
1963
+ }
1964
+ if (getFormatCount(imp) < 2) {
1965
+ return;
1966
+ }
1967
+
1968
+ if (BANNER in imp) {
1969
+ const bannerExt = imp.banner.ext;
1970
+ if (bannerExt !== undefined && bannerExt.siteID !== undefined) {
1971
+ delete r.imp[index].banner.ext.siteID;
1972
+ }
1973
+ if (imp.banner.format !== undefined) {
1974
+ for (let i = 0; i < imp.banner.format.length; i++) {
1975
+ if (imp.banner.format[i].ext !== undefined && imp.banner.format[i].ext.siteID !== undefined) {
1976
+ deepSetValue(r.imp[index], 'ext.siteID', imp.banner.format[i].ext.siteID);
1977
+ deepSetValue(r, 'ext.ixdiag.usid', true);
1978
+ delete r.imp[index].banner.format[i].ext.siteID;
1979
+ }
1980
+ }
1981
+ }
1982
+ }
1983
+
1984
+ if (VIDEO in imp) {
1985
+ const videoExt = imp.video.ext;
1986
+ if (videoExt !== undefined && videoExt.siteID !== undefined) {
1987
+ delete r.imp[index].video.ext.siteID;
1988
+ }
1989
+ }
1990
+
1991
+ if (NATIVE in imp) {
1992
+ const nativeExt = imp.native.ext;
1993
+ if (nativeExt !== undefined && nativeExt.siteID !== undefined) {
1994
+ delete r.imp[index].native.ext.siteID;
1995
+ }
1996
+ }
1997
+ });
1998
+ return r;
1999
+ }
2000
+
2001
+ /**
2002
+ * Gets count of banner/video/native formats in imp
2003
+ * @param {object} imp
2004
+ * @returns int
2005
+ */
2006
+ function getFormatCount(imp) {
2007
+ let formatCount = 0;
2008
+ if (imp.banner !== undefined) {
2009
+ formatCount += 1;
2010
+ }
2011
+ if (imp.video !== undefined) {
2012
+ formatCount += 1;
2013
+ }
2014
+ if (imp.native !== undefined) {
2015
+ formatCount += 1;
2016
+ }
2017
+ return formatCount;
2018
+ }
2019
+
1791
2020
  registerBidder(spec);
@@ -0,0 +1,212 @@
1
+ import { isFn, deepAccess, logMessage, logError } from '../src/utils.js';
2
+ import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
3
+
4
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
5
+ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
6
+ import { config } from '../src/config.js';
7
+
8
+ const BIDDER_CODE = 'kiviads';
9
+ const AD_URL = 'https://lb.kiviads.com/pbjs';
10
+ const SYNC_URL = 'https://sync.kiviads.com';
11
+
12
+ function isBidResponseValid(bid) {
13
+ if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) {
14
+ return false;
15
+ }
16
+
17
+ switch (bid.mediaType) {
18
+ case BANNER:
19
+ return Boolean(bid.width && bid.height && bid.ad);
20
+ case VIDEO:
21
+ return Boolean(bid.vastUrl || bid.vastXml);
22
+ case NATIVE:
23
+ return Boolean(bid.native && bid.native.impressionTrackers && bid.native.impressionTrackers.length);
24
+ default:
25
+ return false;
26
+ }
27
+ }
28
+
29
+ function getPlacementReqData(bid) {
30
+ const { params, bidId, mediaTypes } = bid;
31
+ const schain = bid.schain || {};
32
+ const { placementId, endpointId } = params;
33
+ const bidfloor = getBidFloor(bid);
34
+
35
+ const placement = {
36
+ bidId,
37
+ schain,
38
+ bidfloor
39
+ };
40
+
41
+ if (placementId) {
42
+ placement.placementId = placementId;
43
+ placement.type = 'publisher';
44
+ } else if (endpointId) {
45
+ placement.endpointId = endpointId;
46
+ placement.type = 'network';
47
+ }
48
+
49
+ if (mediaTypes && mediaTypes[BANNER]) {
50
+ placement.adFormat = BANNER;
51
+ placement.sizes = mediaTypes[BANNER].sizes;
52
+ } else if (mediaTypes && mediaTypes[VIDEO]) {
53
+ placement.adFormat = VIDEO;
54
+ placement.playerSize = mediaTypes[VIDEO].playerSize;
55
+ placement.minduration = mediaTypes[VIDEO].minduration;
56
+ placement.maxduration = mediaTypes[VIDEO].maxduration;
57
+ placement.mimes = mediaTypes[VIDEO].mimes;
58
+ placement.protocols = mediaTypes[VIDEO].protocols;
59
+ placement.startdelay = mediaTypes[VIDEO].startdelay;
60
+ placement.placement = mediaTypes[VIDEO].placement;
61
+ placement.skip = mediaTypes[VIDEO].skip;
62
+ placement.skipafter = mediaTypes[VIDEO].skipafter;
63
+ placement.minbitrate = mediaTypes[VIDEO].minbitrate;
64
+ placement.maxbitrate = mediaTypes[VIDEO].maxbitrate;
65
+ placement.delivery = mediaTypes[VIDEO].delivery;
66
+ placement.playbackmethod = mediaTypes[VIDEO].playbackmethod;
67
+ placement.api = mediaTypes[VIDEO].api;
68
+ placement.linearity = mediaTypes[VIDEO].linearity;
69
+ } else if (mediaTypes && mediaTypes[NATIVE]) {
70
+ placement.native = mediaTypes[NATIVE];
71
+ placement.adFormat = NATIVE;
72
+ }
73
+
74
+ return placement;
75
+ }
76
+
77
+ function getBidFloor(bid) {
78
+ if (!isFn(bid.getFloor)) {
79
+ return deepAccess(bid, 'params.bidfloor', 0);
80
+ }
81
+
82
+ try {
83
+ const bidFloor = bid.getFloor({
84
+ currency: 'USD',
85
+ mediaType: '*',
86
+ size: '*',
87
+ });
88
+ return bidFloor.floor;
89
+ } catch (err) {
90
+ logError(err);
91
+ return 0;
92
+ }
93
+ }
94
+
95
+ export const spec = {
96
+ code: BIDDER_CODE,
97
+ supportedMediaTypes: [BANNER, VIDEO, NATIVE],
98
+
99
+ isBidRequestValid: (bid = {}) => {
100
+ const { params, bidId, mediaTypes } = bid;
101
+ let valid = Boolean(bidId && params && (params.placementId || params.endpointId));
102
+
103
+ if (mediaTypes && mediaTypes[BANNER]) {
104
+ valid = valid && Boolean(mediaTypes[BANNER] && mediaTypes[BANNER].sizes);
105
+ } else if (mediaTypes && mediaTypes[VIDEO]) {
106
+ valid = valid && Boolean(mediaTypes[VIDEO] && mediaTypes[VIDEO].playerSize);
107
+ } else if (mediaTypes && mediaTypes[NATIVE]) {
108
+ valid = valid && Boolean(mediaTypes[NATIVE]);
109
+ } else {
110
+ valid = false;
111
+ }
112
+ return valid;
113
+ },
114
+
115
+ buildRequests: (validBidRequests = [], bidderRequest = {}) => {
116
+ // convert Native ORTB definition to old-style prebid native definition
117
+ validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
118
+
119
+ let deviceWidth = 0;
120
+ let deviceHeight = 0;
121
+
122
+ let winLocation;
123
+ try {
124
+ const winTop = window.top;
125
+ deviceWidth = winTop.screen.width;
126
+ deviceHeight = winTop.screen.height;
127
+ winLocation = winTop.location;
128
+ } catch (e) {
129
+ logMessage(e);
130
+ winLocation = window.location;
131
+ }
132
+
133
+ const refferUrl = bidderRequest.refererInfo && bidderRequest.refererInfo.page;
134
+ let refferLocation;
135
+ try {
136
+ refferLocation = refferUrl && new URL(refferUrl);
137
+ } catch (e) {
138
+ logMessage(e);
139
+ }
140
+ let location = refferLocation || winLocation;
141
+ const language = (navigator && navigator.language) ? navigator.language.split('-')[0] : '';
142
+ const host = location.host;
143
+ const page = location.pathname;
144
+ const secure = location.protocol === 'https:' ? 1 : 0;
145
+ const placements = [];
146
+ const request = {
147
+ deviceWidth,
148
+ deviceHeight,
149
+ language,
150
+ secure,
151
+ host,
152
+ page,
153
+ placements,
154
+ coppa: bidderRequest.coppa === true ? 1 : 0,
155
+ ccpa: bidderRequest.uspConsent || undefined,
156
+ gdpr: bidderRequest.gdprConsent || undefined,
157
+ gpp: bidderRequest.gppConsent || undefined,
158
+ tmax: bidderRequest.bidderTimeout
159
+ };
160
+
161
+ const len = validBidRequests.length;
162
+ for (let i = 0; i < len; i++) {
163
+ const bid = validBidRequests[i];
164
+ placements.push(getPlacementReqData(bid));
165
+ }
166
+
167
+ return {
168
+ method: 'POST',
169
+ url: AD_URL,
170
+ data: request
171
+ };
172
+ },
173
+
174
+ interpretResponse: (serverResponse) => {
175
+ let response = [];
176
+ for (let i = 0; i < serverResponse.body.length; i++) {
177
+ let resItem = serverResponse.body[i];
178
+ if (isBidResponseValid(resItem)) {
179
+ const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : [];
180
+ resItem.meta = { ...resItem.meta, advertiserDomains };
181
+
182
+ response.push(resItem);
183
+ }
184
+ }
185
+ return response;
186
+ },
187
+
188
+ getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => {
189
+ let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image';
190
+ let syncUrl = SYNC_URL + `/${syncType}?pbjs=1`;
191
+ if (gdprConsent && gdprConsent.consentString) {
192
+ if (typeof gdprConsent.gdprApplies === 'boolean') {
193
+ syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
194
+ } else {
195
+ syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`;
196
+ }
197
+ }
198
+ if (uspConsent && uspConsent.consentString) {
199
+ syncUrl += `&ccpa_consent=${uspConsent.consentString}`;
200
+ }
201
+
202
+ const coppa = config.getConfig('coppa') ? 1 : 0;
203
+ syncUrl += `&coppa=${coppa}`;
204
+
205
+ return [{
206
+ type: syncType,
207
+ url: syncUrl
208
+ }];
209
+ }
210
+ };
211
+
212
+ registerBidder(spec);