prebid.js 7.34.0 → 7.35.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 (169) hide show
  1. package/.devcontainer/devcontainer.json +2 -1
  2. package/.github/workflows/issue_tracker.yml +1 -1
  3. package/dist/33acrossBidAdapter.js +1 -1
  4. package/dist/33acrossIdSystem.js +1 -1
  5. package/dist/adagioBidAdapter.js +1 -1
  6. package/dist/adbookpspBidAdapter.js +1 -1
  7. package/dist/adgenerationBidAdapter.js +1 -1
  8. package/dist/adrelevantisBidAdapter.js +1 -1
  9. package/dist/adtrgtmeBidAdapter.js +1 -1
  10. package/dist/adxcgBidAdapter.js +1 -1
  11. package/dist/adyoulikeBidAdapter.js +1 -1
  12. package/dist/ajaBidAdapter.js +1 -1
  13. package/dist/amxBidAdapter.js +1 -1
  14. package/dist/amxIdSystem.js +1 -1
  15. package/dist/appierAnalyticsAdapter.js +1 -1
  16. package/dist/appnexusBidAdapter.js +1 -1
  17. package/dist/asoBidAdapter.js +1 -1
  18. package/dist/axonixBidAdapter.js +1 -1
  19. package/dist/bidglassBidAdapter.js +1 -1
  20. package/dist/big-richmediaBidAdapter.js +1 -1
  21. package/dist/bridgewellBidAdapter.js +1 -1
  22. package/dist/brightMountainMediaBidAdapter.js +1 -1
  23. package/dist/carodaBidAdapter.js +1 -1
  24. package/dist/chtnwBidAdapter.js +1 -1
  25. package/dist/concertBidAdapter.js +1 -1
  26. package/dist/connectadBidAdapter.js +1 -1
  27. package/dist/consentManagement.js +1 -1
  28. package/dist/consumableBidAdapter.js +1 -1
  29. package/dist/conversantBidAdapter.js +1 -1
  30. package/dist/craftBidAdapter.js +1 -1
  31. package/dist/criteoBidAdapter.js +1 -1
  32. package/dist/cwireBidAdapter.js +1 -1
  33. package/dist/dspxBidAdapter.js +1 -1
  34. package/dist/eplanningBidAdapter.js +1 -1
  35. package/dist/feedadBidAdapter.js +1 -1
  36. package/dist/finativeBidAdapter.js +1 -1
  37. package/dist/glimpseBidAdapter.js +1 -1
  38. package/dist/gmosspBidAdapter.js +1 -1
  39. package/dist/goldbachBidAdapter.js +1 -1
  40. package/dist/gridBidAdapter.js +1 -1
  41. package/dist/gridNMBidAdapter.js +1 -1
  42. package/dist/gumgumBidAdapter.js +1 -1
  43. package/dist/h12mediaBidAdapter.js +1 -1
  44. package/dist/hadronIdSystem.js +1 -1
  45. package/dist/id5IdSystem.js +1 -1
  46. package/dist/improvedigitalBidAdapter.js +1 -1
  47. package/dist/inmarBidAdapter.js +1 -1
  48. package/dist/insticatorBidAdapter.js +1 -1
  49. package/dist/ixBidAdapter.js +1 -1
  50. package/dist/justpremiumBidAdapter.js +1 -1
  51. package/dist/konduitAnalyticsAdapter.js +1 -1
  52. package/dist/kueezBidAdapter.js +1 -1
  53. package/dist/kueezRtbBidAdapter.js +1 -1
  54. package/dist/lassoBidAdapter.js +1 -1
  55. package/dist/lifestreetBidAdapter.js +1 -1
  56. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  57. package/dist/logicadBidAdapter.js +1 -1
  58. package/dist/loglyliftBidAdapter.js +1 -1
  59. package/dist/magniteAnalyticsAdapter.js +1 -1
  60. package/dist/malltvAnalyticsAdapter.js +1 -1
  61. package/dist/marsmediaBidAdapter.js +1 -1
  62. package/dist/mediafuseBidAdapter.js +1 -1
  63. package/dist/mediasquareBidAdapter.js +1 -1
  64. package/dist/mgidBidAdapter.js +1 -1
  65. package/dist/minutemediaBidAdapter.js +1 -1
  66. package/dist/nexx360BidAdapter.js +1 -1
  67. package/dist/not-for-prod/prebid.js +127 -137
  68. package/dist/oguryBidAdapter.js +1 -1
  69. package/dist/onetagBidAdapter.js +1 -1
  70. package/dist/ooloAnalyticsAdapter.js +1 -1
  71. package/dist/outbrainBidAdapter.js +1 -1
  72. package/dist/parrableIdSystem.js +1 -1
  73. package/dist/permutiveRtdProvider.js +1 -1
  74. package/dist/pixfutureBidAdapter.js +1 -1
  75. package/dist/prebid-core.js +1 -1
  76. package/dist/priceFloors.js +1 -1
  77. package/dist/publinkIdSystem.js +1 -1
  78. package/dist/pubmaticBidAdapter.js +1 -1
  79. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  80. package/dist/pulsepointBidAdapter.js +1 -1
  81. package/dist/pxyzBidAdapter.js +1 -1
  82. package/dist/quantcastBidAdapter.js +1 -1
  83. package/dist/readpeakBidAdapter.js +1 -1
  84. package/dist/relaidoBidAdapter.js +1 -1
  85. package/dist/rhythmoneBidAdapter.js +1 -1
  86. package/dist/riseBidAdapter.js +1 -1
  87. package/dist/rubiconAnalyticsAdapter.js +1 -1
  88. package/dist/rubiconBidAdapter.js +1 -1
  89. package/dist/seedingAllianceBidAdapter.js +1 -1
  90. package/dist/seedtagBidAdapter.js +1 -1
  91. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  92. package/dist/sharethroughBidAdapter.js +1 -1
  93. package/dist/shinezBidAdapter.js +1 -1
  94. package/dist/smaatoBidAdapter.js +1 -1
  95. package/dist/smartadserverBidAdapter.js +1 -1
  96. package/dist/smartxBidAdapter.js +1 -1
  97. package/dist/smartytechBidAdapter.js +1 -1
  98. package/dist/smilewantedBidAdapter.js +1 -1
  99. package/dist/sonobiBidAdapter.js +1 -1
  100. package/dist/sovrnAnalyticsAdapter.js +1 -1
  101. package/dist/sovrnBidAdapter.js +1 -1
  102. package/dist/sspBCBidAdapter.js +1 -1
  103. package/dist/sublimeBidAdapter.js +1 -1
  104. package/dist/synacormediaBidAdapter.js +1 -1
  105. package/dist/taboolaBidAdapter.js +1 -1
  106. package/dist/targetVideoBidAdapter.js +1 -1
  107. package/dist/teadsBidAdapter.js +1 -1
  108. package/dist/trionBidAdapter.js +1 -1
  109. package/dist/tripleliftBidAdapter.js +1 -1
  110. package/dist/ttdBidAdapter.js +1 -1
  111. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  112. package/dist/uid2IdSystem.js +1 -1
  113. package/dist/underdogmediaBidAdapter.js +1 -1
  114. package/dist/undertoneBidAdapter.js +1 -1
  115. package/dist/vidazooBidAdapter.js +1 -1
  116. package/dist/videobyteBidAdapter.js +1 -1
  117. package/dist/visxBidAdapter.js +1 -1
  118. package/dist/vuukleBidAdapter.js +1 -1
  119. package/dist/widespaceBidAdapter.js +1 -1
  120. package/dist/winrBidAdapter.js +1 -1
  121. package/dist/yahoosspBidAdapter.js +1 -1
  122. package/dist/yieldmoBidAdapter.js +1 -1
  123. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  124. package/dist/zeta_global_sspBidAdapter.js +1 -1
  125. package/dist/zeusPrimeRtdProvider.js +4 -14
  126. package/integrationExamples/gpt/hello_world.html +0 -0
  127. package/modules/adyoulikeBidAdapter.js +2 -0
  128. package/modules/consentManagement.js +33 -5
  129. package/modules/cwireBidAdapter.js +169 -242
  130. package/modules/cwireBidAdapter.md +15 -14
  131. package/modules/hadronIdSystem.js +37 -32
  132. package/modules/nexx360BidAdapter.js +1 -2
  133. package/modules/onetagBidAdapter.js +12 -1
  134. package/modules/outbrainBidAdapter.js +103 -6
  135. package/modules/permutiveRtdProvider.js +17 -12
  136. package/modules/priceFloors.js +7 -8
  137. package/modules/pulsepointBidAdapter.js +2 -0
  138. package/modules/smartadserverBidAdapter.js +39 -28
  139. package/modules/smartyadsBidAdapter.md +9 -0
  140. package/modules/smartytechBidAdapter.js +67 -10
  141. package/modules/smartytechBidAdapter.md +44 -33
  142. package/modules/sonobiBidAdapter.js +17 -10
  143. package/modules/taboolaBidAdapter.js +2 -1
  144. package/modules/vidazooBidAdapter.js +56 -22
  145. package/modules/zeta_global_sspBidAdapter.js +15 -0
  146. package/modules/zeusPrimeRtdProvider.js +3 -323
  147. package/modules/zeusPrimeRtdProvider.md +3 -0
  148. package/package.json +1 -1
  149. package/src/auction.js +2 -11
  150. package/src/prebid.js +8 -0
  151. package/src/utils/cpm.js +17 -0
  152. package/test/spec/modules/adyoulikeBidAdapter_spec.js +3 -0
  153. package/test/spec/modules/consentManagement_spec.js +49 -1
  154. package/test/spec/modules/cwireBidAdapter_spec.js +249 -335
  155. package/test/spec/modules/hadronIdSystem_spec.js +4 -6
  156. package/test/spec/modules/nexx360BidAdapter_spec.js +0 -4
  157. package/test/spec/modules/onetagBidAdapter_spec.js +43 -0
  158. package/test/spec/modules/outbrainBidAdapter_spec.js +182 -18
  159. package/test/spec/modules/pulsepointBidAdapter_spec.js +11 -1
  160. package/test/spec/modules/smartadserverBidAdapter_spec.js +116 -5
  161. package/test/spec/modules/smartytechBidAdapter_spec.js +172 -14
  162. package/test/spec/modules/sonobiBidAdapter_spec.js +2 -1
  163. package/test/spec/modules/taboolaBidAdapter_spec.js +12 -3
  164. package/test/spec/modules/userId_spec.js +19 -14
  165. package/test/spec/modules/vidazooBidAdapter_spec.js +61 -22
  166. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +8 -0
  167. package/test/spec/unit/pbjs_api_spec.js +14 -0
  168. package/test/spec/unit/utils/cpm_spec.js +64 -0
  169. package/test/spec/modules/zeusPrimeRtdProvider_spec.js +0 -410
