prebid.js 7.25.0 → 7.26.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 (168) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/adagioBidAdapter.js +1 -1
  3. package/dist/adbookpspBidAdapter.js +1 -1
  4. package/dist/adgenerationBidAdapter.js +1 -1
  5. package/dist/admaticBidAdapter.js +1 -1
  6. package/dist/adrelevantisBidAdapter.js +1 -1
  7. package/dist/adtrgtmeBidAdapter.js +1 -1
  8. package/dist/adxcgBidAdapter.js +1 -1
  9. package/dist/ajaBidAdapter.js +1 -1
  10. package/dist/amxBidAdapter.js +1 -1
  11. package/dist/amxIdSystem.js +1 -1
  12. package/dist/appierAnalyticsAdapter.js +1 -1
  13. package/dist/appnexusBidAdapter.js +1 -1
  14. package/dist/asoBidAdapter.js +1 -1
  15. package/dist/axonixBidAdapter.js +1 -1
  16. package/dist/beopBidAdapter.js +1 -1
  17. package/dist/bidglassBidAdapter.js +1 -1
  18. package/dist/big-richmediaBidAdapter.js +1 -1
  19. package/dist/bridgewellBidAdapter.js +1 -1
  20. package/dist/brightMountainMediaBidAdapter.js +1 -1
  21. package/dist/captifyRtdProvider.js +1 -0
  22. package/dist/carodaBidAdapter.js +1 -1
  23. package/dist/chtnwBidAdapter.js +1 -1
  24. package/dist/concertBidAdapter.js +1 -1
  25. package/dist/connectadBidAdapter.js +1 -1
  26. package/dist/consumableBidAdapter.js +1 -1
  27. package/dist/conversantBidAdapter.js +1 -1
  28. package/dist/craftBidAdapter.js +1 -1
  29. package/dist/criteoBidAdapter.js +1 -1
  30. package/dist/discoveryBidAdapter.js +1 -1
  31. package/dist/dspxBidAdapter.js +1 -1
  32. package/dist/eplanningBidAdapter.js +1 -1
  33. package/dist/finativeBidAdapter.js +1 -1
  34. package/dist/glimpseBidAdapter.js +1 -1
  35. package/dist/gmosspBidAdapter.js +1 -1
  36. package/dist/goldbachBidAdapter.js +1 -1
  37. package/dist/gridBidAdapter.js +1 -1
  38. package/dist/gridNMBidAdapter.js +1 -1
  39. package/dist/gumgumBidAdapter.js +1 -1
  40. package/dist/h12mediaBidAdapter.js +1 -1
  41. package/dist/id5IdSystem.js +1 -1
  42. package/dist/improvedigitalBidAdapter.js +1 -1
  43. package/dist/inmarBidAdapter.js +1 -1
  44. package/dist/insticatorBidAdapter.js +1 -1
  45. package/dist/ixBidAdapter.js +1 -1
  46. package/dist/justpremiumBidAdapter.js +1 -1
  47. package/dist/konduitAnalyticsAdapter.js +1 -1
  48. package/dist/kueezBidAdapter.js +1 -1
  49. package/dist/kueezRtbBidAdapter.js +1 -1
  50. package/dist/lassoBidAdapter.js +1 -1
  51. package/dist/lifestreetBidAdapter.js +1 -1
  52. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  53. package/dist/logicadBidAdapter.js +1 -1
  54. package/dist/loglyliftBidAdapter.js +1 -1
  55. package/dist/magniteAnalyticsAdapter.js +1 -1
  56. package/dist/malltvAnalyticsAdapter.js +1 -1
  57. package/dist/marsmediaBidAdapter.js +1 -1
  58. package/dist/mediafuseBidAdapter.js +1 -1
  59. package/dist/mediasquareBidAdapter.js +1 -1
  60. package/dist/mgidBidAdapter.js +1 -1
  61. package/dist/minutemediaBidAdapter.js +1 -1
  62. package/dist/nextMillenniumBidAdapter.js +1 -1
  63. package/dist/not-for-prod/prebid.js +152 -118
  64. package/dist/oguryBidAdapter.js +1 -1
  65. package/dist/onetagBidAdapter.js +1 -1
  66. package/dist/ooloAnalyticsAdapter.js +1 -1
  67. package/dist/outbrainBidAdapter.js +1 -1
  68. package/dist/parrableIdSystem.js +1 -1
  69. package/dist/pixfutureBidAdapter.js +1 -1
  70. package/dist/prebid-core.js +1 -1
  71. package/dist/publinkIdSystem.js +1 -1
  72. package/dist/pubmaticBidAdapter.js +1 -1
  73. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  74. package/dist/pxyzBidAdapter.js +1 -1
  75. package/dist/quantcastBidAdapter.js +1 -1
  76. package/dist/readpeakBidAdapter.js +1 -1
  77. package/dist/relaidoBidAdapter.js +1 -1
  78. package/dist/rhythmoneBidAdapter.js +1 -1
  79. package/dist/riseBidAdapter.js +1 -1
  80. package/dist/rubiconAnalyticsAdapter.js +1 -1
  81. package/dist/rubiconBidAdapter.js +1 -1
  82. package/dist/seedingAllianceBidAdapter.js +1 -1
  83. package/dist/seedtagBidAdapter.js +1 -1
  84. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  85. package/dist/sharethroughBidAdapter.js +1 -1
  86. package/dist/shinezBidAdapter.js +1 -1
  87. package/dist/smaatoBidAdapter.js +1 -1
  88. package/dist/smartadserverBidAdapter.js +1 -1
  89. package/dist/smartxBidAdapter.js +1 -1
  90. package/dist/smartytechBidAdapter.js +1 -0
  91. package/dist/smilewantedBidAdapter.js +1 -1
  92. package/dist/sonobiBidAdapter.js +1 -1
  93. package/dist/sovrnAnalyticsAdapter.js +1 -1
  94. package/dist/sovrnBidAdapter.js +1 -1
  95. package/dist/sspBCBidAdapter.js +1 -1
  96. package/dist/sublimeBidAdapter.js +1 -1
  97. package/dist/synacormediaBidAdapter.js +1 -1
  98. package/dist/taboolaBidAdapter.js +1 -1
  99. package/dist/tappxBidAdapter.js +1 -1
  100. package/dist/targetVideoBidAdapter.js +1 -1
  101. package/dist/teadsBidAdapter.js +1 -1
  102. package/dist/trionBidAdapter.js +1 -1
  103. package/dist/tripleliftBidAdapter.js +1 -1
  104. package/dist/ttdBidAdapter.js +1 -1
  105. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  106. package/dist/underdogmediaBidAdapter.js +1 -1
  107. package/dist/undertoneBidAdapter.js +1 -1
  108. package/dist/userId.js +1 -1
  109. package/dist/vidazooBidAdapter.js +1 -1
  110. package/dist/videobyteBidAdapter.js +1 -1
  111. package/dist/viqeoBidAdapter.js +1 -0
  112. package/dist/visxBidAdapter.js +1 -1
  113. package/dist/vuukleBidAdapter.js +1 -1
  114. package/dist/widespaceBidAdapter.js +1 -1
  115. package/dist/winrBidAdapter.js +1 -1
  116. package/dist/yahoosspBidAdapter.js +1 -1
  117. package/dist/yieldlabBidAdapter.js +1 -1
  118. package/dist/yieldmoBidAdapter.js +1 -1
  119. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  120. package/dist/zeta_global_sspBidAdapter.js +1 -1
  121. package/dist/zeusPrimeRtdProvider.js +31 -0
  122. package/integrationExamples/gpt/captifyRtdProvider_example.html +167 -0
  123. package/modules/.submodules.json +3 -1
  124. package/modules/admaticBidAdapter.js +108 -59
  125. package/modules/admaticBidAdapter.md +2 -2
  126. package/modules/beopBidAdapter.js +17 -2
  127. package/modules/captifyRtdProvider.js +146 -0
  128. package/modules/captifyRtdProvider.md +68 -0
  129. package/modules/discoveryBidAdapter.js +38 -17
  130. package/modules/discoveryBidAdapter.md +7 -6
  131. package/modules/gridBidAdapter.js +440 -22
  132. package/modules/nextMillenniumBidAdapter.js +19 -23
  133. package/modules/smartadserverBidAdapter.js +6 -2
  134. package/modules/smartxBidAdapter.js +10 -7
  135. package/modules/smartytechBidAdapter.js +78 -0
  136. package/modules/smartytechBidAdapter.md +44 -0
  137. package/modules/taboolaBidAdapter.js +3 -3
  138. package/modules/taboolaBidAdapter.md +0 -2
  139. package/modules/tappxBidAdapter.js +21 -6
  140. package/modules/ttdBidAdapter.js +4 -3
  141. package/modules/userId/index.js +1 -1
  142. package/modules/vidazooBidAdapter.js +15 -2
  143. package/modules/viqeoBidAdapter.js +180 -0
  144. package/modules/viqeoBidAdapter.md +56 -0
  145. package/modules/yieldlabBidAdapter.js +19 -8
  146. package/modules/yieldoneBidAdapter.js +60 -8
  147. package/modules/yieldoneBidAdapter.md +109 -9
  148. package/modules/zeta_global_sspBidAdapter.js +4 -0
  149. package/modules/zeusPrimeRtdProvider.js +357 -0
  150. package/modules/zeusPrimeRtdProvider.md +60 -0
  151. package/package.json +1 -1
  152. package/src/adloader.js +0 -1
  153. package/test/spec/modules/admaticBidAdapter_spec.js +262 -3
  154. package/test/spec/modules/beopBidAdapter_spec.js +52 -0
  155. package/test/spec/modules/captifyRtdProvider_spec.js +253 -0
  156. package/test/spec/modules/discoveryBidAdapter_spec.js +9 -8
  157. package/test/spec/modules/gridBidAdapter_spec.js +289 -1
  158. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +4 -3
  159. package/test/spec/modules/smartadserverBidAdapter_spec.js +80 -0
  160. package/test/spec/modules/smartxBidAdapter_spec.js +32 -0
  161. package/test/spec/modules/smartytechBidAdapter_spec.js +162 -0
  162. package/test/spec/modules/taboolaBidAdapter_spec.js +0 -77
  163. package/test/spec/modules/ttdBidAdapter_spec.js +13 -0
  164. package/test/spec/modules/viqeoBidAdapter_spec.js +124 -0
  165. package/test/spec/modules/yieldlabBidAdapter_spec.js +125 -0
  166. package/test/spec/modules/yieldoneBidAdapter_spec.js +30 -6
  167. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +16 -1
  168. package/test/spec/modules/zeusPrimeRtdProvider_spec.js +410 -0
