prebid.js 6.7.0 → 6.11.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 (160) hide show
  1. package/.eslintrc.js +8 -1
  2. package/integrationExamples/gpt/{haloRtdProvider_example.html → hadronRtdProvider_example.html} +9 -9
  3. package/integrationExamples/gpt/idImportLibrary_example.html +2 -2
  4. package/integrationExamples/gpt/userId_example.html +2 -2
  5. package/integrationExamples/gpt/weboramaRtdProvider_example.html +154 -115
  6. package/integrationExamples/gpt/x-domain/creative.html +63 -29
  7. package/modules/.submodules.json +3 -0
  8. package/modules/adagioBidAdapter.js +0 -8
  9. package/modules/adagioBidAdapter.md +1 -1
  10. package/modules/adkernelBidAdapter.js +2 -1
  11. package/modules/adnuntiusRtdProvider.js +96 -0
  12. package/modules/adnuntiusRtdProvider.md +41 -0
  13. package/modules/adotBidAdapter.js +516 -567
  14. package/modules/adotBidAdapter.md +6 -44
  15. package/modules/adpod.js +12 -14
  16. package/modules/adyoulikeBidAdapter.js +2 -0
  17. package/modules/appnexusBidAdapter.js +14 -2
  18. package/modules/asealBidAdapter.js +58 -0
  19. package/modules/asealBidAdapter.md +52 -0
  20. package/modules/brandmetricsRtdProvider.js +168 -0
  21. package/modules/brandmetricsRtdProvider.md +40 -0
  22. package/modules/conversantBidAdapter.js +7 -0
  23. package/modules/criteoBidAdapter.js +9 -0
  24. package/modules/currency.js +27 -5
  25. package/modules/displayioBidAdapter.js +157 -0
  26. package/modules/displayioBidAdapter.md +148 -0
  27. package/modules/dspxBidAdapter.js +69 -29
  28. package/modules/dspxBidAdapter.md +2 -1
  29. package/modules/e_volutionBidAdapter.js +158 -0
  30. package/modules/gridBidAdapter.js +15 -1
  31. package/modules/gumgumBidAdapter.js +52 -38
  32. package/modules/hadronIdSystem.js +96 -0
  33. package/modules/hadronIdSystem.md +35 -0
  34. package/modules/hadronRtdProvider.js +254 -0
  35. package/modules/hadronRtdProvider.md +126 -0
  36. package/modules/haloIdSystem.md +4 -35
  37. package/modules/haloRtdProvider.md +3 -126
  38. package/modules/imRtdProvider.js +10 -0
  39. package/modules/improvedigitalBidAdapter.js +5 -0
  40. package/modules/interactiveOffersBidAdapter.js +9 -6
  41. package/modules/iqzoneBidAdapter.js +10 -3
  42. package/modules/iqzoneBidAdapter.md +16 -0
  43. package/modules/ixBidAdapter.js +2 -6
  44. package/modules/kubientBidAdapter.js +50 -19
  45. package/modules/lunamediahbBidAdapter.js +32 -4
  46. package/modules/malltvBidAdapter.js +7 -3
  47. package/modules/malltvBidAdapter.md +64 -51
  48. package/modules/mass.js +3 -5
  49. package/modules/mediakeysBidAdapter.js +0 -5
  50. package/modules/medianetAnalyticsAdapter.js +1 -1
  51. package/modules/mediasquareBidAdapter.js +9 -1
  52. package/modules/nextMillenniumBidAdapter.js +1 -0
  53. package/modules/oguryBidAdapter.js +7 -14
  54. package/modules/prebidServerBidAdapter/index.js +61 -39
  55. package/modules/priceFloors.js +20 -12
  56. package/modules/pubmaticBidAdapter.js +1 -1
  57. package/modules/richaudienceBidAdapter.js +8 -3
  58. package/modules/riseBidAdapter.js +17 -6
  59. package/modules/rtbhouseBidAdapter.js +2 -0
  60. package/modules/rubiconAnalyticsAdapter.js +5 -0
  61. package/modules/rubiconBidAdapter.js +2 -2
  62. package/modules/sizeMappingV2.js +1 -8
  63. package/modules/sortableAnalyticsAdapter.js +5 -4
  64. package/modules/sovrnBidAdapter.js +93 -18
  65. package/modules/sovrnBidAdapter.md +80 -2
  66. package/modules/sspBCBidAdapter.js +53 -20
  67. package/modules/telariaBidAdapter.js +22 -29
  68. package/modules/trustpidSystem.js +197 -0
  69. package/modules/trustpidSystem.md +45 -0
  70. package/modules/undertoneBidAdapter.js +17 -1
  71. package/modules/userId/eids.js +16 -1
  72. package/modules/userId/eids.md +10 -2
  73. package/modules/userId/userId.md +17 -2
  74. package/modules/vibrantmediaBidAdapter.js +220 -0
  75. package/modules/vibrantmediaBidAdapter.md +92 -0
  76. package/modules/vidoomyBidAdapter.js +8 -0
  77. package/modules/vidoomyBidAdapter.md +4 -2
  78. package/modules/weboramaRtdProvider.js +264 -34
  79. package/modules/weboramaRtdProvider.md +110 -40
  80. package/modules/yahoosspBidAdapter.js +3 -1
  81. package/modules/yieldoneBidAdapter.js +6 -0
  82. package/package.json +2 -1
  83. package/src/adRendering.js +38 -0
  84. package/src/adapterManager.js +24 -19
  85. package/src/adapters/bidderFactory.js +14 -11
  86. package/src/adloader.js +2 -1
  87. package/src/auction.js +138 -115
  88. package/src/auctionIndex.js +85 -0
  89. package/src/auctionManager.js +3 -0
  90. package/src/bidderSettings.js +69 -0
  91. package/src/bidfactory.js +18 -6
  92. package/src/native.js +29 -21
  93. package/src/prebid.js +3 -19
  94. package/src/secureCreatives.js +128 -45
  95. package/src/targeting.js +11 -2
  96. package/src/utils.js +14 -17
  97. package/src/video.js +10 -11
  98. package/src/videoCache.js +10 -9
  99. package/test/fixtures/fixtures.js +2 -1
  100. package/test/helpers/indexStub.js +28 -0
  101. package/test/helpers/syncPromise.js +71 -0
  102. package/test/spec/auctionmanager_spec.js +268 -89
  103. package/test/spec/config_spec.js +24 -1
  104. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  105. package/test/spec/modules/adnuntiusRtdProvider_spec.js +145 -0
  106. package/test/spec/modules/adotBidAdapter_spec.js +294 -3124
  107. package/test/spec/modules/adpod_spec.js +91 -156
  108. package/test/spec/modules/adyoulikeBidAdapter_spec.js +4 -0
  109. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  110. package/test/spec/modules/asealBidAdapter_spec.js +144 -0
  111. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  112. package/test/spec/modules/conversantBidAdapter_spec.js +54 -2
  113. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  114. package/test/spec/modules/currency_spec.js +36 -15
  115. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  116. package/test/spec/modules/dspxBidAdapter_spec.js +20 -15
  117. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  118. package/test/spec/modules/eids_spec.js +2 -2
  119. package/test/spec/modules/gridBidAdapter_spec.js +18 -0
  120. package/test/spec/modules/gumgumBidAdapter_spec.js +49 -3
  121. package/test/spec/modules/hadronIdSystem_spec.js +57 -0
  122. package/test/spec/modules/hadronRtdProvider_spec.js +762 -0
  123. package/test/spec/modules/imRtdProvider_spec.js +30 -1
  124. package/test/spec/modules/improvedigitalBidAdapter_spec.js +19 -0
  125. package/test/spec/modules/iqzoneBidAdapter_spec.js +1 -0
  126. package/test/spec/modules/ixBidAdapter_spec.js +1 -1
  127. package/test/spec/modules/kubientBidAdapter_spec.js +182 -84
  128. package/test/spec/modules/lunamediahbBidAdapter_spec.js +27 -1
  129. package/test/spec/modules/mass_spec.js +2 -14
  130. package/test/spec/modules/mediakeysBidAdapter_spec.js +9 -5
  131. package/test/spec/modules/mediasquareBidAdapter_spec.js +25 -1
  132. package/test/spec/modules/oguryBidAdapter_spec.js +63 -5
  133. package/test/spec/modules/prebidServerBidAdapter_spec.js +43 -6
  134. package/test/spec/modules/priceFloors_spec.js +83 -24
  135. package/test/spec/modules/pubmaticBidAdapter_spec.js +40 -0
  136. package/test/spec/modules/riseBidAdapter_spec.js +30 -4
  137. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +31 -1
  138. package/test/spec/modules/rubiconBidAdapter_spec.js +1 -1
  139. package/test/spec/modules/sortableAnalyticsAdapter_spec.js +2 -3
  140. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  141. package/test/spec/modules/sspBCBidAdapter_spec.js +7 -7
  142. package/test/spec/modules/telariaBidAdapter_spec.js +1 -3
  143. package/test/spec/modules/trustpidSystem_spec.js +232 -0
  144. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  145. package/test/spec/modules/userId_spec.js +39 -39
  146. package/test/spec/modules/vibrantmediaBidAdapter_spec.js +1237 -0
  147. package/test/spec/modules/vidoomyBidAdapter_spec.js +7 -1
  148. package/test/spec/modules/weboramaRtdProvider_spec.js +536 -20
  149. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  150. package/test/spec/modules/yieldoneBidAdapter_spec.js +33 -0
  151. package/test/spec/native_spec.js +62 -40
  152. package/test/spec/unit/core/adapterManager_spec.js +22 -0
  153. package/test/spec/unit/core/auctionIndex_spec.js +129 -0
  154. package/test/spec/unit/core/bidderFactory_spec.js +65 -12
  155. package/test/spec/unit/core/bidderSettings_spec.js +123 -0
  156. package/test/spec/unit/core/targeting_spec.js +93 -0
  157. package/test/spec/unit/pbjs_api_spec.js +80 -42
  158. package/test/spec/unit/secureCreatives_spec.js +143 -24
  159. package/test/spec/videoCache_spec.js +18 -19
  160. package/test/spec/video_spec.js +51 -61
