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.
- package/integrationExamples/gpt/amp/creative.html +11 -33
- package/integrationExamples/gpt/x-domain/creative.html +53 -26
- package/modules/.submodules.json +2 -1
- package/modules/adagioBidAdapter.js +0 -8
- package/modules/adagioBidAdapter.md +1 -1
- package/modules/adbookpspBidAdapter.js +27 -10
- package/modules/adhashBidAdapter.js +3 -3
- package/modules/adkernelBidAdapter.js +2 -1
- package/modules/admanBidAdapter.js +10 -4
- package/modules/adomikAnalyticsAdapter.js +23 -11
- package/modules/adqueryIdSystem.js +103 -0
- package/modules/adqueryIdSystem.md +35 -0
- package/modules/adyoulikeBidAdapter.js +13 -9
- package/modules/appnexusBidAdapter.js +11 -0
- package/modules/bliinkBidAdapter.js +3 -2
- package/modules/brandmetricsRtdProvider.js +168 -0
- package/modules/brandmetricsRtdProvider.md +40 -0
- package/modules/colossussspBidAdapter.js +12 -8
- package/modules/colossussspBidAdapter.md +15 -1
- package/modules/compassBidAdapter.js +10 -3
- package/modules/consentManagement.js +7 -1
- package/modules/consumableBidAdapter.md +1 -1
- package/modules/criteoBidAdapter.js +10 -1
- package/modules/criteoIdSystem.js +29 -7
- package/modules/currency.js +26 -1
- package/modules/displayioBidAdapter.js +157 -0
- package/modules/displayioBidAdapter.md +148 -0
- package/modules/docereeBidAdapter.js +10 -1
- package/modules/docereeBidAdapter.md +2 -0
- package/modules/e_volutionBidAdapter.js +158 -0
- package/modules/glimpseBidAdapter.js +66 -44
- package/modules/gnetBidAdapter.js +3 -3
- package/modules/gnetBidAdapter.md +4 -4
- package/modules/gptPreAuction.js +55 -7
- package/modules/gumgumBidAdapter.js +56 -42
- package/modules/idImportLibrary.js +45 -8
- package/modules/idImportLibrary.md +4 -0
- package/modules/improvedigitalBidAdapter.js +24 -2
- package/modules/interactiveOffersBidAdapter.js +9 -6
- package/modules/ixBidAdapter.js +29 -12
- package/modules/jwplayerRtdProvider.js +71 -6
- package/modules/jwplayerRtdProvider.md +27 -11
- package/modules/kargoBidAdapter.js +2 -2
- package/modules/limelightDigitalBidAdapter.js +2 -1
- package/modules/livewrappedAnalyticsAdapter.js +3 -1
- package/modules/loglyliftBidAdapter.js +79 -0
- package/modules/loglyliftBidAdapter.md +55 -0
- package/modules/nextMillenniumBidAdapter.js +3 -1
- package/modules/oguryBidAdapter.js +9 -2
- package/modules/onetagBidAdapter.js +4 -2
- package/modules/optimeraRtdProvider.js +8 -1
- package/modules/ozoneBidAdapter.js +21 -64
- package/modules/pilotxBidAdapter.js +147 -0
- package/modules/pilotxBidAdapter.md +50 -0
- package/modules/proxistoreBidAdapter.js +0 -2
- package/modules/pubmaticAnalyticsAdapter.js +16 -0
- package/modules/richaudienceBidAdapter.js +3 -2
- package/modules/riseBidAdapter.js +1 -1
- package/modules/rtbhouseBidAdapter.js +14 -4
- package/modules/rtdModule/index.js +14 -15
- package/modules/rubiconAnalyticsAdapter.js +3 -2
- package/modules/seedingAllianceBidAdapter.js +3 -3
- package/modules/sharethroughBidAdapter.js +12 -17
- package/modules/showheroes-bsBidAdapter.js +13 -2
- package/modules/sovrnBidAdapter.js +93 -18
- package/modules/sovrnBidAdapter.md +80 -2
- package/modules/synacormediaBidAdapter.js +31 -10
- package/modules/tappxBidAdapter.js +8 -5
- package/modules/teadsBidAdapter.js +1 -2
- package/modules/undertoneBidAdapter.js +17 -1
- package/modules/userId/eids.js +7 -1
- package/modules/userId/userId.md +8 -0
- package/modules/viewability.js +177 -0
- package/modules/viewability.md +87 -0
- package/modules/welectBidAdapter.js +106 -0
- package/modules/yahoosspBidAdapter.js +2 -0
- package/modules/yieldmoBidAdapter.js +23 -5
- package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
- package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
- package/package.json +1 -1
- package/src/adRendering.js +38 -0
- package/src/auction.js +44 -9
- package/src/config.js +27 -3
- package/src/hook.js +5 -1
- package/src/prebid.js +21 -21
- package/src/secureCreatives.js +114 -44
- package/src/utils.js +25 -4
- package/test/helpers/syncPromise.js +71 -0
- package/test/spec/auctionmanager_spec.js +148 -16
- package/test/spec/config_spec.js +279 -0
- package/test/spec/modules/adagioBidAdapter_spec.js +0 -10
- package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
- package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
- package/test/spec/modules/admanBidAdapter_spec.js +2 -2
- package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
- package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
- package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
- package/test/spec/modules/appnexusBidAdapter_spec.js +27 -0
- package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
- package/test/spec/modules/brandmetricsRtdProvider_spec.js +191 -0
- package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
- package/test/spec/modules/compassBidAdapter_spec.js +1 -0
- package/test/spec/modules/consentManagement_spec.js +20 -0
- package/test/spec/modules/criteoBidAdapter_spec.js +21 -0
- package/test/spec/modules/criteoIdSystem_spec.js +6 -3
- package/test/spec/modules/currency_spec.js +21 -6
- package/test/spec/modules/displayioBidAdapter_spec.js +239 -0
- package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
- package/test/spec/modules/e_volutionBidAdapter_spec.js +242 -0
- package/test/spec/modules/eids_spec.js +15 -0
- package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
- package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
- package/test/spec/modules/gptPreAuction_spec.js +177 -2
- package/test/spec/modules/gumgumBidAdapter_spec.js +46 -0
- package/test/spec/modules/idImportLibrary_spec.js +197 -10
- package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
- package/test/spec/modules/ixBidAdapter_spec.js +104 -62
- package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
- package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
- package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
- package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
- package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
- package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
- package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
- package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
- package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
- package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
- package/test/spec/modules/realTimeDataModule_spec.js +67 -5
- package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
- package/test/spec/modules/riseBidAdapter_spec.js +1 -1
- package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
- package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
- package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
- package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
- package/test/spec/modules/sovrnBidAdapter_spec.js +413 -333
- package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
- package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
- package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
- package/test/spec/modules/undertoneBidAdapter_spec.js +55 -2
- package/test/spec/modules/userId_spec.js +68 -19
- package/test/spec/modules/viewability_spec.js +280 -0
- package/test/spec/modules/welectBidAdapter_spec.js +211 -0
- package/test/spec/modules/yahoosspBidAdapter_spec.js +10 -0
- package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
- package/test/spec/unit/pbjs_api_spec.js +20 -2
- 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 !!(
|
|
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
|
-
|
|
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
|
-
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
82
|
+
imps = this.buildBannerImpressions(adSizes, bid, tagIdOrPlacementId, pos, videoOrBannerKey);
|
|
87
83
|
} else if (videoOrBannerKey === 'video') {
|
|
88
|
-
imps = this.buildVideoImpressions(adSizes, bid,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
});
|
package/modules/userId/eids.js
CHANGED
|
@@ -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
|
package/modules/userId/userId.md
CHANGED
|
@@ -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();
|