@@ -1,18 +1,38 @@
1
- import { isEmpty, deepAccess, logError, parseGPTSingleSizeArrayToRtbSize, generateUUID, mergeDeep, logWarn } from '../src/utils.js';
1
+ import {
2
+ isEmpty,
3
+ deepAccess,
4
+ logError,
5
+ parseGPTSingleSizeArrayToRtbSize,
6
+ generateUUID,
7
+ mergeDeep,
8
+ logWarn,
9
+ parseUrl, isArray, isNumber
10
+ } from '../src/utils.js';
2
11
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
12
  import { Renderer } from '../src/Renderer.js';
4
13
  import { VIDEO, BANNER } from '../src/mediaTypes.js';
5
14
  import { config } from '../src/config.js';
6
15
  import { getStorageManager } from '../src/storageManager.js';
16
+ import { find } from '../src/polyfill.js';
7
17
 
8
18
  const BIDDER_CODE = 'grid';
9
19
  const ENDPOINT_URL = 'https://grid.bidswitch.net/hbjson';
20
+
21
+ const ADAPTER_VERSION_FOR_CRITEO_MODE = 34;
22
+ const CDB_ENDPOINT = 'https://bidder.criteo.com/cdb';
23
+ const PROFILE_ID_INLINE = 207;
24
+ const SID_COOKIE_NAME = 'cto_sid';
25
+ const IDCPY_COOKIE_NAME = 'cto_idcpy';
26
+ const OPTOUT_COOKIE_NAME = 'cto_optout';
27
+ const BUNDLE_COOKIE_NAME = 'cto_bundle';
28
+
10
29
  const SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid';