@@ -61,6 +61,12 @@ function buildRequests(validBidRequests, bidderRequest) {
61
61
  consentRequired: bidderRequest.gdprConsent.gdprApplies
62
62
  };
63
63
  }
64
+ if (bidderRequest && bidderRequest.gppConsent) {
65
+ payload.gppConsent = {
66
+ consentString: bidderRequest.gppConsent.gppString,
67
+ applicableSections: bidderRequest.gppConsent.applicableSections
68
+ }
69
+ }
64
70
  if (bidderRequest && bidderRequest.uspConsent) {
65
71
  payload.usPrivacy = bidderRequest.uspConsent;
66
72
  }
@@ -340,7 +346,7 @@ function getSizes(sizes) {
340
346
  return ret;
341
347
  }
342
348
 
343
- function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
349
+ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) {
344
350
  let syncs = [];
345
351
  let params = '';
346
352
  if (gdprConsent) {
@@ -351,6 +357,11 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
351
357
  params += '&gdpr_consent=' + gdprConsent.consentString;
352
358
  }
353
359
  }
360
+ if (gppConsent) {
361
+ if (typeof gppConsent.gppString === 'string') {
362
+ params += '&gpp_consent=' + gppConsent.gppString;
363
+ }
364
+ }
354
365
  if (uspConsent && typeof uspConsent === 'string') {
355
366
  params += '&us_privacy=' + uspConsent;
356
367
  }