package/src/auction.js CHANGED
@@ -58,8 +58,8 @@
58
58
  */
59
59
 
60
60
  import {
61
- flatten, timestamp, adUnitsFilter, deepAccess, getBidRequest, getValue, parseUrl, generateUUID,
62
- logMessage, bind, logError, logInfo, logWarn, isEmpty, _each, isFn, isEmptyStr, isAllowZeroCpmBidsEnabled
61
+ flatten, timestamp, adUnitsFilter, deepAccess, getValue, parseUrl, generateUUID,
62
+ logMessage, bind, logError, logInfo, logWarn, isEmpty, _each, isFn, isEmptyStr
63
63
  } from './utils.js';
64
64
  import { getPriceBucketString } from './cpmBucketManager.js';
65
65
  import { getNativeTargeting } from './native.js';
@@ -72,6 +72,8 @@ import find from 'core-js-pure/features/array/find.js';
72
72
  import includes from 'core-js-pure/features/array/includes.js';
73
73
  import { OUTSTREAM } from './video.js';
74
74
  import { VIDEO } from './mediaTypes.js';
75
+ import {auctionManager} from './auctionManager.js';
76
+ import {bidderSettings} from './bidderSettings.js';
75
77
 
76
78
  const { syncUsers } = userSync;
77
79
 