11
30
  const TIME_TO_LIVE = 360;
12
31
  const USER_ID_KEY = 'tmguid';
13
32
  const GVLID = 686;
14
33
  const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
15
34
  export const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE});
35
+
16
36
  const LOG_ERROR_MESS = {
17
37
  noAuid: 'Bid from response has no auid parameter - ',
18
38
  noAdm: 'Bid from response has no adm parameter - ',
@@ -49,7 +69,7 @@ export const spec = {
49
69
  * @return boolean True if this is a valid bid, and false otherwise.
50
70
  */
51
71
  isBidRequestValid: function(bid) {
52
- return !!bid.params.uid;
72
+ return bid && Boolean(bid.params.uid || bid.params.secid);
53
73
  },
54
74
  /**
55
75
  * Make a server request from the list of BidRequests.
@@ -79,10 +99,20 @@ export const spec = {
79
99
  const imp = [];
80
100
  const bidsMap = {};
81
101
  const requests = [];
102
+ const criteoBidsMap = {};
103
+ const criteoBidRequests = [];
82
104
  const sources = [];
83
105
  const bidsArray = [];
84
106
 
85
107
  validBidRequests.forEach((bid) => {
108
+ const bidObject = { bid, savedPrebidBid: null };
109
+ if (bid.params.withCriteo && criteoSpec.isBidRequestValid(bid)) {
110
+ criteoBidsMap[bid.bidId] = bidObject;
111
+ criteoBidRequests.push(bid);
112
+ }
113
+ if (!bid.params.uid && !bid.params.secid) {
114
+ return;
115
+ }
86
116
  if (!bidderRequestId) {
87
117
  bidderRequestId = bid.bidderRequestId;
88
118
  }
@@ -100,7 +130,6 @@ export const spec = {
100
130
  }
101
131
  const { params: { uid, keywords, forceBidder, multiRequest }, mediaTypes, bidId, adUnitCode, rtd, ortb2Imp } = bid;
102
132
  const { pubdata, secid, pubid, source, content: bidParamsContent } = bid.params;
103
- bidsMap[bidId] = bid;
104
133
  const bidFloor = _getFloor(mediaTypes || {}, bid);
105
134
  const jwTargeting = rtd && rtd.jwplayer && rtd.jwplayer.targeting;
106
135
  if (jwTargeting) {
@@ -201,8 +230,9 @@ export const spec = {
201
230
 
202
231
  requests.push(request);
203
232
  sources.push(source);
204
- bidsArray.push(bid);
233
+ bidsArray.push(bidObject);
205
234
  } else {
235
+ bidsMap[bidId] = bidObject;
206
236
  imp.push(impObj);
207
237
  }
208
238
  }
@@ -377,6 +407,11 @@ export const spec = {
377
407
  }
378
408
  });
379
409
 
410
+ const criteoRequest = criteoBidRequests.length && criteoSpec.buildRequests(criteoBidRequests, bidderRequest);
411
+ if (criteoRequest) {
412
+ criteoRequest.criteoBidsMap = criteoBidsMap;
413
+ }
414
+
380
415
  return [...requests.map((req, i) => {
381
416
  let sp;
382
417
  const url = (endpoint || ENDPOINT_URL).replace(/[?&]sp=([^?&=]+)/, (i, found) => {
@@ -391,14 +426,14 @@ export const spec = {
391
426
  method: 'POST',
392
427
  url: urlWithParams,
393
428
  data: JSON.stringify(req),
394
- bid: bidsArray[i],
429
+ bidObject: bidsArray[i],
395
430
  };
396
431
  }), ...(mainRequest ? [{
397
432
  method: 'POST',
398
433
  url: endpoint || ENDPOINT_URL,
399
434
  data: JSON.stringify(mainRequest),
400
435
  bidsMap
401
- }] : [])];
436
+ }] : []), ...(criteoRequest ? [criteoRequest] : [])];
402
437
  },
403
438
  /**
404
439
  * Unpack the response from the server into a list of bids.
@@ -409,25 +444,33 @@ export const spec = {
409
444
  * @return {Bid[]} An array of bids which were nested inside the server.
410
445
  */
411
446
  interpretResponse: function(serverResponse, bidRequest, RendererConst = Renderer) {
412
- serverResponse = serverResponse && serverResponse.body;
413
- const bidResponses = [];
447
+ if (bidRequest.criteoBidsMap && bidRequest.bidRequests) {
448
+ const criteoBids = criteoSpec.interpretResponse(serverResponse, bidRequest);
449
+ return criteoBids.filter((bid) => {
450
+ const { savedPrebidBid } = bidRequest.criteoBidsMap[bid.requestId] || {};
451
+ return canPublishResponse(bid.cpm, savedPrebidBid && savedPrebidBid.cpm);
452
+ });
453
+ } else {
454
+ serverResponse = serverResponse && serverResponse.body;
455
+ const bidResponses = [];
414
456
 
415
- let errorMessage;
457
+ let errorMessage;
416
458
 
417
- if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse;
418
- else if (serverResponse.seatbid && !serverResponse.seatbid.length) {
419
- errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray;
420
- }
459
+ if (!serverResponse) errorMessage = LOG_ERROR_MESS.emptyResponse;
460
+ else if (serverResponse.seatbid && !serverResponse.seatbid.length) {
461
+ errorMessage = LOG_ERROR_MESS.hasEmptySeatbidArray;
462
+ }
421
463
 
422
- const bidderCode = this.forceBidderName || this.code;
464
+ const bidderCode = this.forceBidderName || this.code;
423
465
 
424
- if (!errorMessage && serverResponse.seatbid) {
425
- serverResponse.seatbid.forEach(respItem => {
426
- _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode);
427
- });
466
+ if (!errorMessage && serverResponse.seatbid) {
467
+ serverResponse.seatbid.forEach(respItem => {
468
+ _addBidResponse(_getBidFromResponse(respItem), bidRequest, bidResponses, RendererConst, bidderCode);
469
+ });
470
+ }
471
+ if (errorMessage) logError(errorMessage);
472
+ return bidResponses;
428
473
  }
429
- if (errorMessage) logError(errorMessage);
430
- return bidResponses;
431
474
  },
432
475
  getUserSyncs: function (...args) {
433
476
  const [syncOptions,, gdprConsent, uspConsent] = args;
@@ -502,8 +545,9 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid
502
545
  if (!serverBid.auid) errorMessage = LOG_ERROR_MESS.noAuid + JSON.stringify(serverBid);
503
546
  if (!errorMessage && !serverBid.adm && !serverBid.nurl) errorMessage = LOG_ERROR_MESS.noAdm + JSON.stringify(serverBid);
504
547
  else {
505
- const bid = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bid;
506
- if (bid) {
548
+ const bidObject = bidRequest.bidsMap ? bidRequest.bidsMap[serverBid.impid] : bidRequest.bidObject;
549
+ const { bid, savedPrebidBid } = bidObject || {};
550
+ if (bid && canPublishResponse(serverBid.price, savedPrebidBid && savedPrebidBid.cpm)) {
507
551
  const bidResponse = {
508
552
  requestId: bid.bidId, // bid.bidderRequestId
509
553
  cpm: serverBid.price,
@@ -519,6 +563,8 @@ function _addBidResponse(serverBid, bidRequest, bidResponses, RendererConst, bid
519
563
  dealId: serverBid.dealid
520
564
  };
521
565
 
566
+ bidObject.savedPrebidBid = bidResponse;
567
+
522
568
  if (serverBid.ext && serverBid.ext.bidder && serverBid.ext.bidder.grid && serverBid.ext.bidder.grid.demandSource) {
523
569
  bidResponse.adserverTargeting = { 'hb_ds': serverBid.ext.bidder.grid.demandSource };
524
570
  bidResponse.meta.demandSource = serverBid.ext.bidder.grid.demandSource;
@@ -664,6 +710,13 @@ function reformatKeywords(pageKeywords) {
664
710
  return Object.keys(formatedPageKeywords).length && formatedPageKeywords;
665
711
  }
666
712
 
713
+ function canPublishResponse(price, savedPrice) {
714
+ if (isNumber(savedPrice)) {
715
+ return price > savedPrice || (price === savedPrice && Math.random() > 0.5);
716
+ }
717
+ return true;
718
+ }
719
+
667
720
  function outstreamRender (bid) {
668
721
  bid.renderer.push(() => {
669
722
  window.ANOutstreamVideo.renderAd({
@@ -697,4 +750,369 @@ export function getSyncUrl() {
697
750
  return SYNC_URL;
698
751
  }
699
752
 
753
+ // ================ Criteo methods ==================
754
+
755
+ const criteoSpec = {
756
+ /** f
757
+ * @param {object} bid
758
+ * @return {boolean}
759
+ */
760
+ isBidRequestValid: (bid) => {
761
+ // either one of zoneId or networkId should be set
762
+ if (!(bid && bid.params && (bid.params.zoneId || bid.params.networkId))) {
763
+ return false;
764
+ }
765
+
766
+ // video media types requires some mandatory params
767
+ if (hasVideoMediaType(bid)) {
768
+ if (!hasValidVideoMediaType(bid)) {
769
+ return false;
770
+ }
771
+ }
772
+
773
+ return true;
774
+ },
775
+
776
+ /**
777
+ * @param {BidRequest[]} bidRequests
778
+ * @param {*} bidderRequest
779
+ * @return {ServerRequest}
780
+ */
781
+ buildRequests: (bidRequests, bidderRequest) => {
782
+ let url;
783
+ let data;
784
+ let fpd = bidderRequest.ortb2 || {};
785
+
786
+ Object.assign(bidderRequest, {
787
+ publisherExt: fpd.site?.ext,
788
+ userExt: fpd.user?.ext,
789
+ ceh: config.getConfig('criteo.ceh'),
790
+ coppa: config.getConfig('coppa')
791
+ });
792
+
793
+ const context = buildContext(bidRequests, bidderRequest);
794
+ url = buildCdbUrl(context);
795
+ data = buildCdbRequest(context, bidRequests, bidderRequest);
796
+
797
+ if (data) {
798
+ return { method: 'POST', url, data, bidRequests };
799
+ }
800
+ },
801
+
802
+ /**
803
+ * @param {*} response
804
+ * @param {ServerRequest} request
805
+ * @return {Bid[]}
806
+ */
807
+ interpretResponse: (response, request) => {
808
+ const body = response.body || response;
809
+ const bids = [];
810
+
811
+ if (body && body.slots && isArray(body.slots)) {
812
+ body.slots.forEach(slot => {
813
+ const bidRequest = find(request.bidRequests, b => b.adUnitCode === slot.impid && (!b.params.zoneId || parseInt(b.params.zoneId) === slot.zoneid));
814
+ const bidId = bidRequest.bidId;
815
+ const bid = {
816
+ requestId: bidId,
817
+ cpm: slot.cpm,
818
+ currency: slot.currency,
819
+ netRevenue: true,
820
+ ttl: slot.ttl || 60,
821
+ creativeId: slot.creativecode,
822
+ width: slot.width,
823
+ height: slot.height,
824
+ dealId: slot.dealCode,
825
+ };
826
+ if (body.ext?.paf?.transmission && slot.ext?.paf?.content_id) {
827
+ const pafResponseMeta = {
828
+ content_id: slot.ext.paf.content_id,
829
+ transmission: response.ext.paf.transmission
830
+ };
831
+ bid.meta = Object.assign({}, bid.meta, { paf: pafResponseMeta });
832
+ }
833
+ if (slot.adomain) {
834
+ bid.meta = Object.assign({}, bid.meta, { advertiserDomains: slot.adomain });
835
+ }
836
+ if (slot.video) {
837
+ bid.vastUrl = slot.displayurl;
838
+ bid.mediaType = VIDEO;
839
+ } else {
840
+ bid.ad = slot.creative;
841
+ }
842
+ bids.push(bid);
843
+ });
844
+ }
845
+
846
+ return bids;
847
+ }
848
+ };
849
+
850
+ function readFromAllStorages(name) {
851
+ const fromCookie = storage.getCookie(name);
852
+ const fromLocalStorage = storage.getDataFromLocalStorage(name);
853
+
854
+ return fromCookie || fromLocalStorage || undefined;
855
+ }
856
+
857
+ /**
858
+ * @param {BidRequest[]} bidRequests
859
+ * @param bidderRequest
860
+ */
861
+ function buildContext(bidRequests, bidderRequest) {
862
+ let referrer = '';
863
+ if (bidderRequest && bidderRequest.refererInfo) {
864
+ referrer = bidderRequest.refererInfo.page;
865
+ }
866
+ const queryString = parseUrl(bidderRequest?.refererInfo?.topmostLocation).search;
867
+
868
+ const context = {
869
+ url: referrer,
870
+ debug: queryString['pbt_debug'] === '1',
871
+ noLog: queryString['pbt_nolog'] === '1',
872
+ amp: false,
873
+ };
874
+
875
+ bidRequests.forEach(bidRequest => {
876
+ if (bidRequest.params.integrationMode === 'amp') {
877
+ context.amp = true;
878
+ }
879
+ });
880
+
881
+ return context;
882
+ }
883
+
884
+ /**
885
+ * @param {CriteoContext} context
886
+ * @return {string}
887
+ */
888
+ function buildCdbUrl(context) {
889
+ let url = CDB_ENDPOINT;
890
+ url += '?profileId=' + PROFILE_ID_INLINE;
891
+ url += '&av=' + String(ADAPTER_VERSION_FOR_CRITEO_MODE);
892
+ url += '&wv=' + encodeURIComponent('$prebid.version$');
893
+ url += '&cb=' + String(Math.floor(Math.random() * 99999999999));
894
+
895
+ if (storage.localStorageIsEnabled()) {
896
+ url += '&lsavail=1';
897
+ } else {
898
+ url += '&lsavail=0';
899
+ }
900
+
901
+ if (context.amp) {
902
+ url += '&im=1';
903
+ }
904
+ if (context.debug) {
905
+ url += '&debug=1';
906
+ }
907
+ if (context.noLog) {
908
+ url += '&nolog=1';
909
+ }
910
+
911
+ const bundle = readFromAllStorages(BUNDLE_COOKIE_NAME);
912
+ if (bundle) {
913
+ url += `&bundle=${bundle}`;
914
+ }
915
+
916
+ const optout = readFromAllStorages(OPTOUT_COOKIE_NAME);
917
+ if (optout) {
918
+ url += `&optout=1`;
919
+ }
920
+
921
+ const sid = readFromAllStorages(SID_COOKIE_NAME);
922
+ if (sid) {
923
+ url += `&sid=${sid}`;
924
+ }
925
+
926
+ const idcpy = readFromAllStorages(IDCPY_COOKIE_NAME);
927
+ if (idcpy) {
928
+ url += `&idcpy=${idcpy}`;
929
+ }
930
+
931
+ return url;
932
+ }
933
+
934
+ /**
935
+ * @param {CriteoContext} context
936
+ * @param {BidRequest[]} bidRequests
937
+ * @param bidderRequest
938
+ * @return {*}
939
+ */
940
+ function buildCdbRequest(context, bidRequests, bidderRequest) {
941
+ let networkId;
942
+ let schain;
943
+ const request = {
944
+ publisher: {
945
+ url: context.url,
946
+ ext: bidderRequest.publisherExt,
947
+ },
948
+ regs: {
949
+ coppa: bidderRequest.coppa === true ? 1 : (bidderRequest.coppa === false ? 0 : undefined)
950
+ },
951
+ slots: bidRequests.map(bidRequest => {
952
+ networkId = bidRequest.params.networkId || networkId;
953
+ schain = bidRequest.schain || schain;
954
+ const slot = {
955
+ impid: bidRequest.adUnitCode,
956
+ transactionid: bidRequest.transactionId,
957
+ auctionId: bidRequest.auctionId,
958
+ };
959
+ if (bidRequest.params.zoneId) {
960
+ slot.zoneid = bidRequest.params.zoneId;
961
+ }
962
+ if (deepAccess(bidRequest, 'ortb2Imp.ext')) {
963
+ slot.ext = bidRequest.ortb2Imp.ext;
964
+ }
965
+ if (bidRequest.params.ext) {
966
+ slot.ext = Object.assign({}, slot.ext, bidRequest.params.ext);
967
+ }
968
+ if (bidRequest.params.publisherSubId) {
969
+ slot.publishersubid = bidRequest.params.publisherSubId;
970
+ }
971
+
972
+ if (hasBannerMediaType(bidRequest)) {
973
+ slot.sizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes'), parseSize);
974
+ } else {
975
+ slot.sizes = [];
976
+ }
977
+
978
+ if (hasVideoMediaType(bidRequest)) {
979
+ const video = {
980
+ playersizes: parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize'), parseSize),
981
+ mimes: bidRequest.mediaTypes.video.mimes,
982
+ protocols: bidRequest.mediaTypes.video.protocols,
983
+ maxduration: bidRequest.mediaTypes.video.maxduration,
984
+ api: bidRequest.mediaTypes.video.api,
985
+ skip: bidRequest.mediaTypes.video.skip,
986
+ placement: bidRequest.mediaTypes.video.placement,
987
+ minduration: bidRequest.mediaTypes.video.minduration,
988
+ playbackmethod: bidRequest.mediaTypes.video.playbackmethod,
989
+ startdelay: bidRequest.mediaTypes.video.startdelay
990
+ };
991
+ const paramsVideo = bidRequest.params.video;
992
+ if (paramsVideo !== undefined) {
993
+ video.skip = video.skip || paramsVideo.skip || 0;
994
+ video.placement = video.placement || paramsVideo.placement;
995
+ video.minduration = video.minduration || paramsVideo.minduration;
996
+ video.playbackmethod = video.playbackmethod || paramsVideo.playbackmethod;
997
+ video.startdelay = video.startdelay || paramsVideo.startdelay || 0;
998
+ }
999
+
1000
+ slot.video = video;
1001
+ }
1002
+
1003
+ enrichSlotWithFloors(slot, bidRequest);
1004
+
1005
+ return slot;
1006
+ }),
1007
+ };
1008
+ if (networkId) {
1009
+ request.publisher.networkid = networkId;
1010
+ }
1011
+ if (schain) {
1012
+ request.source = {
1013
+ ext: {
1014
+ schain: schain
1015
+ }
1016
+ };
1017
+ }
1018
+ request.user = {
1019
+ ext: bidderRequest.userExt
1020
+ };
1021
+ if (bidderRequest && bidderRequest.ceh) {
1022
+ request.user.ceh = bidderRequest.ceh;
1023
+ }
1024
+ if (bidderRequest && bidderRequest.gdprConsent) {
1025
+ request.gdprConsent = {};
1026
+ if (typeof bidderRequest.gdprConsent.gdprApplies !== 'undefined') {
1027
+ request.gdprConsent.gdprApplies = !!(bidderRequest.gdprConsent.gdprApplies);
1028
+ }
1029
+ request.gdprConsent.version = bidderRequest.gdprConsent.apiVersion;
1030
+ if (typeof bidderRequest.gdprConsent.consentString !== 'undefined') {
1031
+ request.gdprConsent.consentData = bidderRequest.gdprConsent.consentString;
1032
+ }
1033
+ }
1034
+ if (bidderRequest && bidderRequest.uspConsent) {
1035
+ request.user.uspIab = bidderRequest.uspConsent;
1036
+ }
1037
+ return request;
1038
+ }
1039
+
1040
+ function parseSizes(sizes, parser = s => s) {
1041
+ if (sizes === undefined) {
1042
+ return [];
1043
+ }
1044
+ if (Array.isArray(sizes[0])) { // is there several sizes ? (ie. [[728,90],[200,300]])
1045
+ return sizes.map(size => parser(size));
1046
+ }
1047
+ return [parser(sizes)]; // or a single one ? (ie. [728,90])
1048
+ }
1049
+
1050
+ function parseSize(size) {
1051
+ return size[0] + 'x' + size[1];
1052
+ }
1053
+
1054
+ function hasVideoMediaType(bidRequest) {
1055
+ return deepAccess(bidRequest, 'mediaTypes.video') !== undefined;
1056
+ }
1057
+
1058
+ function hasBannerMediaType(bidRequest) {
1059
+ return deepAccess(bidRequest, 'mediaTypes.banner') !== undefined;
1060
+ }
1061
+
1062
+ function hasValidVideoMediaType(bidRequest) {
1063
+ let isValid = true;
1064
+
1065
+ var requiredMediaTypesParams = ['mimes', 'playerSize', 'maxduration', 'protocols', 'api', 'skip', 'placement', 'playbackmethod'];
1066
+
1067
+ requiredMediaTypesParams.forEach(function (param) {
1068
+ if (deepAccess(bidRequest, 'mediaTypes.video.' + param) === undefined && deepAccess(bidRequest, 'params.video.' + param) === undefined) {
1069
+ isValid = false;
1070
+ logError('TheMediaGrid Bid Adapter (withCriteo mode): mediaTypes.video.' + param + ' is required');
1071
+ }
1072
+ });
1073
+
1074
+ if (isValid) {
1075
+ const videoPlacement = bidRequest.mediaTypes.video.placement || bidRequest.params.video.placement;
1076
+ // We do not support long form for now, also we have to check that context & placement are consistent
1077
+ if (bidRequest.mediaTypes.video.context === 'instream' && videoPlacement === 1) {
1078
+ return true;
1079
+ } else if (bidRequest.mediaTypes.video.context === 'outstream' && videoPlacement !== 1) {
1080
+ return true;
1081
+ }
1082
+ }
1083
+
1084
+ return false;
1085
+ }
1086
+
1087
+ function enrichSlotWithFloors(slot, bidRequest) {
1088
+ try {
1089
+ const slotFloors = {};
1090
+
1091
+ if (bidRequest.getFloor) {
1092
+ if (bidRequest.mediaTypes?.banner) {
1093
+ slotFloors.banner = {};
1094
+ const bannerSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.banner.sizes'))
1095
+ bannerSizes.forEach(bannerSize => slotFloors.banner[parseSize(bannerSize).toString()] = bidRequest.getFloor({ size: bannerSize, mediaType: BANNER }));
1096
+ }
1097
+
1098
+ if (bidRequest.mediaTypes?.video) {
1099
+ slotFloors.video = {};
1100
+ const videoSizes = parseSizes(deepAccess(bidRequest, 'mediaTypes.video.playerSize'))
1101
+ videoSizes.forEach(videoSize => slotFloors.video[parseSize(videoSize).toString()] = bidRequest.getFloor({ size: videoSize, mediaType: VIDEO }));
1102
+ }
1103
+
1104
+ if (Object.keys(slotFloors).length > 0) {
1105
+ if (!slot.ext) {
1106
+ slot.ext = {}
1107
+ }
1108
+ Object.assign(slot.ext, {
1109
+ floors: slotFloors
1110
+ });
1111
+ }
1112
+ }
1113
+ } catch (e) {
1114
+ logError('Could not parse floors from Prebid: ' + e);
1115
+ }
1116
+ }
1117
+
700
1118
  registerBidder(spec);
@@ -22,7 +22,7 @@ import { getRefererInfo } from '../src/refererDetection.js';
22
22
  const BIDDER_CODE = 'nextMillennium';
23
23
  const ENDPOINT = 'https://pbs.nextmillmedia.com/openrtb2/auction';
24
24
  const TEST_ENDPOINT = 'https://test.pbs.nextmillmedia.com/openrtb2/auction';
25
- const SYNC_ENDPOINT = 'https://statics.nextmillmedia.com/load-cookie.html?v=4';
25
+ const SYNC_ENDPOINT = 'https://cookies.nextmillmedia.com/sync?';
26
26
  const TIME_TO_LIVE = 360;
27
27
  const VIDEO_PARAMS = [
28
28
  'api', 'linearity', 'maxduration', 'mimes', 'minduration', 'placement',
@@ -198,28 +198,24 @@ export const spec = {
198
198
  },
199
199
 
200
200
  getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
201
- if (!syncOptions.iframeEnabled) {
202
- return;
203
- };
204
-
205
- let syncurl = gdprConsent && gdprConsent.gdprApplies ? `${SYNC_ENDPOINT}&gdpr=1&gdpr_consent=${gdprConsent.consentString}` : SYNC_ENDPOINT;
206
-
207
- let bidders = [];
208
- if (responses) {
209
- _each(responses, (response) => {
210
- if (!(response && response.body && response.body.ext && response.body.ext.responsetimemillis)) return;
211
- _each(Object.keys(response.body.ext.responsetimemillis), b => bidders.push(b));
212
- });
213
- };
214
-
215
- if (bidders.length) {
216
- syncurl += `&bidders=${bidders.join(',')}`;
217
- };
218
-
219
- return [{
220
- type: 'iframe',
221
- url: syncurl
222
- }];
201
+ const pixels = [];
202
+ let syncUrl = SYNC_ENDPOINT;
203
+
204
+ if (gdprConsent && gdprConsent.gdprApplies) {
205
+ syncUrl += 'gdpr=1&gdpr_consent=' + gdprConsent.consentString;
206
+ }
207
+ if (uspConsent) {
208
+ syncUrl += 'us_privacy=' + uspConsent;
209
+ }
210
+
211
+ if (syncOptions.iframeEnabled) {
212
+ pixels.push({type: 'iframe', url: syncUrl + 'type=iframe'});
213
+ }
214
+ if (syncOptions.pixelEnabled) {
215
+ pixels.push({type: 'image', url: syncUrl + 'type=image'});
216
+ }
217
+
218
+ return pixels;
223
219
  },
224
220
  };
225
221
 
@@ -133,6 +133,8 @@ export const spec = {
133
133
  // use bidderRequest.bids[] to get bidder-dependent request info
134
134
 
135
135
  const adServerCurrency = config.getConfig('currency.adServerCurrency');
136
+ const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data'));
137
+ const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data'));
136
138
 
137
139
  // pull requested transaction ID from bidderRequest.bids[].transactionId
138
140
  return validBidRequests.reduce((bidRequests, bid) => {
@@ -154,7 +156,9 @@ export const spec = {
154
156
  timeout: config.getConfig('bidderTimeout'),
155
157
  bidId: bid.bidId,
156
158
  prebidVersion: '$prebid.version$',
157
- schain: spec.serializeSupplyChain(bid.schain)
159
+ schain: spec.serializeSupplyChain(bid.schain),
160
+ sda: sellerDefinedAudience,
161
+ sdc: sellerDefinedContext
158
162
  };
159
163
 
160
164
  if (bidderRequest && bidderRequest.gdprConsent) {
@@ -209,7 +213,7 @@ export const spec = {
209
213
  const bidResponses = [];
210
214
  let response = serverResponse.body;
211
215
  try {
212
- if (response && !response.isNoAd) {
216
+ if (response && !response.isNoAd && (response.ad || response.adUrl)) {
213
217
  const bidRequest = JSON.parse(bidRequestString.data);
214
218
 
215
219
  let bidResponse = {
@@ -67,7 +67,6 @@ export const spec = {
67
67
  * @return ServerRequest Info describing the request to the server.
68
68
  */
69
69
  buildRequests: function (bidRequests, bidderRequest) {
70
- // TODO: does the fallback make sense here?
71
70
  const page = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation;
72
71
  const isPageSecure = !!page.match(/^https:/)
73
72
 
@@ -197,6 +196,15 @@ export const spec = {
197
196
  userExt.fpc = pubcid;
198
197
  }
199
198
 
199
+ // Add schain object if available
200
+ if (bid && bid.schain) {
201
+ requestPayload['source'] = {
202
+ ext: {
203
+ schain: bid.schain
204
+ }
205
+ };
206
+ }
207
+
200
208
  // Only add the user object if it's not empty
201
209
  if (!isEmpty(userExt)) {
202
210
  requestPayload.user = {
@@ -204,9 +212,7 @@ export const spec = {
204
212
  };
205
213
  }
206
214
 
207
- // requestPayload.user.ext.ver = pbjs.version;
208
-
209
- // Targeting
215
+ // Add targeting
210
216
  if (getBidIdParameter('data', bid.params.user)) {
211
217
  var targetingarr = [];
212
218
  for (var i = 0; i < bid.params.user.data.length; i++) {
@@ -225,8 +231,6 @@ export const spec = {
225
231
  }
226
232
  }
227
233
 
228
- // Todo: USER ID MODULE
229
-
230
234
  requestPayload.user = {
231
235
  ext: userExt,
232
236
  data: targetingarr
@@ -269,7 +273,6 @@ export const spec = {
269
273
  }
270
274
  /**
271
275
  * Make sure currency and price are the right ones
272
- * TODO: what about the pre_market_bid partners sizes?
273
276
  */
274
277
  _each(currentBidRequest.params.pre_market_bids, function (pmb) {
275
278
  if (pmb.deal_id == smartxBid.id) {