@@ -4,11 +4,13 @@
4
4
  import {
5
5
  registerBidder
6
6
  } from '../src/adapters/bidderFactory.js';
7
- import { NATIVE, BANNER } from '../src/mediaTypes.js';
8
- import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray } from '../src/utils.js';
7
+ import { NATIVE, BANNER, VIDEO } from '../src/mediaTypes.js';
8
+ import { OUTSTREAM } from '../src/video.js';
9
+ import { deepAccess, deepSetValue, replaceAuctionPrice, _map, isArray, logWarn } from '../src/utils.js';
9
10
  import { ajax } from '../src/ajax.js';
10
11
  import { config } from '../src/config.js';
11
12
  import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
13
+ import { Renderer } from '../src/Renderer.js';
12
14
 
13
15
  const BIDDER_CODE = 'outbrain';
14
16
  const GVLID = 164;
@@ -22,11 +24,12 @@ const NATIVE_PARAMS = {
22
24
  body: { id: 4, name: 'data', type: 2 },
23
25
  cta: { id: 1, type: 12, name: 'data' }
24
26
  };
27
+ const OUTSTREAM_RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
25
28
 
26
29
  export const spec = {
27
30
  code: BIDDER_CODE,
28
31
  gvlid: GVLID,
29
- supportedMediaTypes: [ NATIVE, BANNER ],
32
+ supportedMediaTypes: [ NATIVE, BANNER, VIDEO ],
30
33
  isBidRequestValid: (bid) => {
31
34
  if (typeof bid.params !== 'object') {
32
35
  return false;
@@ -50,7 +53,7 @@ export const spec = {
50
53
 
51
54
  return (
52
55
  !!config.getConfig('outbrain.bidderUrl') &&
53
- !!(bid.nativeParams || bid.sizes)
56
+ (!!(bid.nativeParams || bid.sizes) || isValidVideoRequest(bid))
54
57
  );
55
58
  },
56
59
  buildRequests: (validBidRequests, bidderRequest) => {
@@ -85,6 +88,8 @@ export const spec = {
85
88
  assets: getNativeAssets(bid)
86
89
  })
87
90
  }
91
+ } else if (isVideoRequest(bid)) {
92
+ imp.video = getVideoAsset(bid);
88
93
  } else {
89
94
  imp.banner = {
90
95
  format: transformSizes(bid.sizes)
@@ -163,7 +168,12 @@ export const spec = {
163
168
  return bids.map((bid, id) => {
164
169
  const bidResponse = bidResponses[id];
165
170
  if (bidResponse) {
166
- const type = bid.nativeParams ? NATIVE : BANNER;
171
+ let type = BANNER;
172
+ if (bid.nativeParams) {
173
+ type = NATIVE;
174
+ } else if (isVideoRequest(bid)) {
175
+ type = VIDEO;
176
+ }
167
177
  const bidObject = {
168
178
  requestId: bid.bidId,
169
179
  cpm: bidResponse.price,
@@ -176,10 +186,16 @@ export const spec = {
176
186
  };
177
187
  if (type === NATIVE) {
178
188
  bidObject.native = parseNative(bidResponse);
179
- } else {
189
+ } else if (type === BANNER) {
180
190
  bidObject.ad = bidResponse.adm;
181
191
  bidObject.width = bidResponse.w;
182
192
  bidObject.height = bidResponse.h;
193
+ } else if (type === VIDEO) {
194
+ bidObject.vastXml = bidResponse.adm;
195
+ const videoContext = deepAccess(bid, 'mediaTypes.video.context');
196
+ if (videoContext === OUTSTREAM) {
197
+ bidObject.renderer = createRenderer(bid);
198
+ }
183
199
  }
184
200
  bidObject.meta = {};
185
201
  if (bidResponse.adomain && bidResponse.adomain.length > 0) {
@@ -304,6 +320,27 @@ function getNativeAssets(bid) {
304
320
  }).filter(Boolean);
305
321
  }
306
322
 
323
+ function getVideoAsset(bid) {
324
+ const sizes = flatten(bid.mediaTypes.video.playerSize);
325
+ return {
326
+ w: parseInt(sizes[0], 10),
327
+ h: parseInt(sizes[1], 10),
328
+ protocols: bid.mediaTypes.video.protocols,
329
+ playbackmethod: bid.mediaTypes.video.playbackmethod,
330
+ mimes: bid.mediaTypes.video.mimes,
331
+ skip: bid.mediaTypes.video.skip,
332
+ delivery: bid.mediaTypes.video.delivery,
333
+ api: bid.mediaTypes.video.api,
334
+ minbitrate: bid.mediaTypes.video.minbitrate,
335
+ maxbitrate: bid.mediaTypes.video.maxbitrate,
336
+ minduration: bid.mediaTypes.video.minduration,
337
+ maxduration: bid.mediaTypes.video.maxduration,
338
+ startdelay: bid.mediaTypes.video.startdelay,
339
+ placement: bid.mediaTypes.video.placement,
340
+ linearity: bid.mediaTypes.video.linearity
341
+ };
342
+ }
343
+
307
344
  /* Turn bid request sizes into ut-compatible format */
308
345
  function transformSizes(requestSizes) {
309
346
  if (!isArray(requestSizes)) {
@@ -338,3 +375,63 @@ function _getFloor(bid, type) {
338
375
  }
339
376
  return null;
340
377
  }
378
+
379
+ function isVideoRequest(bid) {
380
+ return bid.mediaType === 'video' || !!deepAccess(bid, 'mediaTypes.video');
381
+ }
382
+
383
+ function createRenderer(bid) {
384
+ let config = {};
385
+ let playerUrl = OUTSTREAM_RENDERER_URL;
386
+ let render = function (bid) {
387
+ bid.renderer.push(() => {
388
+ window.ANOutstreamVideo.renderAd({
389
+ sizes: bid.sizes,
390
+ targetId: bid.adUnitCode,
391
+ adResponse: { content: bid.vastXml }
392
+ });
393
+ });
394
+ };
395
+
396
+ let externalRenderer = deepAccess(bid, 'mediaTypes.video.renderer');
397
+ if (!externalRenderer) {
398
+ externalRenderer = deepAccess(bid, 'renderer');
399
+ }
400
+
401
+ if (externalRenderer) {
402
+ config = externalRenderer.options;
403
+ playerUrl = externalRenderer.url;
404
+ render = externalRenderer.render;
405
+ }
406
+
407
+ const renderer = Renderer.install({
408
+ id: bid.adUnitCode,
409
+ url: playerUrl,
410
+ config: config,
411
+ adUnitCode: bid.adUnitCode,
412
+ loaded: false
413
+ });
414
+ try {
415
+ renderer.setRender(render);
416
+ } catch (err) {
417
+ logWarn('Prebid Error calling setRender on renderer', err);
418
+ }
419
+ return renderer;
420
+ }
421
+
422
+ function isValidVideoRequest(bid) {
423
+ const videoAdUnit = deepAccess(bid, 'mediaTypes.video')
424
+ if (!videoAdUnit) {
425
+ return false;
426
+ }
427
+
428
+ if (!Array.isArray(videoAdUnit.playerSize)) {
429
+ return false;
430
+ }
431
+
432
+ if (videoAdUnit.context == '') {
433
+ return false;
434
+ }
435
+
436
+ return true;
437
+ }
@@ -311,16 +311,19 @@ export function isPermutiveOnPage () {
311
311
  * @return {Object}
312
312
  */
313
313
  export function getSegments (maxSegs) {
314
- const legacySegs = readSegments('_psegs').map(Number).filter(seg => seg >= 1000000).map(String)
315
- const _ppam = readSegments('_ppam')
316
- const _pcrprs = readSegments('_pcrprs')
314
+ const legacySegs = readSegments('_psegs', []).map(Number).filter(seg => seg >= 1000000).map(String)
315
+ const _ppam = readSegments('_ppam', [])
316
+ const _pcrprs = readSegments('_pcrprs', [])
317
317
 
318
318
  const segments = {
319
319
  ac: [..._pcrprs, ..._ppam, ...legacySegs],
320
- rubicon: readSegments('_prubicons'),
321
- appnexus: readSegments('_papns'),
322
- gam: readSegments('_pdfps'),
323
- ssp: readSegments('_pssps'),
320
+ rubicon: readSegments('_prubicons', []),
321
+ appnexus: readSegments('_papns', []),
322
+ gam: readSegments('_pdfps', []),
323
+ ssp: readSegments('_pssps', {
324
+ cohorts: [],
325
+ ssps: []
326
+ }),
324
327
  }
325
328
 
326
329
  for (const bidder in segments) {
@@ -338,15 +341,17 @@ export function getSegments (maxSegs) {
338
341
 
339
342
  /**
340
343
  * Gets an array of segment IDs from LocalStorage
341
- * or returns an empty array
344
+ * or return the default value provided.
345
+ * @template A
342
346
  * @param {string} key
343
- * @return {string[]|number[]}
347
+ * @param {A} defaultValue
348
+ * @return {A}
344
349
  */
345
- function readSegments (key) {
350
+ function readSegments (key, defaultValue) {
346
351
  try {
347
- return JSON.parse(storage.getDataFromLocalStorage(key) || '[]')
352
+ return JSON.parse(storage.getDataFromLocalStorage(key)) || defaultValue
348
353
  } catch (e) {
349
- return []
354
+ return defaultValue
350
355
  }
351
356
  }
352
357
 
@@ -28,6 +28,7 @@ import {auctionManager} from '../src/auctionManager.js';
28
28
  import {IMP, PBS, registerOrtbProcessor, REQUEST} from '../src/pbjsORTB.js';
29
29
  import {timedAuctionHook, timedBidResponseHook} from '../src/utils/perfMetrics.js';
30
30
  import {beConvertCurrency} from '../src/utils/currency.js';
31
+ import {adjustCpm} from '../src/utils/cpm.js';
31
32
 
32
33
  /**
33
34
  * @summary This Module is intended to provide users with the ability to dynamically set and enforce price floors on a per auction basis.
@@ -179,12 +180,8 @@ function generatePossibleEnumerations(arrayOfFields, delimiter) {
179
180
  /**
180
181
  * @summary If a the input bidder has a registered cpmadjustment it returns the input CPM after being adjusted
181
182
  */
182
- export function getBiddersCpmAdjustment(bidderName, inputCpm, bid, bidRequest) {
183
- const adjustmentFunction = bidderSettings.get(bidderName, 'bidCpmAdjustment');
184
- if (adjustmentFunction) {
185
- return parseFloat(adjustmentFunction(inputCpm, { ...bid, cpm: inputCpm }, bidRequest));
186
- }
187
- return parseFloat(inputCpm);
183
+ export function getBiddersCpmAdjustment(inputCpm, bid, bidRequest) {
184
+ return parseFloat(adjustCpm(inputCpm, {...bid, cpm: inputCpm}, bidRequest));
188
185
  }
189
186
 
190
187
  /**
@@ -254,7 +251,7 @@ export function getFloor(requestParams = {currency: 'USD', mediaType: '*', size:
254
251
  if (inverseFunction) {
255
252
  floorInfo.matchingFloor = inverseFunction(floorInfo.matchingFloor, bidRequest);
256
253
  } else {
257
- let cpmAdjustment = getBiddersCpmAdjustment(bidRequest.bidder, floorInfo.matchingFloor, {}, bidRequest);
254
+ let cpmAdjustment = getBiddersCpmAdjustment(floorInfo.matchingFloor, null, bidRequest);
258
255
  floorInfo.matchingFloor = cpmAdjustment ? calculateAdjustedFloor(floorInfo.matchingFloor, cpmAdjustment) : floorInfo.matchingFloor;
259
256
  }
260
257
  }
@@ -313,6 +310,8 @@ export function getFloorDataFromAdUnits(adUnits) {
313
310
  // copy over the new rules into our values object
314
311
  Object.assign(accum.values, newRules);
315
312
  }
313
+ } else if (adUnit.floors != null) {
314
+ logWarn(`adUnit '${adUnit.code}' provides an invalid \`floor\` definition, it will be ignored for floor calculations`, adUnit);
316
315
  }
317
316
  return accum;
318
317
  }, {});
@@ -737,7 +736,7 @@ export const addBidResponseHook = timedBidResponseHook('priceFloors', function a
737
736
  }
738
737
 
739
738
  // ok we got the bid response cpm in our desired currency. Now we need to run the bidders CPMAdjustment function if it exists
740
- adjustedCpm = getBiddersCpmAdjustment(bid.bidderCode, adjustedCpm, bid, matchingBidRequest);
739
+ adjustedCpm = getBiddersCpmAdjustment(adjustedCpm, bid, matchingBidRequest);
741
740
 
742
741
  // add necessary data information for analytics adapters / floor providers would possibly need
743
742
  addFloorDataToBid(floorData, floorInfo, bid, adjustedCpm);
@@ -16,6 +16,7 @@ const DEFAULT_BID_TTL = 20;
16
16
  const DEFAULT_CURRENCY = 'USD';
17
17
  const DEFAULT_NET_REVENUE = true;
18
18
  const KNOWN_PARAMS = ['cp', 'ct', 'cf', 'video', 'battr', 'bcat', 'badv', 'bidfloor'];
19
+ const DEFAULT_TMAX = 500;
19
20
 
20
21
  /**
21
22
  * PulsePoint Bid Adapter.
@@ -54,6 +55,7 @@ export const spec = {
54
55
  user: user(bidRequests[0], bidderRequest),
55
56
  regs: regs(bidderRequest),
56
57
  source: source(bidRequests[0].schain),
58
+ tmax: bidderRequest.timeout || DEFAULT_TMAX,
57
59
  };
58
60
  return {
59
61
  method: 'POST',
@@ -13,6 +13,7 @@ export const spec = {
13
13
  gvlid: GVL_ID,
14
14
  aliases: ['smart'], // short code
15
15
  supportedMediaTypes: [BANNER, VIDEO],
16
+
16
17
  /**
17
18
  * Determines whether or not the given bid request is valid.
18
19
  *
@@ -131,7 +132,6 @@ export const spec = {
131
132
  */
132
133
  buildRequests: function (validBidRequests, bidderRequest) {
133
134
  // use bidderRequest.bids[] to get bidder-dependent request info
134
-
135
135
  const adServerCurrency = config.getConfig('currency.adServerCurrency');
136
136
  const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data'));
137
137
  const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data'));
@@ -144,7 +144,6 @@ export const spec = {
144
144
  pageid: bid.params.pageId,
145
145
  formatid: bid.params.formatId,
146
146
  currencyCode: adServerCurrency,
147
- bidfloor: bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency),
148
147
  targeting: bid.params.target && bid.params.target !== '' ? bid.params.target : undefined,
149
148
  buid: bid.params.buId && bid.params.buId !== '' ? bid.params.buId : undefined,
150
149
  appname: bid.params.appName && bid.params.appName !== '' ? bid.params.appName : undefined,
@@ -161,10 +160,21 @@ export const spec = {
161
160
  sdc: sellerDefinedContext
162
161
  };
163
162
 
164
- if (bidderRequest && bidderRequest.gdprConsent) {
165
- payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent;
166
- payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
167
- payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side
163
+ if (bidderRequest) {
164
+ if (bidderRequest.gdprConsent) {
165
+ payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent;
166
+ payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
167
+ payload.gdpr = bidderRequest.gdprConsent.gdprApplies; // we're handling the undefined case server side
168
+ }
169
+
170
+ if (bidderRequest.gppConsent) {
171
+ payload.gpp = bidderRequest.gppConsent.gppString;
172
+ payload.gpp_sid = bidderRequest.gppConsent.applicableSections;
173
+ }
174
+
175
+ if (bidderRequest.uspConsent) {
176
+ payload.us_privacy = bidderRequest.uspConsent;
177
+ }
168
178
  }
169
179
 
170
180
  if (bid && bid.userId) {
@@ -175,24 +185,28 @@ export const spec = {
175
185
  payload.us_privacy = bidderRequest.uspConsent;
176
186
  }
177
187
 
178
- const videoMediaType = deepAccess(bid, 'mediaTypes.video');
179
188
  const bannerMediaType = deepAccess(bid, 'mediaTypes.banner');
180
- const isAdUnitContainingVideo = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream');
181
- if (!isAdUnitContainingVideo && bannerMediaType) {
182
- payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes);
183
- bidRequests.push(spec.createServerRequest(payload, bid.params.domain));
184
- } else if (isAdUnitContainingVideo && !bannerMediaType) {
185
- spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video);
186
- bidRequests.push(spec.createServerRequest(payload, bid.params.domain));
187
- } else if (isAdUnitContainingVideo && bannerMediaType) {
188
- // If there are video and banner media types in the ad unit, we clone the payload
189
- // to create a specific one for video.
190
- let videoPayload = deepClone(payload);
189
+ const videoMediaType = deepAccess(bid, 'mediaTypes.video');
190
+ const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream');
191
+
192
+ if (bannerMediaType || isSupportedVideoContext) {
193
+ let type;
194
+ if (bannerMediaType) {
195
+ type = BANNER;
196
+ payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes);
191
197
 
192
- spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video);
193
- bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain));
198
+ if (isSupportedVideoContext) {
199
+ let videoPayload = deepClone(payload);
200
+ spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video);
201
+ videoPayload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, VIDEO);
202
+ bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain));
203
+ }
204
+ } else {
205
+ type = VIDEO;
206
+ spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video);
207
+ }
194
208
 
195
- payload.sizes = spec.adaptBannerSizes(bannerMediaType.sizes);
209
+ payload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type);
196
210
  bidRequests.push(spec.createServerRequest(payload, bid.params.domain));
197
211
  } else {
198
212
  bidRequests.push({});
@@ -253,24 +267,21 @@ export const spec = {
253
267
  *
254
268
  * @param {object} bid Bid request object
255
269
  * @param {string} currency Ad server currency
270
+ * @param {string} mediaType Bid media type
256
271
  * @return {number} Floor price
257
272
  */
258
- getBidFloor: function (bid, currency) {
273
+ getBidFloor: function (bid, currency, mediaType) {
259
274
  if (!isFn(bid.getFloor)) {
260
275
  return DEFAULT_FLOOR;
261
276
  }
262
277
 
263
278
  const floor = bid.getFloor({
264
279
  currency: currency || 'USD',
265
- mediaType: '*',
280
+ mediaType,
266
281
  size: '*'
267
282
  });
268
283
 
269
- if (isPlainObject(floor) && !isNaN(floor.floor)) {
270
- return floor.floor;
271
- }
272
-
273
- return DEFAULT_FLOOR;
284
+ return isPlainObject(floor) && !isNaN(floor.floor) ? floor.floor : DEFAULT_FLOOR;
274
285
  },
275
286
 
276
287
  /**
@@ -10,6 +10,15 @@ Maintainer: supply@smartyads.com
10
10
 
11
11
  Module that connects to SmartyAds' demand sources
12
12
 
13
+ # Parameters
14
+
15
+ | Name | Scope | Description | Example |
16
+ | :------------ | :------- | :------------------------ | :------------------- |
17
+ | `sourceid` | required (for prebid.js) | placement ID | "0" |
18
+ | `host` | required (for prebid-server) | const value, set to "prebid" | "prebid" |
19
+ | `accountid` | required (for prebid-server) | partner ID | "1901" |
20
+ | `traffic` | optional (for prebid.js) | Configures the mediaType that should be used. Values can be banner, native or video | "banner" |
21
+
13
22
  # Test Parameters
14
23
  ```
15
24
  var adUnits = [
@@ -1,29 +1,77 @@
1
+ import {buildUrl, deepAccess} from '../src/utils.js'
2
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
1
3
  import {registerBidder} from '../src/adapters/bidderFactory.js';
2
- import {buildUrl} from '../src/utils.js'
3
4
 
4
5
  const BIDDER_CODE = 'smartytech';
5
6
  export const ENDPOINT_PROTOCOL = 'https';
6
7
  export const ENDPOINT_DOMAIN = 'server.smartytech.io';
7
- export const ENDPOINT_PATH = '/hb/bidder';
8
+ export const ENDPOINT_PATH = '/hb/v2/bidder';
8
9
 
9
10
  export const spec = {
11
+ supportedMediaTypes: [ BANNER, VIDEO ],
10
12
  code: BIDDER_CODE,
11
13
 
12
14
  isBidRequestValid: function (bidRequest) {
13
- return !!parseInt(bidRequest.params.endpointId);
15
+ return (
16
+ !!parseInt(bidRequest.params.endpointId) &&
17
+ spec._validateBanner(bidRequest) &&
18
+ spec._validateVideo(bidRequest)
19
+ );
20
+ },
21
+
22
+ _validateBanner: function(bidRequest) {
23
+ const bannerAdUnit = deepAccess(bidRequest, 'mediaTypes.banner');
24
+
25
+ if (bannerAdUnit === undefined) {
26
+ return true;
27
+ }
28
+
29
+ if (!Array.isArray(bannerAdUnit.sizes)) {
30
+ return false;
31
+ }
32
+
33
+ return true;
34
+ },
35
+
36
+ _validateVideo: function(bidRequest) {
37
+ const videoAdUnit = deepAccess(bidRequest, 'mediaTypes.video');
38
+
39
+ if (videoAdUnit === undefined) {
40
+ return true;
41
+ }
42
+
43
+ if (!Array.isArray(videoAdUnit.playerSize)) {
44
+ return false;
45
+ }
46
+
47
+ if (!videoAdUnit.context) {
48
+ return false;
49
+ }
50
+
51
+ return true;
14
52
  },
15
53
 
16
54
  buildRequests: function (validBidRequests, bidderRequest) {
17
55
  const referer = bidderRequest?.refererInfo?.page || window.location.href;
18
56
 
19
57
  const bidRequests = validBidRequests.map((validBidRequest) => {
20
- return {
58
+ let video = deepAccess(validBidRequest, 'mediaTypes.video', false);
59
+ let banner = deepAccess(validBidRequest, 'mediaTypes.banner', false);
60
+
61
+ let oneRequest = {
21
62
  endpointId: validBidRequest.params.endpointId,
22
63
  adUnitCode: validBidRequest.adUnitCode,
23
- sizes: validBidRequest.sizes,
24
- bidId: validBidRequest.bidId,
25
- referer: referer
64
+ referer: referer,
65
+ bidId: validBidRequest.bidId
26
66
  };
67
+
68
+ if (video) {
69
+ oneRequest.video = video;
70
+ } else if (banner) {
71
+ oneRequest.banner = banner;
72
+ }
73
+
74
+ return oneRequest
27
75
  });
28
76
 
29
77
  let adPartnerRequestUrl = buildUrl({
@@ -55,12 +103,14 @@ export const spec = {
55
103
  bid: validBids.find(b => b.adUnitCode === key),
56
104
  response: responseBody[key]
57
105
  }
58
- }).map(item => spec.adResponse(item.bid.bidId, item.response));
106
+ }).map(item => spec._adResponse(item.bid, item.response));
59
107
  },
60
108
 
61
- adResponse: function (requestId, response) {
109
+ _adResponse: function (request, response) {
62
110
  const bidObject = {
63
- requestId,
111
+ requestId: request.bidId,
112
+ adUnitCode: request.adUnitCode,
113
+ bidderCode: BIDDER_CODE,
64
114
  ad: response.ad,
65
115
  cpm: response.cpm,
66
116
  width: response.width,
@@ -69,7 +119,14 @@ export const spec = {
69
119
  creativeId: response.creativeId,
70
120
  netRevenue: true,
71
121
  currency: response.currency,
122
+ mediaType: BANNER
72
123
  }
124
+
125
+ if (response.mediaType === VIDEO) {
126
+ bidObject.vastXml = response.ad;
127
+ bidObject.mediaType = VIDEO;
128
+ }
129
+
73
130
  return bidObject;
74
131
  },
75
132
 
@@ -1,44 +1,55 @@
1
1
  # Overview
2
2
 
3
- Module Name: SmartyTech Bidder Adapter
4
-
5
- Module Type: Bidder Adapter
6
-
3
+ ```
4
+ Module Name: SmartyTech Bid Adapter
5
+ Module Type: Bidder Adapter
7
6
  Maintainer: info@adpartner.pro
7
+ ```
8
8
 
9
9
  # Description
10
10
 
11
- You can use this adapter to get a bid from smartytech.io.
11
+ Connects to SmartyTech's exchange for bids.
12
12
 
13
- About us : https://smartytech.io
13
+ SmartyTech bid adapter supports Banner and Video
14
14
 
15
- # Test Parameters
15
+ # Sample Ad Unit: For Publishers
16
+ ## Sample Banner Ad Unit
17
+ ```
18
+ var adUnits = [{
19
+ code: '/123123123/prebidjs-banner',
20
+ mediaTypes: {
21
+ banner: {
22
+ sizes: [
23
+ [300, 301],
24
+ [300, 250]
25
+ ]
26
+ }
27
+ },
28
+ bids: [{
29
+ bidder: 'smartytech',
30
+ params: {
31
+ endpointId: 12
32
+ }
33
+ }]
34
+ }];
35
+ ```
16
36
 
17
- ```javascript
18
- var adUnits = [
19
- {
20
- code: 'div-smartytech-example',
21
- sizes: [[300, 250]],
22
- bids: [
23
- {
24
- bidder: "smartytech",
25
- params: {
26
- endpointId: 14
27
- }
28
- }
29
- ]
37
+ ## Sample Video Ad Unit
38
+ ```
39
+ var videoAdUnit = {
40
+ code: '/123123123/video-vast-banner',
41
+ mediaTypes: {
42
+ video: {
43
+ context: 'instream',
44
+ playerSize: [640, 480],
45
+ mimes: ['video/mp4'],
46
+ }
30
47
  },
31
- {
32
- code: 'div-smartytech-example-2',
33
- sizes: [[300, 250]],
34
- bids: [
35
- {
36
- bidder: "smartytech",
37
- params: {
38
- endpointId: 14
39
- }
40
- }
41
- ]
42
- }
43
- ];
48
+ bids: [{
49
+ bidder: 'smartytech',
50
+ params: {
51
+ endpointId: 12
52
+ }
53
+ }]
54
+ };
44
55
  ```