prebid.js 6.4.0 → 6.8.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 (147) hide show
  1. package/integrationExamples/gpt/amp/creative.html +11 -33
  2. package/integrationExamples/gpt/x-domain/creative.html +53 -26
  3. package/modules/.submodules.json +2 -1
  4. package/modules/adagioBidAdapter.js +0 -8
  5. package/modules/adagioBidAdapter.md +1 -1
  6. package/modules/adbookpspBidAdapter.js +27 -10
  7. package/modules/adhashBidAdapter.js +3 -3
  8. package/modules/adkernelBidAdapter.js +2 -1
  9. package/modules/admanBidAdapter.js +10 -4
  10. package/modules/adomikAnalyticsAdapter.js +23 -11
  11. package/modules/adqueryIdSystem.js +103 -0
  12. package/modules/adqueryIdSystem.md +35 -0
  13. package/modules/adyoulikeBidAdapter.js +13 -9
  14. package/modules/appnexusBidAdapter.js +11 -0
  15. package/modules/bliinkBidAdapter.js +3 -2
  16. package/modules/brandmetricsRtdProvider.js +168 -0
  17. package/modules/brandmetricsRtdProvider.md +40 -0
  18. package/modules/colossussspBidAdapter.js +12 -8
  19. package/modules/colossussspBidAdapter.md +15 -1
  20. package/modules/compassBidAdapter.js +10 -3
  21. package/modules/consentManagement.js +7 -1
  22. package/modules/consumableBidAdapter.md +1 -1
  23. package/modules/criteoBidAdapter.js +10 -1
  24. package/modules/criteoIdSystem.js +29 -7
  25. package/modules/currency.js +26 -1
  26. package/modules/displayioBidAdapter.js +157 -0
  27. package/modules/displayioBidAdapter.md +148 -0
  28. package/modules/docereeBidAdapter.js +10 -1
  29. package/modules/docereeBidAdapter.md +2 -0
  30. package/modules/e_volutionBidAdapter.js +158 -0
  31. package/modules/glimpseBidAdapter.js +66 -44
  32. package/modules/gnetBidAdapter.js +3 -3
  33. package/modules/gnetBidAdapter.md +4 -4
  34. package/modules/gptPreAuction.js +55 -7
  35. package/modules/gumgumBidAdapter.js +56 -42
  36. package/modules/idImportLibrary.js +45 -8
  37. package/modules/idImportLibrary.md +4 -0
  38. package/modules/improvedigitalBidAdapter.js +24 -2
  39. package/modules/interactiveOffersBidAdapter.js +9 -6
  40. package/modules/ixBidAdapter.js +29 -12
  41. package/modules/jwplayerRtdProvider.js +71 -6
  42. package/modules/jwplayerRtdProvider.md +27 -11
  43. package/modules/kargoBidAdapter.js +2 -2
  44. package/modules/limelightDigitalBidAdapter.js +2 -1
  45. package/modules/livewrappedAnalyticsAdapter.js +3 -1
  46. package/modules/loglyliftBidAdapter.js +79 -0
  47. package/modules/loglyliftBidAdapter.md +55 -0
  48. package/modules/nextMillenniumBidAdapter.js +3 -1
  49. package/modules/oguryBidAdapter.js +9 -2
  50. package/modules/onetagBidAdapter.js +4 -2
  51. package/modules/optimeraRtdProvider.js +8 -1
  52. package/modules/ozoneBidAdapter.js +21 -64
  53. package/modules/pilotxBidAdapter.js +147 -0
  54. package/modules/pilotxBidAdapter.md +50 -0
  55. package/modules/proxistoreBidAdapter.js +0 -2
  56. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  57. package/modules/richaudienceBidAdapter.js +3 -2
  58. package/modules/riseBidAdapter.js +1 -1
  59. package/modules/rtbhouseBidAdapter.js +14 -4
  60. package/modules/rtdModule/index.js +14 -15
  61. package/modules/rubiconAnalyticsAdapter.js +3 -2
  62. package/modules/seedingAllianceBidAdapter.js +3 -3
  63. package/modules/sharethroughBidAdapter.js +12 -17
  64. package/modules/showheroes-bsBidAdapter.js +13 -2
  65. package/modules/sovrnBidAdapter.js +93 -18
  66. package/modules/sovrnBidAdapter.md +80 -2
  67. package/modules/synacormediaBidAdapter.js +31 -10
  68. package/modules/tappxBidAdapter.js +8 -5
  69. package/modules/teadsBidAdapter.js +1 -2
  70. package/modules/undertoneBidAdapter.js +17 -1
  71. package/modules/userId/eids.js +7 -1
  72. package/modules/userId/userId.md +8 -0
  73. package/modules/viewability.js +177 -0
  74. package/modules/viewability.md +87 -0
  75. package/modules/welectBidAdapter.js +106 -0
  76. package/modules/yahoosspBidAdapter.js +2 -0
  77. package/modules/yieldmoBidAdapter.js +23 -5
  78. package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
  79. package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
  80. package/package.json +1 -1
  81. package/src/adRendering.js +38 -0
  82. package/src/auction.js +44 -9
  83. package/src/config.js +27 -3
  84. package/src/hook.js +5 -1
  85. package/src/prebid.js +21 -21
  86. package/src/secureCreatives.js +114 -44
  87. package/src/utils.js +25 -4
  88. package/test/helpers/syncPromise.js +71 -0
  89. package/test/spec/auctionmanager_spec.js +148 -16
  90. package/test/spec/config_spec.js +279 -0
  91. package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
  92. package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
  93. package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
  94. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  95. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  96. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  97. package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
  98. package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
  99. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  100. package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
  101. package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
  102. package/test/spec/modules/compassBidAdapter_spec.js +1 -0
  103. package/test/spec/modules/consentManagement_spec.js +20 -0
  104. package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
  105. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  106. package/test/spec/modules/currency_spec.js +21 -6
  107. package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
  108. package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
  109. package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
  110. package/test/spec/modules/eids_spec.js +15 -0
  111. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  112. package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
  113. package/test/spec/modules/gptPreAuction_spec.js +177 -2
  114. package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
  115. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  116. package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
  117. package/test/spec/modules/ixBidAdapter_spec.js +104 -62
  118. package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
  119. package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
  120. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
  121. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
  122. package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
  123. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
  124. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  125. package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
  126. package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
  127. package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
  128. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  129. package/test/spec/modules/realTimeDataModule_spec.js +67 -5
  130. package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
  131. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  132. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  133. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
  134. package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
  135. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  136. package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
  137. package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
  138. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  139. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  140. package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
  141. package/test/spec/modules/userId_spec.js +68 -19
  142. package/test/spec/modules/viewability_spec.js +280 -0
  143. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  144. package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
  145. package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
  146. package/test/spec/unit/pbjs_api_spec.js +20 -2
  147. package/test/spec/unit/secureCreatives_spec.js +85 -0