@@ -249,12 +251,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
249
251
  events.emit(CONSTANTS.EVENTS.AUCTION_INIT, getProperties());
250
252
 
251
253
  let callbacks = auctionCallbacks(auctionDone, this);
252
- adapterManager.callBids(_adUnits, bidRequests, function(...args) {
253
- addBidResponse.apply({
254
- dispatch: callbacks.addBidResponse,
255
- bidderRequest: this
256
- }, args)
257
- }, callbacks.adapterDone, {
254
+ adapterManager.callBids(_adUnits, bidRequests, callbacks.addBidResponse, callbacks.adapterDone, {
258
255
  request(source, origin) {
259
256
  increment(outstandingRequests, origin);
260
257
  increment(requests, source);
@@ -344,6 +341,7 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
344
341
  addWinningBid,
345
342
  setBidTargeting,
346
343
  getWinningBids: () => _winningBids,
344
+ getAuctionStart: () => _auctionStart,
347
345
  getTimeout: () => _timeout,
348
346
  getAuctionId: () => _auctionId,
349
347
  getAuctionStatus: () => _auctionStatus,
@@ -351,12 +349,13 @@ export function newAuction({adUnits, adUnitCodes, callback, cbTimeout, labels, a
351
349
  getAdUnitCodes: () => _adUnitCodes,
352
350
  getBidRequests: () => _bidderRequests,
353
351
  getBidsReceived: () => _bidsReceived,
354
- getNoBids: () => _noBids
352
+ getNoBids: () => _noBids,
353
+
355
354
  }
356
355
  }
357
356
 
358
- export const addBidResponse = hook('async', function(adUnitCode, bid) {
359
- this.dispatch.call(this.bidderRequest, adUnitCode, bid);
357
+ export const addBidResponse = hook('sync', function(adUnitCode, bid) {
358
+ this.dispatch.call(null, adUnitCode, bid);
360
359
  }, 'addBidResponse');
361
360
 
362
361
  export const addBidderRequests = hook('sync', function(bidderRequests) {
@@ -369,11 +368,37 @@ export const bidsBackCallback = hook('async', function (adUnits, callback) {
369
368
  }
370
369
  }, 'bidsBackCallback');
371
370
 
372
- export function auctionCallbacks(auctionDone, auctionInstance) {
371
+ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionManager.index} = {}) {
373
372
  let outstandingBidsAdded = 0;
374
373
  let allAdapterCalledDone = false;
375
374
  let bidderRequestsDone = new Set();
376
375
  let bidResponseMap = {};
376
+ const ready = {};
377
+
378
+ function waitFor(requestId, result) {
379
+ if (ready[requestId] == null) {
380
+ ready[requestId] = Promise.resolve();
381
+ }
382
+ ready[requestId] = ready[requestId].then(() => Promise.resolve(result).catch(() => {}))
383
+ }
384
+
385
+ function guard(bidderRequest, fn) {
386
+ let timeout = bidderRequest.timeout;
387
+ if (timeout == null || timeout > auctionInstance.getTimeout()) {
388
+ timeout = auctionInstance.getTimeout();
389
+ }
390
+ const timeRemaining = auctionInstance.getAuctionStart() + timeout - Date.now();
391
+ const wait = ready[bidderRequest.bidderRequestId];
392
+ const orphanWait = ready['']; // also wait for "orphan" responses that are not associated with any request
393
+ if ((wait != null || orphanWait != null) && timeRemaining > 0) {
394
+ Promise.race([
395
+ new Promise((resolve) => setTimeout(resolve, timeRemaining)),
396
+ Promise.resolve(orphanWait).then(() => wait)
397
+ ]).then(fn);
398
+ } else {
399
+ fn();
400
+ }
401
+ }
377
402
 
378
403
  function afterBidAdded() {
379
404
  outstandingBidsAdded--;
@@ -382,18 +407,16 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
382
407
  }
383
408
  }
384
409
 
385
- function addBidResponse(adUnitCode, bid) {
386
- let bidderRequest = this;
387
-
410
+ function handleBidResponse(adUnitCode, bid) {
388
411
  bidResponseMap[bid.requestId] = true;
389
412
 
390
413
  outstandingBidsAdded++;
391
414
  let auctionId = auctionInstance.getAuctionId();
392
415
 
393
- let bidResponse = getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId});
416
+ let bidResponse = getPreparedBidForAuction({adUnitCode, bid, auctionId});
394
417
 
395
418
  if (bidResponse.mediaType === 'video') {
396
- tryAddVideoBid(auctionInstance, bidResponse, bidderRequest, afterBidAdded);
419
+ tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded);
397
420
  } else {
398
421
  addBidToAuction(auctionInstance, bidResponse);
399
422
  afterBidAdded();
@@ -429,8 +452,15 @@ export function auctionCallbacks(auctionDone, auctionInstance) {
429
452
  }
430
453
 
431
454
  return {
432
- addBidResponse,
433
- adapterDone
455
+ addBidResponse: function (adUnit, bid) {
456
+ const bidderRequest = index.getBidderRequest(bid);
457
+ waitFor((bidderRequest && bidderRequest.bidderRequestId) || '', addBidResponse.call({
458
+ dispatch: handleBidResponse,
459
+ }, adUnit, bid));
460
+ },
461
+ adapterDone: function () {
462
+ guard(this, adapterDone.bind(this))
463
+ }
434
464
  }
435
465
  }
436
466
 
@@ -442,9 +472,7 @@ export function doCallbacksIfTimedout(auctionInstance, bidResponse) {
442
472
 
443
473
  // Add a bid to the auction.
444
474
  export function addBidToAuction(auctionInstance, bidResponse) {
445
- let bidderRequests = auctionInstance.getBidRequests();
446
- let bidderRequest = find(bidderRequests, bidderRequest => bidderRequest.bidderCode === bidResponse.bidderCode);
447
- setupBidTargeting(bidResponse, bidderRequest);
475
+ setupBidTargeting(bidResponse);
448
476
 
449
477
  events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bidResponse);
450
478
  auctionInstance.addBidReceived(bidResponse);
@@ -453,18 +481,20 @@ export function addBidToAuction(auctionInstance, bidResponse) {
453
481
  }
454
482
 
455
483
  // Video bids may fail if the cache is down, or there's trouble on the network.
456
- function tryAddVideoBid(auctionInstance, bidResponse, bidRequests, afterBidAdded) {
484
+ function tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded, {index = auctionManager.index} = {}) {
457
485
  let addBid = true;
458
486
 
459
- const bidderRequest = getBidRequest(bidResponse.originalRequestId || bidResponse.requestId, [bidRequests]);
460
- const videoMediaType =
461
- bidderRequest && deepAccess(bidderRequest, 'mediaTypes.video');
487
+ const videoMediaType = deepAccess(
488
+ index.getMediaTypes({
489
+ requestId: bidResponse.originalRequestId || bidResponse.requestId,
490
+ transactionId: bidResponse.transactionId
491
+ }), 'video');
462
492
  const context = videoMediaType && deepAccess(videoMediaType, 'context');
463
493
 
464
494
  if (config.getConfig('cache.url') && context !== OUTSTREAM) {
465
495
  if (!bidResponse.videoCacheKey || config.getConfig('cache.ignoreBidderCacheKey')) {
466
496
  addBid = false;
467
- callPrebidCache(auctionInstance, bidResponse, afterBidAdded, bidderRequest);
497
+ callPrebidCache(auctionInstance, bidResponse, afterBidAdded, videoMediaType);
468
498
  } else if (!bidResponse.vastUrl) {
469
499
  logError('videoCacheKey specified but not required vastUrl for video bid');
470
500
  addBid = false;
@@ -476,7 +506,7 @@ function tryAddVideoBid(auctionInstance, bidResponse, bidRequests, afterBidAdded
476
506
  }
477
507
  }
478
508
 
479
- export const callPrebidCache = hook('async', function(auctionInstance, bidResponse, afterBidAdded, bidderRequest) {
509
+ export const callPrebidCache = hook('async', function(auctionInstance, bidResponse, afterBidAdded, videoMediaType) {
480
510
  store([bidResponse], function (error, cacheIds) {
481
511
  if (error) {
482
512
  logWarn(`Failed to save to the video cache: ${error}. Video bid must be discarded.`);
@@ -497,13 +527,14 @@ export const callPrebidCache = hook('async', function(auctionInstance, bidRespon
497
527
  afterBidAdded();
498
528
  }
499
529
  }
500
- }, bidderRequest);
530
+ });
501
531
  }, 'callPrebidCache');
502
532
 
503
533
  // Postprocess the bids so that all the universal properties exist, no matter which bidder they came from.
504
534
  // This should be called before addBidToAuction().
505
- function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
506
- const start = bidderRequest.start;
535
+ function getPreparedBidForAuction({adUnitCode, bid, auctionId}, {index = auctionManager.index} = {}) {
536
+ const bidderRequest = index.getBidderRequest(bid);
537
+ const start = (bidderRequest && bidderRequest.start) || bid.requestTimestamp;
507
538
 
508
539
  let bidObject = Object.assign({}, bid, {
509
540
  auctionId,
@@ -523,14 +554,12 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
523
554
  events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bidObject);
524
555
 
525
556
  // a publisher-defined renderer can be used to render bids
526
- const bidReq = bidderRequest.bids && find(bidderRequest.bids, bid => bid.adUnitCode == adUnitCode && bid.bidId == bidObject.requestId);
527
- const adUnitRenderer = bidReq && bidReq.renderer;
557
+ const adUnitRenderer = index.getAdUnit(bidObject).renderer;
528
558
 
529
559
  // a publisher can also define a renderer for a mediaType
530
560
  const bidObjectMediaType = bidObject.mediaType;
531
- const bidMediaType = bidReq &&
532
- bidReq.mediaTypes &&
533
- bidReq.mediaTypes[bidObjectMediaType];
561
+ const mediaTypes = index.getMediaTypes(bidObject)
562
+ const bidMediaType = mediaTypes && mediaTypes[bidObjectMediaType];
534
563
 
535
564
  var mediaTypeRenderer = bidMediaType && bidMediaType.renderer;
536
565
 
@@ -549,7 +578,7 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
549
578
  }
550
579
 
551
580
  // Use the config value 'mediaTypeGranularity' if it has been defined for mediaType, else use 'customPriceBucket'
552
- const mediaTypeGranularity = getMediaTypeGranularity(bid.mediaType, bidReq, config.getConfig('mediaTypePriceGranularity'));
581
+ const mediaTypeGranularity = getMediaTypeGranularity(bid.mediaType, mediaTypes, config.getConfig('mediaTypePriceGranularity'));
553
582
  const priceStringsObj = getPriceBucketString(
554
583
  bidObject.cpm,
555
584
  (typeof mediaTypeGranularity === 'object') ? mediaTypeGranularity : config.getConfig('customPriceBucket'),
@@ -565,12 +594,11 @@ function getPreparedBidForAuction({adUnitCode, bid, bidderRequest, auctionId}) {
565
594
  return bidObject;
566
595
  }
567
596
 
568
- function setupBidTargeting(bidObject, bidderRequest) {
597
+ function setupBidTargeting(bidObject) {
569
598
  let keyValues;
570
- const cpmCheck = (isAllowZeroCpmBidsEnabled(bidObject.bidderCode)) ? bidObject.cpm >= 0 : bidObject.cpm > 0;
599
+ const cpmCheck = (bidderSettings.get(bidObject.bidderCode, 'allowZeroCpmBids') === true) ? bidObject.cpm >= 0 : bidObject.cpm > 0;
571
600
  if (bidObject.bidderCode && (cpmCheck || bidObject.dealId)) {
572
- let bidReq = find(bidderRequest.bids, bid => bid.adUnitCode === bidObject.adUnitCode && bid.bidId === bidObject.requestId);
573
- keyValues = getKeyValueTargetingPairs(bidObject.bidderCode, bidObject, bidReq);
601
+ keyValues = getKeyValueTargetingPairs(bidObject.bidderCode, bidObject);
574
602
  }
575
603
 
576
604
  // use any targeting provided as defaults, otherwise just set from getKeyValueTargetingPairs
@@ -579,14 +607,14 @@ function setupBidTargeting(bidObject, bidderRequest) {
579
607
 
580
608
  /**
581
609
  * @param {MediaType} mediaType
582
- * @param {Bid} [bidReq]
610
+ * @param mediaTypes media types map from adUnit
583
611
  * @param {MediaTypePriceGranularity} [mediaTypePriceGranularity]
584
612
  * @returns {(Object|string|undefined)}
585
613
  */
586
- export function getMediaTypeGranularity(mediaType, bidReq, mediaTypePriceGranularity) {
614
+ export function getMediaTypeGranularity(mediaType, mediaTypes, mediaTypePriceGranularity) {
587
615
  if (mediaType && mediaTypePriceGranularity) {
588
616
  if (mediaType === VIDEO) {
589
- const context = deepAccess(bidReq, `mediaTypes.${VIDEO}.context`, 'instream');
617
+ const context = deepAccess(mediaTypes, `${VIDEO}.context`, 'instream');
590
618
  if (mediaTypePriceGranularity[`${VIDEO}-${context}`]) {
591
619
  return mediaTypePriceGranularity[`${VIDEO}-${context}`];
592
620
  }
@@ -597,14 +625,14 @@ export function getMediaTypeGranularity(mediaType, bidReq, mediaTypePriceGranula
597
625
 
598
626
  /**
599
627
  * This function returns the price granularity defined. It can be either publisher defined or default value
600
- * @param {string} mediaType
601
- * @param {BidRequest} bidReq
628
+ * @param bid bid response object
629
+ * @param index
602
630
  * @returns {string} granularity
603
631
  */
604
- export const getPriceGranularity = (mediaType, bidReq) => {
632
+ export const getPriceGranularity = (bid, {index = auctionManager.index} = {}) => {
605
633
  // Use the config value 'mediaTypeGranularity' if it has been set for mediaType, else use 'priceGranularity'
606
- const mediaTypeGranularity = getMediaTypeGranularity(mediaType, bidReq, config.getConfig('mediaTypePriceGranularity'));
607
- const granularity = (typeof mediaType === 'string' && mediaTypeGranularity) ? ((typeof mediaTypeGranularity === 'string') ? mediaTypeGranularity : 'custom') : config.getConfig('priceGranularity');
634
+ const mediaTypeGranularity = getMediaTypeGranularity(bid.mediaType, index.getMediaTypes(bid), config.getConfig('mediaTypePriceGranularity'));
635
+ const granularity = (typeof bid.mediaType === 'string' && mediaTypeGranularity) ? ((typeof mediaTypeGranularity === 'string') ? mediaTypeGranularity : 'custom') : config.getConfig('priceGranularity');
608
636
  return granularity;
609
637
  }
610
638
 
@@ -614,19 +642,19 @@ export const getPriceGranularity = (mediaType, bidReq) => {
614
642
  * @returns {function}
615
643
  */
616
644
  export const getPriceByGranularity = (granularity) => {
617
- return (bid, bidReq) => {
618
- granularity = granularity || getPriceGranularity(bid.mediaType, bidReq);
619
- if (granularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
645
+ return (bid) => {
646
+ const bidGranularity = granularity || getPriceGranularity(bid);
647
+ if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
620
648
  return bid.pbAg;
621
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
649
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
622
650
  return bid.pbDg;
623
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.LOW) {
651
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.LOW) {
624
652
  return bid.pbLg;
625
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.MEDIUM) {
653
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.MEDIUM) {
626
654
  return bid.pbMg;
627
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.HIGH) {
655
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.HIGH) {
628
656
  return bid.pbHg;
629
- } else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.CUSTOM) {
657
+ } else if (bidGranularity === CONSTANTS.GRANULARITY_OPTIONS.CUSTOM) {
630
658
  return bid.pbCg;
631
659
  }
632
660
  }
@@ -642,6 +670,34 @@ export const getAdvertiserDomain = () => {
642
670
  }
643
671
  }
644
672
 
673
+ // factory for key value objs
674
+ function createKeyVal(key, value) {
675
+ return {
676
+ key,
677
+ val: (typeof value === 'function')
678
+ ? function (bidResponse, bidReq) {
679
+ return value(bidResponse, bidReq);
680
+ }
681
+ : function (bidResponse) {
682
+ return getValue(bidResponse, value);
683
+ }
684
+ };
685
+ }
686
+
687
+ function defaultAdserverTargeting() {
688
+ const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
689
+ return [
690
+ createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
691
+ createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
692
+ createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
693
+ createKeyVal(TARGETING_KEYS.SIZE, 'size'),
694
+ createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
695
+ createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
696
+ createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'),
697
+ createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()),
698
+ ]
699
+ }
700
+
645
701
  /**
646
702
  * @param {string} mediaType
647
703
  * @param {string} bidderCode
@@ -649,40 +705,16 @@ export const getAdvertiserDomain = () => {
649
705
  * @returns {*}
650
706
  */
651
707
  export function getStandardBidderSettings(mediaType, bidderCode) {
652
- // factory for key value objs
653
- function createKeyVal(key, value) {
654
- return {
655
- key,
656
- val: (typeof value === 'function')
657
- ? function (bidResponse, bidReq) {
658
- return value(bidResponse, bidReq);
659
- }
660
- : function (bidResponse) {
661
- return getValue(bidResponse, value);
662
- }
663
- };
664
- }
665
708
  const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
709
+ const standardSettings = Object.assign({}, bidderSettings.settingsFor(null));
666
710
 
667
- let bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
668
- if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD]) {
669
- bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD] = {};
670
- }
671
- if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
672
- bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = [
673
- createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
674
- createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
675
- createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
676
- createKeyVal(TARGETING_KEYS.SIZE, 'size'),
677
- createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
678
- createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
679
- createKeyVal(TARGETING_KEYS.FORMAT, 'mediaType'),
680
- createKeyVal(TARGETING_KEYS.ADOMAIN, getAdvertiserDomain()),
681
- ]
711
+ if (!standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
712
+ standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = defaultAdserverTargeting();
682
713
  }
683
714
 
684
715
  if (mediaType === 'video') {
685
- const adserverTargeting = bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING];
716
+ const adserverTargeting = standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING].slice();
717
+ standardSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = adserverTargeting;
686
718
 
687
719
  // Adding hb_uuid + hb_cache_id
688
720
  [TARGETING_KEYS.UUID, TARGETING_KEYS.CACHE_ID].forEach(targetingKeyVal => {
@@ -692,7 +724,7 @@ export function getStandardBidderSettings(mediaType, bidderCode) {
692
724
  });
693
725
 
694
726
  // Adding hb_cache_host
695
- if (config.getConfig('cache.url') && (!bidderCode || deepAccess(bidderSettings, `${bidderCode}.sendStandardTargeting`) !== false)) {
727
+ if (config.getConfig('cache.url') && (!bidderCode || bidderSettings.get(bidderCode, 'sendStandardTargeting') !== false)) {
696
728
  const urlInfo = parseUrl(config.getConfig('cache.url'));
697
729
 
698
730
  if (typeof find(adserverTargeting, targetingKeyVal => targetingKeyVal.key === TARGETING_KEYS.CACHE_HOST) === 'undefined') {
@@ -703,33 +735,30 @@ export function getStandardBidderSettings(mediaType, bidderCode) {
703
735
  }
704
736
  }
705
737
  }
706
- return bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD];
738
+ return standardSettings;
707
739
  }
708
740
 
709
- export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
741
+ export function getKeyValueTargetingPairs(bidderCode, custBidObj, {index = auctionManager.index} = {}) {
710
742
  if (!custBidObj) {
711
743
  return {};
712
744
  }
713
-
745
+ const bidRequest = index.getBidRequest(custBidObj);
714
746
  var keyValues = {};
715
- var bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
716
747
 
717
748
  // 1) set the keys from "standard" setting or from prebid defaults
718
- if (bidderSettings) {
719
- // initialize default if not set
720
- const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
721
- setKeys(keyValues, standardSettings, custBidObj, bidReq);
722
-
723
- // 2) set keys from specific bidder setting override if they exist
724
- if (bidderCode && bidderSettings[bidderCode] && bidderSettings[bidderCode][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
725
- setKeys(keyValues, bidderSettings[bidderCode], custBidObj, bidReq);
726
- custBidObj.sendStandardTargeting = bidderSettings[bidderCode].sendStandardTargeting;
727
- }
749
+ // initialize default if not set
750
+ const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
751
+ setKeys(keyValues, standardSettings, custBidObj, bidRequest);
752
+
753
+ // 2) set keys from specific bidder setting override if they exist
754
+ if (bidderCode && bidderSettings.getOwn(bidderCode, CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING)) {
755
+ setKeys(keyValues, bidderSettings.ownSettingsFor(bidderCode), custBidObj, bidRequest);
756
+ custBidObj.sendStandardTargeting = bidderSettings.get(bidderCode, 'sendStandardTargeting');
728
757
  }
729
758
 
730
759
  // set native key value targeting
731
760
  if (custBidObj['native']) {
732
- keyValues = Object.assign({}, keyValues, getNativeTargeting(custBidObj, bidReq));
761
+ keyValues = Object.assign({}, keyValues, getNativeTargeting(custBidObj));
733
762
  }
734
763
 
735
764
  return keyValues;
@@ -776,19 +805,13 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) {
776
805
  export function adjustBids(bid) {
777
806
  let code = bid.bidderCode;
778
807
  let bidPriceAdjusted = bid.cpm;
779
- let bidCpmAdjustment;
780
- if ($$PREBID_GLOBAL$$.bidderSettings) {
781
- if (code && $$PREBID_GLOBAL$$.bidderSettings[code] && typeof $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment === 'function') {
782
- bidCpmAdjustment = $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment;
783
- } else if ($$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD] && typeof $$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD].bidCpmAdjustment === 'function') {
784
- bidCpmAdjustment = $$PREBID_GLOBAL$$.bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD].bidCpmAdjustment;
785
- }
786
- if (bidCpmAdjustment) {
787
- try {
788
- bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid));
789
- } catch (e) {
790
- logError('Error during bid adjustment', 'bidmanager.js', e);
791
- }
808
+ const bidCpmAdjustment = bidderSettings.get(code || null, 'bidCpmAdjustment');
809
+
810
+ if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') {
811
+ try {
812
+ bidPriceAdjusted = bidCpmAdjustment(bid.cpm, Object.assign({}, bid));
813
+ } catch (e) {
814
+ logError('Error during bid adjustment', 'bidmanager.js', e);
792
815
  }
793
816
  }
794
817
 
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Retrieves request-related bid data.
3
+ * All methods are designed to work with Bid (response) objects returned by bid adapters.
4
+ */
5
+ export function AuctionIndex(getAuctions) {
6
+ Object.assign(this, {
7
+ /**
8
+ * @param auctionId
9
+ * @returns {*} Auction instance for `auctionId`
10
+ */
11
+ getAuction({auctionId}) {
12
+ if (auctionId != null) {
13
+ return getAuctions()
14
+ .find(auction => auction.getAuctionId() === auctionId);
15
+ }
16
+ },
17
+ /**
18
+ * NOTE: you should prefer {@link #getMediaTypes} for looking up bid media types.
19
+ * @param transactionId
20
+ * @returns adUnit object for `transactionId`
21
+ */
22
+ getAdUnit({transactionId}) {
23
+ if (transactionId != null) {
24
+ return getAuctions()
25
+ .flatMap(a => a.getAdUnits())
26
+ .find(au => au.transactionId === transactionId);
27
+ }
28
+ },
29
+ /**
30
+ * @param transactionId
31
+ * @param requestId?
32
+ * @returns {*} mediaTypes object from bidRequest (through requestId) falling back to the adUnit (through transactionId).
33
+ *
34
+ * The bidRequest is given precedence because its mediaTypes can differ from the adUnit's (if bidder-specific labels are in use).
35
+ * Bids that have no associated request do not have labels either, and use the adUnit's mediaTypes.
36
+ */
37
+ getMediaTypes({transactionId, requestId}) {
38
+ if (requestId != null) {
39
+ const req = this.getBidRequest({requestId});
40
+ if (req != null && (transactionId == null || req.transactionId === transactionId)) {
41
+ return req.mediaTypes;
42
+ }
43
+ } else if (transactionId != null) {
44
+ const au = this.getAdUnit({transactionId});
45
+ if (au != null) {
46
+ return au.mediaTypes;
47
+ }
48
+ }
49
+ },
50
+ /**
51
+ * @param requestId?
52
+ * @param bidderRequestId?
53
+ * @returns {*} bidderRequest that matches both requestId and bidderRequestId (if either or both are provided).
54
+ *
55
+ * NOTE: Bid responses are not guaranteed to have a corresponding request.
56
+ */
57
+ getBidderRequest({requestId, bidderRequestId}) {
58
+ if (requestId != null || bidderRequestId != null) {
59
+ let bers = getAuctions().flatMap(a => a.getBidRequests());
60
+ if (bidderRequestId != null) {
61
+ bers = bers.filter(ber => ber.bidderRequestId === bidderRequestId);
62
+ }
63
+ if (requestId == null) {
64
+ return bers[0];
65
+ } else {
66
+ return bers.find(ber => ber.bids && ber.bids.find(br => br.bidId === requestId) != null)
67
+ }
68
+ }
69
+ },
70
+ /**
71
+ * @param requestId
72
+ * @returns {*} bidRequest object for requestId
73
+ *
74
+ * NOTE: Bid responses are not guaranteed to have a corresponding request.
75
+ */
76
+ getBidRequest({requestId}) {
77
+ if (requestId != null) {
78
+ return getAuctions()
79
+ .flatMap(a => a.getBidRequests())
80
+ .flatMap(ber => ber.bids)
81
+ .find(br => br && br.bidId === requestId);
82
+ }
83
+ }
84
+ });
85
+ }
@@ -22,6 +22,7 @@
22
22
  import { uniques, flatten, logWarn } from './utils.js';
23
23
  import { newAuction, getStandardBidderSettings, AUCTION_COMPLETED } from './auction.js';
24
24
  import find from 'core-js-pure/features/array/find.js';
25
+ import {AuctionIndex} from './auctionIndex.js';
25
26
 
26
27
  const CONSTANTS = require('./constants.json');
27
28
 
@@ -123,6 +124,8 @@ export function newAuctionManager() {
123
124
  _auctions.push(auction);
124
125
  }
125
126
 
127
+ auctionManager.index = new AuctionIndex(() => _auctions);
128
+
126
129
  return auctionManager;
127
130
  }
128
131
 
@@ -0,0 +1,69 @@
1
+ import {deepAccess, mergeDeep} from './utils.js';
2
+ import {getGlobal} from './prebidGlobal.js';
3
+
4
+ const CONSTANTS = require('./constants.json');
5
+
6
+ export class ScopedSettings {
7
+ constructor(getSettings, defaultScope) {
8
+ this.getSettings = getSettings;
9
+ this.defaultScope = defaultScope;
10
+ }
11
+
12
+ /**
13
+ * Get setting value at `path` under the given scope, falling back to the default scope if needed.
14
+ * If `scope` is `null`, get the setting's default value.
15
+ * @param scope {String|null}
16
+ * @param path {String}
17
+ * @returns {*}
18
+ */
19
+ get(scope, path) {
20
+ let value = this.getOwn(scope, path);
21
+ if (typeof value === 'undefined') {
22
+ value = this.getOwn(null, path);
23
+ }
24
+ return value;
25
+ }
26
+
27
+ /**
28
+ * Get the setting value at `path` *without* falling back to the default value.
29
+ * @param scope {String}
30
+ * @param path {String}
31
+ * @returns {*}
32
+ */
33
+ getOwn(scope, path) {
34
+ scope = this.#resolveScope(scope);
35
+ return deepAccess(this.getSettings(), `${scope}.${path}`)
36
+ }
37
+
38
+ /**
39
+ * @returns {string[]} all existing scopes except the default one.
40
+ */
41
+ getScopes() {
42
+ return Object.keys(this.getSettings()).filter((scope) => scope !== this.defaultScope);
43
+ }
44
+
45
+ /**
46
+ * @returns all settings in the given scope, merged with the settings for the default scope.
47
+ */
48
+ settingsFor(scope) {
49
+ return mergeDeep({}, this.ownSettingsFor(null), this.ownSettingsFor(scope));
50
+ }
51
+
52
+ /**
53
+ * @returns all settings in the given scope, *without* any of the default settings.
54
+ */
55
+ ownSettingsFor(scope) {
56
+ scope = this.#resolveScope(scope);
57
+ return this.getSettings()[scope] || {};
58
+ }
59
+
60
+ #resolveScope(scope) {
61
+ if (scope == null) {
62
+ return this.defaultScope;
63
+ } else {
64
+ return scope;
65
+ }
66
+ }
67
+ }
68
+
69
+ export const bidderSettings = new ScopedSettings(() => getGlobal().bidderSettings || {}, CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD);