prebid.js 5.19.0 → 5.20.3
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/.circleci/config.yml +4 -5
- package/modules/adxcgBidAdapter.js +311 -359
- package/modules/airgridRtdProvider.js +1 -1
- package/modules/appnexusBidAdapter.js +9 -3
- package/modules/atsAnalyticsAdapter.js +67 -46
- package/modules/atsAnalyticsAdapter.md +1 -0
- package/modules/betweenBidAdapter.js +2 -1
- package/modules/browsiRtdProvider.js +106 -18
- package/modules/cleanioRtdProvider.js +192 -0
- package/modules/cleanioRtdProvider.md +59 -0
- package/modules/deltaprojectsBidAdapter.js +252 -0
- package/modules/deltaprojectsBidAdapter.md +32 -0
- package/modules/gridBidAdapter.js +1 -0
- package/modules/ipromBidAdapter.js +79 -0
- package/modules/ixBidAdapter.js +7 -1
- package/modules/jixieBidAdapter.js +8 -2
- package/modules/justpremiumBidAdapter.js +6 -1
- package/modules/kinessoIdSystem.js +1 -1
- package/modules/livewrappedAnalyticsAdapter.js +5 -0
- package/modules/multibid/index.js +3 -3
- package/modules/nativoBidAdapter.js +5 -1
- package/modules/openxBidAdapter.js +1 -1
- package/modules/operaadsBidAdapter.js +21 -1
- package/modules/otmBidAdapter.js +146 -0
- package/modules/otmBidAdapter.md +27 -26
- package/modules/outbrainBidAdapter.js +5 -0
- package/modules/playwireBidAdapter.md +61 -0
- package/modules/pubmaticBidAdapter.js +1 -1
- package/modules/rtdModule/index.js +2 -2
- package/modules/sonobiBidAdapter.js +7 -0
- package/modules/sortableBidAdapter.js +1 -0
- package/modules/teadsBidAdapter.js +3 -0
- package/modules/trustxBidAdapter.js +8 -6
- package/modules/ventesBidAdapter.js +370 -0
- package/modules/ventesBidAdapter.md +94 -0
- package/modules/yahoosspBidAdapter.js +6 -6
- package/package.json +1 -1
- package/src/auction.js +11 -11
- package/src/prebid.js +20 -4
- package/src/targeting.js +8 -0
- package/test/fixtures/fixtures.js +2 -1
- package/test/spec/modules/adxcgBidAdapter_spec.js +827 -571
- package/test/spec/modules/appnexusBidAdapter_spec.js +16 -1
- package/test/spec/modules/atsAnalyticsAdapter_spec.js +42 -9
- package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
- package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
- package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
- package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
- package/test/spec/modules/ipromBidAdapter_spec.js +195 -0
- package/test/spec/modules/ixBidAdapter_spec.js +3 -3
- package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
- package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +23 -4
- package/test/spec/modules/multibid_spec.js +31 -31
- package/test/spec/modules/openxBidAdapter_spec.js +0 -26
- package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
- package/test/spec/modules/otmBidAdapter_spec.js +67 -0
- package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
- package/test/spec/modules/pubmaticBidAdapter_spec.js +40 -0
- package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
- package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
- package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
- package/test/spec/modules/trustxBidAdapter_spec.js +3 -3
- package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
- package/test/spec/unit/core/adapterManager_spec.js +7 -3
- package/test/spec/unit/core/targeting_spec.js +93 -0
- package/test/spec/unit/pbjs_api_spec.js +3 -1
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
import {registerBidder} from '../src/adapters/bidderFactory.js';
|
|
2
|
+
import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
|
|
3
|
+
import {convertCamelToUnderscore, isStr, isArray, isNumber, isPlainObject, replaceAuctionPrice} from '../src/utils.js';
|
|
4
|
+
import find from 'core-js-pure/features/array/find.js';
|
|
5
|
+
import includes from 'core-js-pure/features/array/includes.js';
|
|
6
|
+
|
|
7
|
+
const BID_METHOD = 'POST';
|
|
8
|
+
const BIDDER_URL = 'http://13.234.201.146:8088/va/ad';
|
|
9
|
+
const FIRST_PRICE = 1;
|
|
10
|
+
const NET_REVENUE = true;
|
|
11
|
+
const TTL = 10;
|
|
12
|
+
const USER_PARAMS = ['age', 'externalUid', 'segments', 'gender', 'dnt', 'language'];
|
|
13
|
+
const DEVICE_PARAMS = ['ua', 'geo', 'dnt', 'lmt', 'ip', 'ipv6', 'devicetype'];
|
|
14
|
+
const APP_DEVICE_PARAMS = ['geo', 'device_id']; // appid is collected separately
|
|
15
|
+
const DOMAIN_REGEX = new RegExp('//([^/]*)');
|
|
16
|
+
|
|
17
|
+
function groupBy(values, key) {
|
|
18
|
+
const groups = values.reduce((acc, value) => {
|
|
19
|
+
const groupId = value[key];
|
|
20
|
+
|
|
21
|
+
if (!acc[groupId]) acc[groupId] = [];
|
|
22
|
+
acc[groupId].push(value);
|
|
23
|
+
|
|
24
|
+
return acc;
|
|
25
|
+
}, {});
|
|
26
|
+
|
|
27
|
+
return Object
|
|
28
|
+
.keys(groups)
|
|
29
|
+
.map(id => ({id, key, values: groups[id]}));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function validateMediaTypes(mediaTypes, allowedMediaTypes) {
|
|
33
|
+
if (!isPlainObject(mediaTypes)) return false;
|
|
34
|
+
if (!allowedMediaTypes.some(mediaType => mediaType in mediaTypes)) return false;
|
|
35
|
+
|
|
36
|
+
if (isBanner(mediaTypes)) {
|
|
37
|
+
if (!validateBanner(mediaTypes.banner)) return false;
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function isBanner(mediaTypes) {
|
|
43
|
+
return isPlainObject(mediaTypes) && isPlainObject(mediaTypes.banner);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function validateBanner(banner) {
|
|
47
|
+
return isPlainObject(banner) &&
|
|
48
|
+
isArray(banner.sizes) &&
|
|
49
|
+
(banner.sizes.length > 0) &&
|
|
50
|
+
banner.sizes.every(validateMediaSizes);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function validateMediaSizes(mediaSize) {
|
|
54
|
+
return isArray(mediaSize) &&
|
|
55
|
+
(mediaSize.length === 2) &&
|
|
56
|
+
mediaSize.every(size => (isNumber(size) && size >= 0));
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function hasUserInfo(bid) {
|
|
60
|
+
return !!bid.params.user;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function validateParameters(parameters, adUnit) {
|
|
64
|
+
if (!(parameters.placementId)) {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
if (!(parameters.publisherId)) {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function extractSiteDomainFromURL(url) {
|
|
75
|
+
if (!url || !isStr(url)) return null;
|
|
76
|
+
|
|
77
|
+
const domain = url.match(DOMAIN_REGEX);
|
|
78
|
+
|
|
79
|
+
if (isArray(domain) && domain.length === 2) return domain[1];
|
|
80
|
+
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function generateSiteFromAdUnitContext(bidRequests, adUnitContext) {
|
|
85
|
+
if (!adUnitContext || !adUnitContext.refererInfo) return null;
|
|
86
|
+
|
|
87
|
+
const domain = extractSiteDomainFromURL(adUnitContext.refererInfo.referer);
|
|
88
|
+
const publisherId = bidRequests[0].params.publisherId;
|
|
89
|
+
|
|
90
|
+
if (!domain) return null;
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
page: adUnitContext.refererInfo.referer,
|
|
94
|
+
domain: domain,
|
|
95
|
+
name: domain,
|
|
96
|
+
publisher: {
|
|
97
|
+
id: publisherId
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function validateServerRequest(serverRequest) {
|
|
103
|
+
return isPlainObject(serverRequest) &&
|
|
104
|
+
isPlainObject(serverRequest.data) &&
|
|
105
|
+
isArray(serverRequest.data.imp)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function createServerRequestFromAdUnits(adUnits, bidRequestId, adUnitContext) {
|
|
109
|
+
return {
|
|
110
|
+
method: BID_METHOD,
|
|
111
|
+
url: BIDDER_URL,
|
|
112
|
+
data: generateBidRequestsFromAdUnits(adUnits, bidRequestId, adUnitContext),
|
|
113
|
+
options: {
|
|
114
|
+
contentType: 'application/json',
|
|
115
|
+
withCredentials: false,
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function generateBidRequestsFromAdUnits(bidRequests, bidRequestId, adUnitContext) {
|
|
121
|
+
const userObjBid = find(bidRequests, hasUserInfo);
|
|
122
|
+
let userObj = {};
|
|
123
|
+
if (userObjBid) {
|
|
124
|
+
Object.keys(userObjBid.params.user)
|
|
125
|
+
.filter(param => includes(USER_PARAMS, param))
|
|
126
|
+
.forEach((param) => {
|
|
127
|
+
let uparam = convertCamelToUnderscore(param);
|
|
128
|
+
if (param === 'segments' && isArray(userObjBid.params.user[param])) {
|
|
129
|
+
let segs = [];
|
|
130
|
+
userObjBid.params.user[param].forEach(val => {
|
|
131
|
+
if (isNumber(val)) {
|
|
132
|
+
segs.push({'id': val});
|
|
133
|
+
} else if (isPlainObject(val)) {
|
|
134
|
+
segs.push(val);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
userObj[uparam] = segs;
|
|
138
|
+
} else if (param !== 'segments') {
|
|
139
|
+
userObj[uparam] = userObjBid.params.user[param];
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const deviceObjBid = find(bidRequests, hasDeviceInfo);
|
|
145
|
+
let deviceObj;
|
|
146
|
+
if (deviceObjBid && deviceObjBid.params && deviceObjBid.params.device) {
|
|
147
|
+
deviceObj = {};
|
|
148
|
+
Object.keys(deviceObjBid.params.device)
|
|
149
|
+
.filter(param => includes(DEVICE_PARAMS, param))
|
|
150
|
+
.forEach(param => deviceObj[param] = deviceObjBid.params.device[param]);
|
|
151
|
+
if (!deviceObjBid.hasOwnProperty('ua')) {
|
|
152
|
+
deviceObj.ua = navigator.userAgent;
|
|
153
|
+
}
|
|
154
|
+
if (!deviceObjBid.hasOwnProperty('language')) {
|
|
155
|
+
deviceObj.language = navigator.language;
|
|
156
|
+
}
|
|
157
|
+
} else {
|
|
158
|
+
deviceObj = {};
|
|
159
|
+
deviceObj.ua = navigator.userAgent;
|
|
160
|
+
deviceObj.language = navigator.language;
|
|
161
|
+
}
|
|
162
|
+
const appDeviceObjBid = find(bidRequests, hasAppInfo);
|
|
163
|
+
let appIdObj;
|
|
164
|
+
if (appDeviceObjBid && appDeviceObjBid.params && appDeviceObjBid.params.app && appDeviceObjBid.params.app.id) {
|
|
165
|
+
Object.keys(appDeviceObjBid.params.app)
|
|
166
|
+
.filter(param => includes(APP_DEVICE_PARAMS, param))
|
|
167
|
+
.forEach(param => appDeviceObjBid[param] = appDeviceObjBid.params.app[param]);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const payload = {}
|
|
171
|
+
payload.id = bidRequestId
|
|
172
|
+
payload.at = FIRST_PRICE
|
|
173
|
+
payload.cur = ['USD']
|
|
174
|
+
payload.imp = bidRequests.reduce(generateImpressionsFromAdUnit, [])
|
|
175
|
+
payload.site = generateSiteFromAdUnitContext(bidRequests, adUnitContext)
|
|
176
|
+
payload.device = deviceObj
|
|
177
|
+
if (appDeviceObjBid && payload.site != null) {
|
|
178
|
+
payload.app = appIdObj;
|
|
179
|
+
}
|
|
180
|
+
payload.user = userObj
|
|
181
|
+
// payload.regs = getRegulationFromAdUnitContext(adUnitContext)
|
|
182
|
+
// payload.ext = generateBidRequestExtension()
|
|
183
|
+
|
|
184
|
+
return payload
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function generateImpressionsFromAdUnit(acc, adUnit) {
|
|
188
|
+
const {bidId, mediaTypes, params} = adUnit;
|
|
189
|
+
const {placementId} = params;
|
|
190
|
+
const pmp = {};
|
|
191
|
+
|
|
192
|
+
if (placementId) pmp.deals = [{id: placementId}]
|
|
193
|
+
|
|
194
|
+
const imps = Object
|
|
195
|
+
.keys(mediaTypes)
|
|
196
|
+
.reduce((acc, mediaType) => {
|
|
197
|
+
const data = mediaTypes[mediaType];
|
|
198
|
+
const impId = `${bidId}`;
|
|
199
|
+
|
|
200
|
+
if (mediaType === 'banner') return acc.concat(generateBannerFromAdUnit(impId, data, params));
|
|
201
|
+
}, []);
|
|
202
|
+
|
|
203
|
+
return acc.concat(imps);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function generateBannerFromAdUnit(impId, data, params) {
|
|
207
|
+
const {position, placementId} = params;
|
|
208
|
+
const pos = position || 0;
|
|
209
|
+
const pmp = {};
|
|
210
|
+
const ext = {placementId};
|
|
211
|
+
|
|
212
|
+
if (placementId) pmp.deals = [{id: placementId}]
|
|
213
|
+
|
|
214
|
+
return data.sizes.map(([w, h]) => ({id: `${impId}`, banner: {format: [{w, h}], w, h, pos}, pmp, ext, tagid: placementId}));
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function validateServerResponse(serverResponse) {
|
|
218
|
+
return isPlainObject(serverResponse) &&
|
|
219
|
+
isPlainObject(serverResponse.body) &&
|
|
220
|
+
isStr(serverResponse.body.cur) &&
|
|
221
|
+
isArray(serverResponse.body.seatbid);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function seatBidsToAds(seatBid, bidResponse, serverRequest) {
|
|
225
|
+
return seatBid.bid
|
|
226
|
+
.filter(bid => validateBids(bid))
|
|
227
|
+
.map(bid => generateAdFromBid(bid, bidResponse));
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function validateBids(bid) {
|
|
231
|
+
if (!isPlainObject(bid)) return false;
|
|
232
|
+
if (!isStr(bid.impid)) return false;
|
|
233
|
+
if (!isStr(bid.crid)) return false;
|
|
234
|
+
if (!isNumber(bid.price)) return false;
|
|
235
|
+
if (!isNumber(bid.w)) return false;
|
|
236
|
+
if (!isNumber(bid.h)) return false;
|
|
237
|
+
if (!bid.adm) return false;
|
|
238
|
+
if (bid.adm) {
|
|
239
|
+
if (!isStr(bid.adm)) return false;
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const VAST_REGEXP = /VAST\s+version/;
|
|
245
|
+
|
|
246
|
+
function getMediaType(adm) {
|
|
247
|
+
const videoRegex = new RegExp(VAST_REGEXP);
|
|
248
|
+
|
|
249
|
+
if (videoRegex.test(adm)) {
|
|
250
|
+
return VIDEO;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const markup = safeJSONparse(adm.replace(/\\/g, ''));
|
|
254
|
+
|
|
255
|
+
if (markup && isPlainObject(markup.native)) {
|
|
256
|
+
return NATIVE;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return BANNER;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function safeJSONparse(...args) {
|
|
263
|
+
try {
|
|
264
|
+
return JSON.parse(...args);
|
|
265
|
+
} catch (_) {
|
|
266
|
+
return undefined;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function generateAdFromBid(bid, bidResponse) {
|
|
271
|
+
const mediaType = getMediaType(bid.adm);
|
|
272
|
+
const base = {
|
|
273
|
+
requestId: bid.impid,
|
|
274
|
+
cpm: bid.price,
|
|
275
|
+
currency: bidResponse.cur,
|
|
276
|
+
ttl: TTL,
|
|
277
|
+
creativeId: bid.crid,
|
|
278
|
+
mediaType: mediaType,
|
|
279
|
+
netRevenue: NET_REVENUE
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
if (bid.adomain) {
|
|
283
|
+
base.meta = { advertiserDomains: bid.adomain };
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const size = getSizeFromBid(bid);
|
|
287
|
+
const creative = getCreativeFromBid(bid);
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
...base,
|
|
291
|
+
height: size.height,
|
|
292
|
+
width: size.width,
|
|
293
|
+
ad: creative.markup,
|
|
294
|
+
adUrl: creative.markupUrl,
|
|
295
|
+
// vastXml: isVideo && !isStr(creative.markupUrl) ? creative.markup : null,
|
|
296
|
+
// vastUrl: isVideo && isStr(creative.markupUrl) ? creative.markupUrl : null,
|
|
297
|
+
renderer: creative.renderer
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getSizeFromBid(bid) {
|
|
302
|
+
if (isNumber(bid.w) && isNumber(bid.h)) {
|
|
303
|
+
return { width: bid.w, height: bid.h };
|
|
304
|
+
}
|
|
305
|
+
return { width: null, height: null };
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
function getCreativeFromBid(bid) {
|
|
309
|
+
const shouldUseAdMarkup = !!bid.adm;
|
|
310
|
+
const price = bid.price;
|
|
311
|
+
return {
|
|
312
|
+
markup: shouldUseAdMarkup ? replaceAuctionPrice(bid.adm, price) : null,
|
|
313
|
+
markupUrl: !shouldUseAdMarkup ? replaceAuctionPrice(bid.nurl, price) : null
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function hasDeviceInfo(bid) {
|
|
318
|
+
if (bid.params) {
|
|
319
|
+
return !!bid.params.device
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function hasAppInfo(bid) {
|
|
324
|
+
if (bid.params) {
|
|
325
|
+
return !!bid.params.app
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const venavenBidderSpec = {
|
|
330
|
+
code: 'ventes',
|
|
331
|
+
supportedMediaTypes: [BANNER],
|
|
332
|
+
isBidRequestValid(adUnit) {
|
|
333
|
+
const allowedBidderCodes = [this.code];
|
|
334
|
+
|
|
335
|
+
return isPlainObject(adUnit) &&
|
|
336
|
+
allowedBidderCodes.indexOf(adUnit.bidder) !== -1 &&
|
|
337
|
+
isStr(adUnit.adUnitCode) &&
|
|
338
|
+
isStr(adUnit.bidderRequestId) &&
|
|
339
|
+
isStr(adUnit.bidId) &&
|
|
340
|
+
validateMediaTypes(adUnit.mediaTypes, this.supportedMediaTypes) &&
|
|
341
|
+
validateParameters(adUnit.params, adUnit);
|
|
342
|
+
},
|
|
343
|
+
buildRequests(bidRequests, bidderRequest) {
|
|
344
|
+
if (!bidRequests) return null;
|
|
345
|
+
|
|
346
|
+
return groupBy(bidRequests, 'bidderRequestId').map(group => {
|
|
347
|
+
const bidRequestId = group.id;
|
|
348
|
+
const adUnits = groupBy(group.values, 'bidId').map((group) => {
|
|
349
|
+
const length = group.values.length;
|
|
350
|
+
return length > 0 && group.values[length - 1]
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
return createServerRequestFromAdUnits(adUnits, bidRequestId, bidderRequest)
|
|
354
|
+
});
|
|
355
|
+
},
|
|
356
|
+
interpretResponse(serverResponse, serverRequest) {
|
|
357
|
+
if (!validateServerRequest(serverRequest)) return [];
|
|
358
|
+
if (!validateServerResponse(serverResponse)) return [];
|
|
359
|
+
|
|
360
|
+
const bidResponse = serverResponse.body;
|
|
361
|
+
|
|
362
|
+
return bidResponse.seatbid
|
|
363
|
+
.filter(seatBid => isPlainObject(seatBid) && isArray(seatBid.bid))
|
|
364
|
+
.reduce((acc, seatBid) => acc.concat(seatBidsToAds(seatBid, bidResponse, serverRequest)), []);
|
|
365
|
+
}
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
registerBidder(venavenBidderSpec);
|
|
369
|
+
|
|
370
|
+
export {venavenBidderSpec as spec};
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: bidder
|
|
3
|
+
title: ventes
|
|
4
|
+
description: Prebid ventes Bidder Adapter
|
|
5
|
+
pbjs: false
|
|
6
|
+
biddercode: ventes
|
|
7
|
+
gdpr_supported: false
|
|
8
|
+
usp_supported: false
|
|
9
|
+
media_types: banner
|
|
10
|
+
coppa_supported: false
|
|
11
|
+
schain_supported: false
|
|
12
|
+
dchain_supported: false
|
|
13
|
+
prebid_member: false
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
### BidParams
|
|
17
|
+
{: .table .table-bordered .table-striped }
|
|
18
|
+
| Name | Scope | Description | Example | Type |
|
|
19
|
+
|-----------------|----------|-----------------------------------------------------------|----------------------------------------------|---------------|
|
|
20
|
+
| `placementId` | required | Placement ID from Ventes Avenues | `'VA-062-0013-0183'` | `string` |
|
|
21
|
+
| `publisherId` | required | Publisher ID from Ventes Avenues | `'VA-062'` | `string` |
|
|
22
|
+
| `user` | optional | Object that specifies information about an external user. | `user: { age: 25, gender: 0, dnt: true}` | `object` |
|
|
23
|
+
| `app` | required | Object containing mobile app parameters. | `app : { id: 'app-id'}` | `object` |
|
|
24
|
+
| `device` | required | Object containing device info mandatory for mobile devices| `device : { ifa: 'device-id'}` | `object` |
|
|
25
|
+
|
|
26
|
+
#### User Object
|
|
27
|
+
|
|
28
|
+
{: .table .table-bordered .table-striped }
|
|
29
|
+
| Name | Description | Example | Type |
|
|
30
|
+
|-------------------|-------------------------------------------------------------------------------------------|-----------------------|-----------------------|
|
|
31
|
+
| `age` | The age of the user. | `35` | `integer` |
|
|
32
|
+
| `externalUid` | Specifies a string that corresponds to an external user ID for this user. | `'1234567890abcdefg'` | `string` |
|
|
33
|
+
| `segments` | Specifies the segments to which the user belongs. | `[1, 2]` | `Array<integer>` |
|
|
34
|
+
| `gender` | Specifies the gender of the user. Allowed values: Unknown: `0`; Male: `1`; Female: `2` | `1` | `integer` |
|
|
35
|
+
| `dnt` | Do not track flag. Indicates if tracking cookies should be disabled for this auction | `true` | `boolean` |
|
|
36
|
+
| `language` | Two-letter ANSI code for this user's language. | `EN` | `string` |
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
### Ad Unit Setup for Banner through mobile devices
|
|
40
|
+
```javascript
|
|
41
|
+
var adUnits = [
|
|
42
|
+
{
|
|
43
|
+
code: 'test-hb-ad-11111-1',
|
|
44
|
+
mediaTypes: {
|
|
45
|
+
banner: {
|
|
46
|
+
sizes: [
|
|
47
|
+
[300, 250]
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
bids: [{
|
|
52
|
+
bidder: 'ventes',
|
|
53
|
+
params: {
|
|
54
|
+
placementId: 'VA-062-0013-0183',
|
|
55
|
+
publisherId: '5cebea3c9eea646c7b623d5e',
|
|
56
|
+
IABCategories: "['IAB1', 'IAB5']",
|
|
57
|
+
device:{
|
|
58
|
+
ip: '123.145.167.189',
|
|
59
|
+
ifa:"AEBE52E7-03EE-455A-B3C4-E57283966239",
|
|
60
|
+
},
|
|
61
|
+
app: {
|
|
62
|
+
id: "agltb3B1Yi1pbmNyDAsSA0FwcBiJkfIUDA",
|
|
63
|
+
name: "Yahoo Weather",
|
|
64
|
+
bundle: 'com.kiloo.subwaysurf',
|
|
65
|
+
storeurl: 'https://play.google.com/store/apps/details?id=com.kiloo.subwaysurf&hl=en',
|
|
66
|
+
domain: 'somoaudience.com',
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}]
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Ad Unit Setup for Banner through Websites
|
|
75
|
+
```javascript
|
|
76
|
+
var adUnits = [
|
|
77
|
+
{
|
|
78
|
+
code: 'test-hb-ad-11111-1',
|
|
79
|
+
mediaTypes: {
|
|
80
|
+
banner: {
|
|
81
|
+
sizes: [
|
|
82
|
+
[300, 250]
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
bids: [{
|
|
87
|
+
bidder: 'ventes',
|
|
88
|
+
params: {
|
|
89
|
+
placementId: 'VA-002-0007-0799',
|
|
90
|
+
publisherId: '5cebea3c9eea646c7b623d5e',
|
|
91
|
+
}
|
|
92
|
+
}]
|
|
93
|
+
}
|
|
94
|
+
]
|
|
@@ -144,9 +144,9 @@ function getAdapterMode() {
|
|
|
144
144
|
|
|
145
145
|
function getResponseFormat(bid) {
|
|
146
146
|
const adm = bid.adm;
|
|
147
|
-
if (adm.
|
|
147
|
+
if (adm.indexOf('o2playerSettings') !== -1 || adm.indexOf('YAHOO.VideoPlatform.VideoPlayer') !== -1 || adm.indexOf('AdPlacement') !== -1) {
|
|
148
148
|
return BANNER;
|
|
149
|
-
} else if (adm.
|
|
149
|
+
} else if (adm.indexOf('VAST') !== -1) {
|
|
150
150
|
return VIDEO;
|
|
151
151
|
}
|
|
152
152
|
};
|
|
@@ -188,23 +188,23 @@ function validateAppendObject(validationType, allowedKeys, inputObject, appendTo
|
|
|
188
188
|
for (const objectKey in inputObject) {
|
|
189
189
|
switch (validationType) {
|
|
190
190
|
case 'string':
|
|
191
|
-
if (allowedKeys.
|
|
191
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isStr(inputObject[objectKey])) {
|
|
192
192
|
outputObject[objectKey] = inputObject[objectKey];
|
|
193
193
|
};
|
|
194
194
|
break;
|
|
195
195
|
case 'number':
|
|
196
|
-
if (allowedKeys.
|
|
196
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isNumber(inputObject[objectKey])) {
|
|
197
197
|
outputObject[objectKey] = inputObject[objectKey];
|
|
198
198
|
};
|
|
199
199
|
break;
|
|
200
200
|
|
|
201
201
|
case 'array':
|
|
202
|
-
if (allowedKeys.
|
|
202
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isArray(inputObject[objectKey])) {
|
|
203
203
|
outputObject[objectKey] = inputObject[objectKey];
|
|
204
204
|
};
|
|
205
205
|
break;
|
|
206
206
|
case 'object':
|
|
207
|
-
if (allowedKeys.
|
|
207
|
+
if (allowedKeys.indexOf(objectKey) !== -1 && isPlainObject(inputObject[objectKey])) {
|
|
208
208
|
outputObject[objectKey] = inputObject[objectKey];
|
|
209
209
|
};
|
|
210
210
|
break;
|
package/package.json
CHANGED
package/src/auction.js
CHANGED
|
@@ -613,7 +613,8 @@ export const getPriceGranularity = (mediaType, bidReq) => {
|
|
|
613
613
|
* @returns {function}
|
|
614
614
|
*/
|
|
615
615
|
export const getPriceByGranularity = (granularity) => {
|
|
616
|
-
return (bid) => {
|
|
616
|
+
return (bid, bidReq) => {
|
|
617
|
+
granularity = granularity || getPriceGranularity(bid.mediaType, bidReq);
|
|
617
618
|
if (granularity === CONSTANTS.GRANULARITY_OPTIONS.AUTO) {
|
|
618
619
|
return bid.pbAg;
|
|
619
620
|
} else if (granularity === CONSTANTS.GRANULARITY_OPTIONS.DENSE) {
|
|
@@ -646,14 +647,14 @@ export const getAdvertiserDomain = () => {
|
|
|
646
647
|
* @param {BidRequest} bidReq
|
|
647
648
|
* @returns {*}
|
|
648
649
|
*/
|
|
649
|
-
export function getStandardBidderSettings(mediaType, bidderCode
|
|
650
|
+
export function getStandardBidderSettings(mediaType, bidderCode) {
|
|
650
651
|
// factory for key value objs
|
|
651
652
|
function createKeyVal(key, value) {
|
|
652
653
|
return {
|
|
653
654
|
key,
|
|
654
655
|
val: (typeof value === 'function')
|
|
655
|
-
? function (bidResponse) {
|
|
656
|
-
return value(bidResponse);
|
|
656
|
+
? function (bidResponse, bidReq) {
|
|
657
|
+
return value(bidResponse, bidReq);
|
|
657
658
|
}
|
|
658
659
|
: function (bidResponse) {
|
|
659
660
|
return getValue(bidResponse, value);
|
|
@@ -661,7 +662,6 @@ export function getStandardBidderSettings(mediaType, bidderCode, bidReq) {
|
|
|
661
662
|
};
|
|
662
663
|
}
|
|
663
664
|
const TARGETING_KEYS = CONSTANTS.TARGETING_KEYS;
|
|
664
|
-
const granularity = getPriceGranularity(mediaType, bidReq);
|
|
665
665
|
|
|
666
666
|
let bidderSettings = $$PREBID_GLOBAL$$.bidderSettings;
|
|
667
667
|
if (!bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD]) {
|
|
@@ -671,7 +671,7 @@ export function getStandardBidderSettings(mediaType, bidderCode, bidReq) {
|
|
|
671
671
|
bidderSettings[CONSTANTS.JSON_MAPPING.BD_SETTING_STANDARD][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING] = [
|
|
672
672
|
createKeyVal(TARGETING_KEYS.BIDDER, 'bidderCode'),
|
|
673
673
|
createKeyVal(TARGETING_KEYS.AD_ID, 'adId'),
|
|
674
|
-
createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity(
|
|
674
|
+
createKeyVal(TARGETING_KEYS.PRICE_BUCKET, getPriceByGranularity()),
|
|
675
675
|
createKeyVal(TARGETING_KEYS.SIZE, 'size'),
|
|
676
676
|
createKeyVal(TARGETING_KEYS.DEAL, 'dealId'),
|
|
677
677
|
createKeyVal(TARGETING_KEYS.SOURCE, 'source'),
|
|
@@ -716,12 +716,12 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
|
|
|
716
716
|
// 1) set the keys from "standard" setting or from prebid defaults
|
|
717
717
|
if (bidderSettings) {
|
|
718
718
|
// initialize default if not set
|
|
719
|
-
const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode
|
|
720
|
-
setKeys(keyValues, standardSettings, custBidObj);
|
|
719
|
+
const standardSettings = getStandardBidderSettings(custBidObj.mediaType, bidderCode);
|
|
720
|
+
setKeys(keyValues, standardSettings, custBidObj, bidReq);
|
|
721
721
|
|
|
722
722
|
// 2) set keys from specific bidder setting override if they exist
|
|
723
723
|
if (bidderCode && bidderSettings[bidderCode] && bidderSettings[bidderCode][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) {
|
|
724
|
-
setKeys(keyValues, bidderSettings[bidderCode], custBidObj);
|
|
724
|
+
setKeys(keyValues, bidderSettings[bidderCode], custBidObj, bidReq);
|
|
725
725
|
custBidObj.sendStandardTargeting = bidderSettings[bidderCode].sendStandardTargeting;
|
|
726
726
|
}
|
|
727
727
|
}
|
|
@@ -734,7 +734,7 @@ export function getKeyValueTargetingPairs(bidderCode, custBidObj, bidReq) {
|
|
|
734
734
|
return keyValues;
|
|
735
735
|
}
|
|
736
736
|
|
|
737
|
-
function setKeys(keyValues, bidderSettings, custBidObj) {
|
|
737
|
+
function setKeys(keyValues, bidderSettings, custBidObj, bidReq) {
|
|
738
738
|
var targeting = bidderSettings[CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING];
|
|
739
739
|
custBidObj.size = custBidObj.getSize();
|
|
740
740
|
|
|
@@ -748,7 +748,7 @@ function setKeys(keyValues, bidderSettings, custBidObj) {
|
|
|
748
748
|
|
|
749
749
|
if (isFn(value)) {
|
|
750
750
|
try {
|
|
751
|
-
value = value(custBidObj);
|
|
751
|
+
value = value(custBidObj, bidReq);
|
|
752
752
|
} catch (e) {
|
|
753
753
|
logError('bidmanager', 'ERROR', e);
|
|
754
754
|
}
|
package/src/prebid.js
CHANGED
|
@@ -403,10 +403,23 @@ function emitAdRenderSucceeded({ doc, bid, id }) {
|
|
|
403
403
|
events.emit(AD_RENDER_SUCCEEDED, data);
|
|
404
404
|
}
|
|
405
405
|
|
|
406
|
+
/**
|
|
407
|
+
* This function will check for presence of given node in given parent. If not present - will inject it.
|
|
408
|
+
* @param {Node} node node, whose existance is in question
|
|
409
|
+
* @param {Document} doc document element do look in
|
|
410
|
+
* @param {string} tagName tag name to look in
|
|
411
|
+
*/
|
|
412
|
+
function reinjectNodeIfRemoved(node, doc, tagName) {
|
|
413
|
+
const injectionNode = doc.querySelector(tagName);
|
|
414
|
+
if (!node.parentNode || node.parentNode !== injectionNode) {
|
|
415
|
+
insertElement(node, doc, tagName);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
406
419
|
/**
|
|
407
420
|
* This function will render the ad (based on params) in the given iframe document passed through.
|
|
408
421
|
* Note that doc SHOULD NOT be the parent document page as we can't doc.write() asynchronously
|
|
409
|
-
* @param {
|
|
422
|
+
* @param {Document} doc document
|
|
410
423
|
* @param {string} id bid id to locate the ad
|
|
411
424
|
* @alias module:pbjs.renderAd
|
|
412
425
|
*/
|
|
@@ -450,10 +463,13 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
450
463
|
const {height, width, ad, mediaType, adUrl, renderer} = bid;
|
|
451
464
|
|
|
452
465
|
const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`);
|
|
466
|
+
// It is important that the comment with metadata is injected before the ad is actually rendered,
|
|
467
|
+
// so the creativeId can be used by e.g. ad quality scanners to check against blocking rules
|
|
468
|
+
insertElement(creativeComment, doc, 'html');
|
|
453
469
|
|
|
454
470
|
if (isRendererRequired(renderer)) {
|
|
455
471
|
executeRenderer(renderer, bid);
|
|
456
|
-
|
|
472
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
457
473
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
458
474
|
} else if ((doc === document && !inIframe()) || mediaType === 'video') {
|
|
459
475
|
const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`;
|
|
@@ -472,7 +488,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
472
488
|
doc.write(ad);
|
|
473
489
|
doc.close();
|
|
474
490
|
setRenderSize(doc, width, height);
|
|
475
|
-
|
|
491
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
476
492
|
callBurl(bid);
|
|
477
493
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
478
494
|
} else if (adUrl) {
|
|
@@ -485,7 +501,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
|
|
|
485
501
|
|
|
486
502
|
insertElement(iframe, doc, 'body');
|
|
487
503
|
setRenderSize(doc, width, height);
|
|
488
|
-
|
|
504
|
+
reinjectNodeIfRemoved(creativeComment, doc, 'html');
|
|
489
505
|
callBurl(bid);
|
|
490
506
|
emitAdRenderSucceeded({ doc, bid, id });
|
|
491
507
|
} else {
|
package/src/targeting.js
CHANGED
|
@@ -416,7 +416,15 @@ export function newTargeting(auctionManager) {
|
|
|
416
416
|
let bidsReceived = auctionManager.getBidsReceived();
|
|
417
417
|
|
|
418
418
|
if (!config.getConfig('useBidCache')) {
|
|
419
|
+
// don't use bid cache (i.e. filter out bids not in the latest auction)
|
|
419
420
|
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId)
|
|
421
|
+
} else {
|
|
422
|
+
// if custom bid cache filter function exists, run for each bid from
|
|
423
|
+
// previous auctions. If it returns true, include bid in bid pool
|
|
424
|
+
const filterFunction = config.getConfig('bidCacheFilterFunction');
|
|
425
|
+
if (typeof filterFunction === 'function') {
|
|
426
|
+
bidsReceived = bidsReceived.filter(bid => latestAuctionForAdUnit[bid.adUnitCode] === bid.auctionId || !!filterFunction(bid))
|
|
427
|
+
}
|
|
420
428
|
}
|
|
421
429
|
|
|
422
430
|
bidsReceived = bidsReceived
|
|
@@ -1231,7 +1231,7 @@ export function getCurrencyRates() {
|
|
|
1231
1231
|
};
|
|
1232
1232
|
}
|
|
1233
1233
|
|
|
1234
|
-
export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId}) {
|
|
1234
|
+
export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, adUnitCode, adId, status, ttl, requestId, mediaType}) {
|
|
1235
1235
|
let bid = {
|
|
1236
1236
|
'bidderCode': bidder,
|
|
1237
1237
|
'width': '300',
|
|
@@ -1259,6 +1259,7 @@ export function createBidReceived({bidder, cpm, auctionId, responseTimestamp, ad
|
|
|
1259
1259
|
'hb_pb': cpm,
|
|
1260
1260
|
'foobar': '300x250'
|
|
1261
1261
|
}),
|
|
1262
|
+
'mediaType': mediaType,
|
|
1262
1263
|
'netRevenue': true,
|
|
1263
1264
|
'currency': 'USD',
|
|
1264
1265
|
'ttl': (!ttl) ? 300 : ttl
|