@@ -1,12 +1,38 @@
1
- import { _each, getBidIdParameter, isArray, deepClone, parseUrl, getUniqueIdentifierStr, deepSetValue, logError, deepAccess } from '../src/utils.js';
1
+ import { _each, getBidIdParameter, isArray, deepClone, parseUrl, getUniqueIdentifierStr, deepSetValue, logError, deepAccess, isInteger, logWarn } from '../src/utils.js';
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js'
3
- import { BANNER } from '../src/mediaTypes.js'
3
+ import { ADPOD, BANNER, VIDEO } from '../src/mediaTypes.js'
4
4
  import { createEidsArray } from './userId/eids.js';
5
5
  import {config} from '../src/config.js';
6
6
 
7
+ const ORTB_VIDEO_PARAMS = {
8
+ 'mimes': (value) => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'),
9
+ 'minduration': (value) => isInteger(value),
10
+ 'maxduration': (value) => isInteger(value),
11
+ 'protocols': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 10),
12
+ 'w': (value) => isInteger(value),
13
+ 'h': (value) => isInteger(value),
14
+ 'startdelay': (value) => isInteger(value),
15
+ 'placement': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 5),
16
+ 'linearity': (value) => [1, 2].indexOf(value) !== -1,
17
+ 'skip': (value) => [0, 1].indexOf(value) !== -1,
18
+ 'skipmin': (value) => isInteger(value),
19
+ 'skipafter': (value) => isInteger(value),
20
+ 'sequence': (value) => isInteger(value),
21
+ 'battr': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 17),
22
+ 'maxextended': (value) => isInteger(value),
23
+ 'minbitrate': (value) => isInteger(value),
24
+ 'maxbitrate': (value) => isInteger(value),
25
+ 'boxingallowed': (value) => [0, 1].indexOf(value) !== -1,
26
+ 'playbackmethod': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 6),
27
+ 'playbackend': (value) => [1, 2, 3].indexOf(value) !== -1,
28
+ 'delivery': (value) => [1, 2, 3].indexOf(value) !== -1,
29
+ 'pos': (value) => Array.isArray(value) && value.every(v => v >= 0 && v <= 7),
30
+ 'api': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 6)
31
+ }
32
+
7
33
  export const spec = {
8
34
  code: 'sovrn',
9
- supportedMediaTypes: [BANNER],
35
+ supportedMediaTypes: [BANNER, VIDEO],
10
36
  gvlid: 13,
11
37
 
12
38
  /**
@@ -15,7 +41,12 @@ export const spec = {
15
41
  * @return boolean for whether or not a bid is valid
16
42
  */
17
43
  isBidRequestValid: function(bid) {
18
- return !!(bid.params.tagid && !isNaN(parseFloat(bid.params.tagid)) && isFinite(bid.params.tagid))
44
+ return !!(
45
+ bid.params.tagid &&
46
+ !isNaN(parseFloat(bid.params.tagid)) &&
47
+ isFinite(bid.params.tagid) &&
48
+ deepAccess(bid, 'mediaTypes.video.context') !== ADPOD
49
+ )
19
50
  },
20
51
 
21
52
  /**
@@ -50,13 +81,9 @@ export const spec = {
50
81
  }
51
82
  iv = iv || getBidIdParameter('iv', bid.params)
52
83
 
53
- let bidSizes = (bid.mediaTypes && bid.mediaTypes.banner && bid.mediaTypes.banner.sizes) || bid.sizes
54
- bidSizes = ((isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes])
55
- bidSizes = bidSizes.filter(size => isArray(size))
56
- const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)}))
57
84
  const floorInfo = (bid.getFloor && typeof bid.getFloor === 'function') ? bid.getFloor({
58
85
  currency: 'USD',
59
- mediaType: 'banner',
86
+ mediaType: bid.mediaTypes && bid.mediaTypes.banner ? 'banner' : 'video',
60
87
  size: '*'
61
88
  }) : {}
62
89
  floorInfo.floor = floorInfo.floor || getBidIdParameter('bidfloor', bid.params)
@@ -64,13 +91,24 @@ export const spec = {
64
91
  const imp = {
65
92
  adunitcode: bid.adUnitCode,
66
93
  id: bid.bidId,
67
- banner: {
94
+ tagid: String(getBidIdParameter('tagid', bid.params)),
95
+ bidfloor: floorInfo.floor
96
+ }
97
+
98
+ if (deepAccess(bid, 'mediaTypes.banner')) {
99
+ let bidSizes = deepAccess(bid, 'mediaTypes.banner.sizes') || bid.sizes
100
+ bidSizes = (isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes]
101
+ bidSizes = bidSizes.filter(size => isArray(size))
102
+ const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)}))
103
+
104
+ imp.banner = {
68
105
  format: processedSizes,
69
106
  w: 1,
70
107
  h: 1,
71
- },
72
- tagid: String(getBidIdParameter('tagid', bid.params)),
73
- bidfloor: floorInfo.floor
108
+ };
109
+ }
110
+ if (deepAccess(bid, 'mediaTypes.video')) {
111
+ imp.video = _buildVideoRequestObj(bid);
74
112
  }
75
113
 
76
114
  imp.ext = getBidIdParameter('ext', bid.ortb2Imp) || undefined
@@ -149,7 +187,7 @@ export const spec = {
149
187
  seatbid[0].bid &&
150
188
  seatbid[0].bid.length > 0) {
151
189
  seatbid[0].bid.map(sovrnBid => {
152
- sovrnBidResponses.push({
190
+ const bid = {
153
191
  requestId: sovrnBid.impid,
154
192
  cpm: parseFloat(sovrnBid.price),
155
193
  width: parseInt(sovrnBid.w),
@@ -158,11 +196,18 @@ export const spec = {
158
196
  dealId: sovrnBid.dealid || null,
159
197
  currency: 'USD',
160
198
  netRevenue: true,
161
- mediaType: BANNER,
162
- ad: decodeURIComponent(`${sovrnBid.adm}<img src="${sovrnBid.nurl}">`),
163
199
  ttl: sovrnBid.ext ? (sovrnBid.ext.ttl || 90) : 90,
164
200
  meta: { advertiserDomains: sovrnBid && sovrnBid.adomain ? sovrnBid.adomain : [] }
165
- });
201
+ }
202
+
203
+ if (!sovrnBid.nurl) {
204
+ bid.mediaType = VIDEO
205
+ bid.vastXml = decodeURIComponent(sovrnBid.adm)
206
+ } else {
207
+ bid.mediaType = BANNER
208
+ bid.ad = decodeURIComponent(`${sovrnBid.adm}<img src="${sovrnBid.nurl}">`)
209
+ }
210
+ sovrnBidResponses.push(bid);
166
211
  });
167
212
  }
168
213
  return sovrnBidResponses
@@ -209,4 +254,34 @@ export const spec = {
209
254
  },
210
255
  }
211
256
 
212
- registerBidder(spec);
257
+ function _buildVideoRequestObj(bid) {
258
+ const videoObj = {}
259
+ const videoAdUnitParams = deepAccess(bid, 'mediaTypes.video', {})
260
+ const videoBidderParams = deepAccess(bid, 'params.video', {})
261
+ const computedParams = {}
262
+
263
+ if (Array.isArray(videoAdUnitParams.playerSize)) {
264
+ const sizes = (Array.isArray(videoAdUnitParams.playerSize[0])) ? videoAdUnitParams.playerSize[0] : videoAdUnitParams.playerSize
265
+ computedParams.w = sizes[0]
266
+ computedParams.h = sizes[1]
267
+ }
268
+
269
+ const videoParams = {
270
+ ...computedParams,
271
+ ...videoAdUnitParams,
272
+ ...videoBidderParams
273
+ };
274
+
275
+ Object.keys(ORTB_VIDEO_PARAMS).forEach(paramName => {
276
+ if (videoParams.hasOwnProperty(paramName)) {
277
+ if (ORTB_VIDEO_PARAMS[paramName](videoParams[paramName])) {
278
+ videoObj[paramName] = videoParams[paramName]
279
+ } else {
280
+ logWarn(`The OpenRTB video param ${paramName} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.`);
281
+ }
282
+ }
283
+ })
284
+ return videoObj
285
+ }
286
+
287
+ registerBidder(spec)
@@ -10,9 +10,9 @@ Maintainer: jrosendahl@sovrn.com
10
10
 
11
11
  Sovrn's adapter integration to the Prebid library. Posts plain-text JSON to the /rtb/bid endpoint.
12
12
 
13
- # Test Parameters
13
+ # Banner Test Parameters
14
14
 
15
- ```
15
+ ```js
16
16
  var adUnits = [
17
17
  {
18
18
  code: 'test-leaderboard',
@@ -45,3 +45,81 @@ var adUnits = [
45
45
  }
46
46
  ]
47
47
  ```
48
+
49
+ # Video Test Parameters
50
+ ### Instream
51
+ ```js
52
+ var videoAdUnit = {
53
+ code: 'video1',
54
+ sizes: [640, 480],
55
+ mediaTypes: {
56
+ video: {
57
+ context: 'instream',
58
+ playerSize: [640, 480],
59
+ mimes: ['video/mp4'],
60
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
61
+ playbackmethod: [2],
62
+ skip: 1,
63
+ },
64
+ },
65
+ bids: [
66
+ {
67
+ bidder: 'sovrn',
68
+ // Prebid Server Bidder Params https://docs.prebid.org/dev-docs/pbs-bidders.html#sovrn
69
+ params: {
70
+ tagid: '315045',
71
+ bidfloor: '0.04',
72
+ },
73
+ },
74
+ ],
75
+ }
76
+ ```
77
+ ### Outstream
78
+ ```js
79
+ var adUnits = [
80
+ {
81
+ code: videoId,
82
+ mediaTypes: {
83
+ video: {
84
+ context: 'outstream',
85
+ playerSize: [640, 360],
86
+ mimes: ['video/mp4'],
87
+ protocols: [1, 2, 3, 4, 5, 6, 7, 8],
88
+ playbackmethod: [2],
89
+ skip: 1,
90
+ },
91
+ },
92
+ bids: [
93
+ {
94
+ bidder: 'sovrn',
95
+ // Prebid Server Bidder Params https://docs.prebid.org/dev-docs/pbs-bidders.html#sovrn
96
+ params: {
97
+ tagid: '315045',
98
+ bidfloor: '0.04',
99
+ },
100
+ },
101
+ ],
102
+ renderer: {
103
+ url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js',
104
+ render: function (bid) {
105
+ adResponse = {
106
+ ad: {
107
+ video: {
108
+ content: bid.vastXml,
109
+ player_height: bid.height,
110
+ player_width: bid.width,
111
+ },
112
+ },
113
+ }
114
+ // push to render queue because ANOutstreamVideo may not be loaded yet.
115
+ bid.renderer.push(() => {
116
+ ANOutstreamVideo.renderAd({
117
+ targetId: bid.adUnitCode,
118
+ adResponse: adResponse,
119
+ })
120
+ })
121
+ },
122
+ },
123
+ },
124
+ ]
125
+ ```
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- import { getAdUnitSizes, logWarn, deepSetValue } from '../src/utils.js';
3
+ import { getAdUnitSizes, logWarn, deepSetValue, isFn, isPlainObject } from '../src/utils.js';
4
4
  import { registerBidder } from '../src/adapters/bidderFactory.js';
5
5
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
6
6
  import includes from 'core-js-pure/features/array/includes.js';
@@ -67,11 +67,7 @@ export const spec = {
67
67
  } else {
68
68
  seatId = bid.params.seatId;
69
69
  }
70
- const tagIdOrplacementId = bid.params.tagId || bid.params.placementId;
71
- const bidFloor = bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : null;
72
- if (isNaN(bidFloor)) {
73
- logWarn(`Synacormedia: there is an invalid bid floor: ${bid.params.bidfloor}`);
74
- }
70
+ const tagIdOrPlacementId = bid.params.tagId || bid.params.placementId;
75
71
  let pos = parseInt(bid.params.pos, 10);
76
72
  if (isNaN(pos)) {
77
73
  logWarn(`Synacormedia: there is an invalid POS: ${bid.params.pos}`);
@@ -83,9 +79,9 @@ export const spec = {
83
79
 
84
80
  let imps = [];
85
81
  if (videoOrBannerKey === 'banner') {
86
- imps = this.buildBannerImpressions(adSizes, bid, tagIdOrplacementId, pos, bidFloor, videoOrBannerKey);
82
+ imps = this.buildBannerImpressions(adSizes, bid, tagIdOrPlacementId, pos, videoOrBannerKey);
87
83
  } else if (videoOrBannerKey === 'video') {
88
- imps = this.buildVideoImpressions(adSizes, bid, tagIdOrplacementId, pos, bidFloor, videoOrBannerKey);
84
+ imps = this.buildVideoImpressions(adSizes, bid, tagIdOrPlacementId, pos, videoOrBannerKey);
89
85
  }
90
86
  if (imps.length > 0) {
91
87
  imps.forEach(i => openRtbBidRequest.imp.push(i));
@@ -128,7 +124,7 @@ export const spec = {
128
124
  return eids;
129
125
  },
130
126
 
131
- buildBannerImpressions: function (adSizes, bid, tagIdOrPlacementId, pos, bidFloor, videoOrBannerKey) {
127
+ buildBannerImpressions: function (adSizes, bid, tagIdOrPlacementId, pos, videoOrBannerKey) {
132
128
  let format = [];
133
129
  let imps = [];
134
130
  adSizes.forEach((size, i) => {
@@ -151,6 +147,10 @@ export const spec = {
151
147
  },
152
148
  tagid: tagIdOrPlacementId,
153
149
  };
150
+ const bidFloor = getBidFloor(bid, 'banner', '*');
151
+ if (isNaN(bidFloor)) {
152
+ logWarn(`Synacormedia: there is an invalid bid floor: ${bid.params.bidfloor}`);
153
+ }
154
154
  if (bidFloor !== null && !isNaN(bidFloor)) {
155
155
  imp.bidfloor = bidFloor;
156
156
  }
@@ -159,7 +159,7 @@ export const spec = {
159
159
  return imps;
160
160
  },
161
161
 
162
- buildVideoImpressions: function(adSizes, bid, tagIdOrPlacementId, pos, bidFloor, videoOrBannerKey) {
162
+ buildVideoImpressions: function(adSizes, bid, tagIdOrPlacementId, pos, videoOrBannerKey) {
163
163
  let imps = [];
164
164
  adSizes.forEach((size, i) => {
165
165
  if (!size || size.length != 2) {
@@ -171,6 +171,11 @@ export const spec = {
171
171
  id: `${videoOrBannerKey.substring(0, 1)}${bid.bidId}-${size0}x${size1}`,
172
172
  tagid: tagIdOrPlacementId
173
173
  };
174
+ const bidFloor = getBidFloor(bid, 'video', size);
175
+ if (isNaN(bidFloor)) {
176
+ logWarn(`Synacormedia: there is an invalid bid floor: ${bid.params.bidfloor}`);
177
+ }
178
+
174
179
  if (bidFloor !== null && !isNaN(bidFloor)) {
175
180
  imp.bidfloor = bidFloor;
176
181
  }
@@ -287,4 +292,20 @@ export const spec = {
287
292
  }
288
293
  };
289
294
 
295
+ function getBidFloor(bid, mediaType, size) {
296
+ if (!isFn(bid.getFloor)) {
297
+ return bid.params.bidfloor ? parseFloat(bid.params.bidfloor) : null;
298
+ }
299
+ let floor = bid.getFloor({
300
+ currency: 'USD',
301
+ mediaType,
302
+ size
303
+ });
304
+
305
+ if (isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') {
306
+ return floor.floor;
307
+ }
308
+ return null;
309
+ }
310
+
290
311
  registerBidder(spec);
@@ -53,7 +53,14 @@ export const spec = {
53
53
  * @return boolean True if this is a valid bid, and false otherwise.
54
54
  */
55
55
  isBidRequestValid: function(bid) {
56
- return validBasic(bid) && validMediaType(bid)
56
+ // bid.params.host
57
+ if ((new RegExp(`^(vz.*|zz.*)\\.*$`, 'i')).test(bid.params.host)) { // New endpoint
58
+ if ((new RegExp(`^(zz.*)\\.*$`, 'i')).test(bid.params.host)) return validBasic(bid)
59
+ else return validBasic(bid) && validMediaType(bid)
60
+ } else { // This is backward compatible feature. It will be remove in the future
61
+ if ((new RegExp(`^(ZZ.*)\\.*$`, 'i')).test(bid.params.endpoint)) return validBasic(bid)
62
+ else return validBasic(bid) && validMediaType(bid)
63
+ }
57
64
  },
58
65
 
59
66
  /**
@@ -169,10 +176,6 @@ function validMediaType(bid) {
169
176
  logWarn(LOG_PREFIX, 'Please review the mandatory Tappx parameters for Video. Video context not supported.');
170
177
  return false;
171
178
  }
172
- if (typeof video.mimes == 'undefined') {
173
- logWarn(LOG_PREFIX, 'Please review the mandatory Tappx parameters for Video. Mimes param is mandatory.');
174
- return false;
175
- }
176
179
  }
177
180
 
178
181
  return true;
@@ -190,8 +190,7 @@ function buildRequestObject(bid) {
190
190
  const reqObj = {};
191
191
  let placementId = getValue(bid.params, 'placementId');
192
192
  let pageId = getValue(bid.params, 'pageId');
193
- const impressionData = deepAccess(bid, 'ortb2Imp.ext.data');
194
- const gpid = deepAccess(impressionData, 'pbadslot') || deepAccess(impressionData, 'adserver.adslot');
193
+ const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid');
195
194
 
196
195
  reqObj.sizes = getSizes(bid);
197
196
  reqObj.bidId = getBidIdParameter('bidId', bid);
@@ -12,6 +12,20 @@ const FRAME_USER_SYNC = 'https://cdn.undertone.com/js/usersync.html';
12
12
  const PIXEL_USER_SYNC_1 = 'https://usr.undertone.com/userPixel/syncOne?id=1&of=2';
13
13
  const PIXEL_USER_SYNC_2 = 'https://usr.undertone.com/userPixel/syncOne?id=2&of=2';
14
14
 
15
+ function getBidFloor(bidRequest, mediaType) {
16
+ if (typeof bidRequest.getFloor !== 'function') {
17
+ return 0;
18
+ }
19
+
20
+ const floor = bidRequest.getFloor({
21
+ currency: 'USD',
22
+ mediaType: mediaType,
23
+ size: '*'
24
+ });
25
+
26
+ return (floor && floor.currency === 'USD' && floor.floor) || 0;
27
+ }
28
+
15
29
  function getCanonicalUrl() {
16
30
  try {
17
31
  let doc = window.top.document;
@@ -134,6 +148,9 @@ export const spec = {
134
148
  params: bidReq.params
135
149
  };
136
150
  const videoMediaType = deepAccess(bidReq, 'mediaTypes.video');
151
+ const mediaType = videoMediaType ? VIDEO : BANNER;
152
+ bid.mediaType = mediaType;
153
+ bid.bidfloor = getBidFloor(bidReq, mediaType);
137
154
  if (videoMediaType) {
138
155
  bid.video = {
139
156
  playerSize: deepAccess(bidReq, 'mediaTypes.video.playerSize') || null,
@@ -142,7 +159,6 @@ export const spec = {
142
159
  maxDuration: deepAccess(bidReq, 'params.video.maxDuration') || null,
143
160
  skippable: deepAccess(bidReq, 'params.video.skippable') || null
144
161
  };
145
- bid.mediaType = 'video';
146
162
  }
147
163
  payload['x-ut-hb-params'].push(bid);
148
164
  });
@@ -257,7 +257,13 @@ const USER_IDS_CONFIG = {
257
257
  'connectId': {
258
258
  source: 'yahoo.com',
259
259
  atype: 3
260
- }
260
+ },
261
+
262
+ // Adquery ID
263
+ 'qid': {
264
+ source: 'adquery.io',
265
+ atype: 1
266
+ },
261
267
  };
262
268
 
263
269
  // this function will create an eid object for the given UserId sub-module
@@ -297,6 +297,14 @@ pbjs.setConfig({
297
297
  type: 'html5',
298
298
  expires: 15
299
299
  }
300
+ }
301
+ {
302
+ name: "qid",
303
+ storage: {
304
+ type: "html5",
305
+ name: "qid",
306
+ expires: 365
307
+ }
300
308
  }],
301
309
  syncDelay: 5000
302
310
  }
@@ -0,0 +1,177 @@
1
+ import { logWarn, logInfo, isStr, isFn, triggerPixel, insertHtmlIntoIframe } from '../src/utils.js';
2
+ import { getGlobal } from '../src/prebidGlobal.js';
3
+ import find from 'core-js-pure/features/array/find.js';
4
+
5
+ export const MODULE_NAME = 'viewability';
6
+
7
+ export function init() {
8
+ (getGlobal()).viewability = {
9
+ startMeasurement: startMeasurement,
10
+ stopMeasurement: stopMeasurement,
11
+ };
12
+
13
+ listenMessagesFromCreative();
14
+ }
15
+
16
+ const observers = {};
17
+
18
+ function isValid(vid, element, tracker, criteria) {
19
+ if (!element) {
20
+ logWarn(`${MODULE_NAME}: no html element provided`);
21
+ return false;
22
+ }
23
+
24
+ let validTracker = tracker &&
25
+ ((tracker.method === 'img' && isStr(tracker.value)) ||
26
+ (tracker.method === 'js' && isStr(tracker.value)) ||
27
+ (tracker.method === 'callback' && isFn(tracker.value)));
28
+
29
+ if (!validTracker) {
30
+ logWarn(`${MODULE_NAME}: invalid tracker`, tracker);
31
+ return false;
32
+ }
33
+
34
+ if (!criteria || !criteria.inViewThreshold || !criteria.timeInView) {
35
+ logWarn(`${MODULE_NAME}: missing criteria`, criteria);
36
+ return false;
37
+ }
38
+
39
+ if (!vid || observers[vid]) {
40
+ logWarn(`${MODULE_NAME}: must provide an unregistered vid`, vid);
41
+ return false;
42
+ }
43
+
44
+ return true;
45
+ }
46
+
47
+ function stopObserving(observer, vid, element) {
48
+ observer.unobserve(element);
49
+ observers[vid].done = true;
50
+ }
51
+
52
+ function fireViewabilityTracker(element, tracker) {
53
+ switch (tracker.method) {
54
+ case 'img':
55
+ triggerPixel(tracker.value, () => {
56
+ logInfo(`${MODULE_NAME}: viewability pixel fired`, tracker.value);
57
+ });
58
+ break;
59
+ case 'js':
60
+ insertHtmlIntoIframe(`<script src="${tracker.value}"></script>`);
61
+ break;
62
+ case 'callback':
63
+ tracker.value(element);
64
+ break;
65
+ }
66
+ }
67
+
68
+ function viewabilityCriteriaMet(observer, vid, element, tracker) {
69
+ stopObserving(observer, vid, element);
70
+ fireViewabilityTracker(element, tracker);
71
+ }
72
+
73
+ /**
74
+ * Start measuring viewability of an element
75
+ * @typedef {{ method: string='img','js','callback', value: string|function }} ViewabilityTracker { method: 'img', value: 'http://my.tracker/123' }
76
+ * @typedef {{ inViewThreshold: number, timeInView: number }} ViewabilityCriteria { inViewThreshold: 0.5, timeInView: 1000 }
77
+ * @param {string} vid unique viewability identifier
78
+ * @param {HTMLElement} element
79
+ * @param {ViewabilityTracker} tracker
80
+ * @param {ViewabilityCriteria} criteria
81
+ */
82
+ export function startMeasurement(vid, element, tracker, criteria) {
83
+ if (!isValid(vid, element, tracker, criteria)) {
84
+ return;
85
+ }
86
+
87
+ const options = {
88
+ root: null,
89
+ rootMargin: '0px',
90
+ threshold: criteria.inViewThreshold,
91
+ };
92
+
93
+ let observer;
94
+ let viewable = false;
95
+ let stateChange = (entries) => {
96
+ viewable = entries[0].isIntersecting;
97
+
98
+ if (viewable) {
99
+ observers[vid].timeoutId = window.setTimeout(() => {
100
+ viewabilityCriteriaMet(observer, vid, element, tracker);
101
+ }, criteria.timeInView);
102
+ } else if (observers[vid].timeoutId) {
103
+ window.clearTimeout(observers[vid].timeoutId);
104
+ }
105
+ };
106
+
107
+ observer = new IntersectionObserver(stateChange, options);
108
+ observers[vid] = {
109
+ observer: observer,
110
+ element: element,
111
+ timeoutId: null,
112
+ done: false,
113
+ };
114
+
115
+ observer.observe(element);
116
+
117
+ logInfo(`${MODULE_NAME}: startMeasurement called with:`, arguments);
118
+ }
119
+
120
+ /**
121
+ * Stop measuring viewability of an element
122
+ * @param {string} vid unique viewability identifier
123
+ */
124
+ export function stopMeasurement(vid) {
125
+ if (!vid || !observers[vid]) {
126
+ logWarn(`${MODULE_NAME}: must provide a registered vid`, vid);
127
+ return;
128
+ }
129
+
130
+ observers[vid].observer.unobserve(observers[vid].element);
131
+ if (observers[vid].timeoutId) {
132
+ window.clearTimeout(observers[vid].timeoutId);
133
+ }
134
+
135
+ // allow the observer under this vid to be created again
136
+ if (!observers[vid].done) {
137
+ delete observers[vid];
138
+ }
139
+ }
140
+
141
+ function listenMessagesFromCreative() {
142
+ window.addEventListener('message', receiveMessage, false);
143
+ }
144
+
145
+ /**
146
+ * Recieve messages from creatives
147
+ * @param {MessageEvent} evt
148
+ */
149
+ export function receiveMessage(evt) {
150
+ var key = evt.message ? 'message' : 'data';
151
+ var data = {};
152
+ try {
153
+ data = JSON.parse(evt[key]);
154
+ } catch (e) {
155
+ return;
156
+ }
157
+
158
+ if (!data || data.message !== 'Prebid Viewability') {
159
+ return;
160
+ }
161
+
162
+ switch (data.action) {
163
+ case 'startMeasurement':
164
+ let element = data.elementId && document.getElementById(data.elementId);
165
+ if (!element) {
166
+ element = find(document.getElementsByTagName('IFRAME'), iframe => (iframe.contentWindow || iframe.contentDocument.defaultView) == evt.source);
167
+ }
168
+
169
+ startMeasurement(data.vid, element, data.tracker, data.criteria);
170
+ break;
171
+ case 'stopMeasurement':
172
+ stopMeasurement(data.vid);
173
+ break;
174
+ }
175
+ }
176
+
177
+ init();