prebid.js 5.16.0 → 5.20.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 (182) hide show
  1. package/.devcontainer/Dockerfile +11 -0
  2. package/.devcontainer/devcontainer.json +27 -0
  3. package/.devcontainer/postCreate.sh +6 -0
  4. package/browsers.json +1 -0
  5. package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
  6. package/modules/.submodules.json +1 -0
  7. package/modules/adfBidAdapter.js +21 -16
  8. package/modules/adgenerationBidAdapter.js +28 -4
  9. package/modules/adkernelBidAdapter.js +3 -1
  10. package/modules/admixerBidAdapter.js +11 -0
  11. package/modules/adnuntiusBidAdapter.js +1 -0
  12. package/modules/adtelligentBidAdapter.js +2 -1
  13. package/modules/airgridRtdProvider.js +1 -1
  14. package/modules/akamaiDapRtdProvider.js +474 -0
  15. package/modules/akamaiDapRtdProvider.md +47 -0
  16. package/modules/aolBidAdapter.js +2 -1
  17. package/modules/appnexusBidAdapter.js +5 -3
  18. package/modules/atsAnalyticsAdapter.js +89 -63
  19. package/modules/atsAnalyticsAdapter.md +1 -0
  20. package/modules/betweenBidAdapter.js +20 -3
  21. package/modules/bliinkBidAdapter.js +58 -32
  22. package/modules/bliinkBidAdapter.md +29 -6
  23. package/modules/browsiRtdProvider.js +106 -18
  24. package/modules/cleanioRtdProvider.js +192 -0
  25. package/modules/cleanioRtdProvider.md +59 -0
  26. package/modules/codefuelBidAdapter.js +183 -0
  27. package/modules/codefuelBidAdapter.md +111 -0
  28. package/modules/connectIdSystem.js +104 -0
  29. package/modules/connectIdSystem.md +33 -0
  30. package/modules/cwireBidAdapter.js +272 -0
  31. package/modules/cwireBidAdapter.md +43 -0
  32. package/modules/deepintentBidAdapter.js +106 -9
  33. package/modules/deepintentBidAdapter.md +36 -1
  34. package/modules/deltaprojectsBidAdapter.js +252 -0
  35. package/modules/deltaprojectsBidAdapter.md +32 -0
  36. package/modules/dgkeywordRtdProvider.js +0 -1
  37. package/modules/engageyaBidAdapter.js +157 -0
  38. package/modules/glimpseBidAdapter.js +160 -48
  39. package/modules/glimpseBidAdapter.md +11 -74
  40. package/modules/gridBidAdapter.js +1 -0
  41. package/modules/gridNMBidAdapter.js +7 -6
  42. package/modules/gumgumBidAdapter.js +16 -2
  43. package/modules/iasRtdProvider.js +83 -67
  44. package/modules/inskinBidAdapter.js +7 -3
  45. package/modules/ixBidAdapter.js +8 -1
  46. package/modules/jixieBidAdapter.js +8 -2
  47. package/modules/justpremiumBidAdapter.js +6 -1
  48. package/modules/kargoBidAdapter.js +14 -7
  49. package/modules/kargoBidAdapter.md +20 -0
  50. package/modules/limelightDigitalBidAdapter.js +22 -2
  51. package/modules/livewrappedAnalyticsAdapter.js +53 -3
  52. package/modules/mediakeysBidAdapter.js +405 -14
  53. package/modules/mediakeysBidAdapter.md +108 -0
  54. package/modules/multibid/index.js +3 -3
  55. package/modules/mytargetBidAdapter.js +112 -0
  56. package/modules/nativoBidAdapter.js +48 -29
  57. package/modules/nativoBidAdapter.md +0 -1
  58. package/modules/nextMillenniumBidAdapter.js +12 -3
  59. package/modules/nextrollBidAdapter.js +375 -0
  60. package/modules/nobidBidAdapter.js +2 -1
  61. package/modules/oguryBidAdapter.js +36 -7
  62. package/modules/openxBidAdapter.js +34 -22
  63. package/modules/operaadsBidAdapter.js +21 -1
  64. package/modules/otmBidAdapter.js +146 -0
  65. package/modules/otmBidAdapter.md +27 -26
  66. package/modules/outbrainBidAdapter.js +5 -0
  67. package/modules/pixfutureBidAdapter.js +24 -4
  68. package/modules/pixfutureBidAdapter.md +127 -0
  69. package/modules/playwireBidAdapter.md +61 -0
  70. package/modules/prebidServerBidAdapter/index.js +1 -1
  71. package/modules/proxistoreBidAdapter.js +4 -6
  72. package/modules/publinkIdSystem.js +17 -7
  73. package/modules/publinkIdSystem.md +7 -2
  74. package/modules/pubmaticBidAdapter.js +22 -6
  75. package/modules/pubmaticBidAdapter.md +1 -1
  76. package/modules/relaidoBidAdapter.js +8 -2
  77. package/modules/rtdModule/index.js +2 -2
  78. package/modules/sharethroughBidAdapter.js +12 -19
  79. package/modules/slimcutBidAdapter.js +121 -0
  80. package/modules/sonobiBidAdapter.js +7 -0
  81. package/modules/sortableBidAdapter.js +1 -0
  82. package/modules/spotxBidAdapter.js +15 -1
  83. package/modules/sspBCBidAdapter.js +207 -12
  84. package/modules/sspBCBidAdapter.md +1 -1
  85. package/modules/talkadsBidAdapter.js +129 -0
  86. package/modules/talkadsBidAdapter.md +60 -0
  87. package/modules/tappxBidAdapter.js +6 -5
  88. package/modules/teadsBidAdapter.js +3 -0
  89. package/modules/tripleliftBidAdapter.js +22 -5
  90. package/modules/trustxBidAdapter.js +17 -11
  91. package/modules/undertoneBidAdapter.js +9 -5
  92. package/modules/undertoneBidAdapter.md +5 -1
  93. package/modules/unicornBidAdapter.js +3 -3
  94. package/modules/userId/eids.js +18 -0
  95. package/modules/userId/eids.md +7 -0
  96. package/modules/userId/userId.md +12 -0
  97. package/modules/ventesBidAdapter.js +370 -0
  98. package/modules/ventesBidAdapter.md +94 -0
  99. package/modules/videobyteBidAdapter.js +13 -6
  100. package/modules/videobyteBidAdapter.md +49 -0
  101. package/modules/vidoomyBidAdapter.js +20 -12
  102. package/modules/visxBidAdapter.js +15 -22
  103. package/modules/yahoosspBidAdapter.js +637 -0
  104. package/modules/yahoosspBidAdapter.md +795 -0
  105. package/modules/yieldlabBidAdapter.js +48 -3
  106. package/modules/yieldlabBidAdapter.md +16 -1
  107. package/modules/yieldmoBidAdapter.js +20 -6
  108. package/modules/yieldmoSyntheticInventoryModule.js +46 -0
  109. package/modules/yieldmoSyntheticInventoryModule.md +68 -0
  110. package/package.json +1 -1
  111. package/src/adapterManager.js +5 -0
  112. package/src/adapters/bidderFactory.js +4 -3
  113. package/src/auction.js +11 -11
  114. package/src/constants.json +1 -0
  115. package/src/secureCreatives.js +6 -7
  116. package/src/targeting.js +11 -9
  117. package/test/.eslintrc.js +2 -1
  118. package/test/spec/modules/adfBidAdapter_spec.js +83 -29
  119. package/test/spec/modules/adgenerationBidAdapter_spec.js +121 -50
  120. package/test/spec/modules/adnuntiusBidAdapter_spec.js +68 -0
  121. package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
  122. package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
  123. package/test/spec/modules/appnexusBidAdapter_spec.js +2 -1
  124. package/test/spec/modules/atsAnalyticsAdapter_spec.js +77 -9
  125. package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
  126. package/test/spec/modules/bliinkBidAdapter_spec.js +87 -36
  127. package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
  128. package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
  129. package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
  130. package/test/spec/modules/connectIdSystem_spec.js +189 -0
  131. package/test/spec/modules/cwireBidAdapter_spec.js +246 -0
  132. package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
  133. package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
  134. package/test/spec/modules/engageyaBidAdapter_spec.js +286 -0
  135. package/test/spec/modules/glimpseBidAdapter_spec.js +302 -204
  136. package/test/spec/modules/gridNMBidAdapter_spec.js +40 -1
  137. package/test/spec/modules/gumgumBidAdapter_spec.js +23 -6
  138. package/test/spec/modules/iasRtdProvider_spec.js +71 -6
  139. package/test/spec/modules/ixBidAdapter_spec.js +13 -3
  140. package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
  141. package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
  142. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
  143. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +67 -12
  144. package/test/spec/modules/mediakeysBidAdapter_spec.js +406 -51
  145. package/test/spec/modules/multibid_spec.js +31 -31
  146. package/test/spec/modules/mytargetBidAdapter_spec.js +199 -0
  147. package/test/spec/modules/nativoBidAdapter_spec.js +50 -3
  148. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
  149. package/test/spec/modules/nextrollBidAdapter_spec.js +290 -0
  150. package/test/spec/modules/nobidBidAdapter_spec.js +65 -1
  151. package/test/spec/modules/oguryBidAdapter_spec.js +125 -37
  152. package/test/spec/modules/openxBidAdapter_spec.js +85 -13
  153. package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
  154. package/test/spec/modules/otmBidAdapter_spec.js +67 -0
  155. package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
  156. package/test/spec/modules/publinkIdSystem_spec.js +34 -15
  157. package/test/spec/modules/pubmaticBidAdapter_spec.js +217 -1
  158. package/test/spec/modules/relaidoBidAdapter_spec.js +21 -20
  159. package/test/spec/modules/sharethroughBidAdapter_spec.js +156 -136
  160. package/test/spec/modules/slimcutBidAdapter_spec.js +200 -0
  161. package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
  162. package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
  163. package/test/spec/modules/spotxBidAdapter_spec.js +36 -0
  164. package/test/spec/modules/sspBCBidAdapter_spec.js +210 -62
  165. package/test/spec/modules/talkadsBidAdapter_spec.js +231 -0
  166. package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
  167. package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
  168. package/test/spec/modules/trustxBidAdapter_spec.js +38 -5
  169. package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
  170. package/test/spec/modules/unicornBidAdapter_spec.js +4 -4
  171. package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
  172. package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
  173. package/test/spec/modules/visxBidAdapter_spec.js +48 -4
  174. package/test/spec/modules/yahoosspBidAdapter_spec.js +1332 -0
  175. package/test/spec/modules/yieldlabBidAdapter_spec.js +65 -1
  176. package/test/spec/modules/yieldmoBidAdapter_spec.js +30 -9
  177. package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
  178. package/test/spec/unit/core/adapterManager_spec.js +32 -0
  179. package/test/spec/unit/core/bidderFactory_spec.js +61 -1
  180. package/test/spec/unit/pbjs_api_spec.js +37 -2
  181. package/test/spec/unit/secureCreatives_spec.js +54 -25
  182. package/modules/turktelekomBidAdapter.md +0 -49
@@ -1,4 +1,6 @@
1
- import { getWindowTop, isFn, logWarn, getDNT, deepAccess, isArray, inIframe, mergeDeep, isStr, isEmpty, deepSetValue, deepClone, parseUrl, cleanObj, logError, triggerPixel } from '../src/utils.js';
1
+ import find from 'core-js-pure/features/array/find.js';
2
+ import arrayFrom from 'core-js-pure/features/array/from';
3
+ import { getWindowTop, isFn, logWarn, getDNT, deepAccess, isArray, inIframe, mergeDeep, isStr, isEmpty, deepSetValue, deepClone, parseUrl, cleanObj, logError, triggerPixel, isInteger, isNumber } from '../src/utils.js';
2
4
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
5
  import { config } from '../src/config.js';
4
6
  import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
@@ -8,10 +10,63 @@ const AUCTION_TYPE = 1;
8
10
  const BIDDER_CODE = 'mediakeys';
9
11
  const ENDPOINT = 'https://prebid.eu-central-1.bidder.mediakeys.io/bids';
10
12
  const GVLID = 498;
11
- const SUPPORTED_MEDIA_TYPES = [BANNER];
13
+ const SUPPORTED_MEDIA_TYPES = [BANNER, NATIVE, VIDEO];
12
14
  const DEFAULT_CURRENCY = 'USD';
13
15
  const NET_REVENUE = true;
14
16
 
17
+ const NATIVE_ASSETS_MAPPING = [
18
+ { name: 'title', id: 1, type: 0 },
19
+ { name: 'image', id: 2, type: 3 },
20
+ { name: 'icon', id: 3, type: 1 },
21
+ { name: 'sponsoredBy', id: 5, type: 1 },
22
+ { name: 'body', id: 6, type: 2 },
23
+ { name: 'rating', id: 7, type: 3 },
24
+ { name: 'likes', id: 8, type: 4 },
25
+ { name: 'downloads', id: 9, type: 5 },
26
+ { name: 'price', id: 10, type: 6 },
27
+ { name: 'salePrice', id: 11, type: 7 },
28
+ { name: 'phone', id: 12, type: 8 },
29
+ { name: 'address', id: 13, type: 9 },
30
+ { name: 'body2', id: 14, type: 10 },
31
+ { name: 'displayUrl', id: 15, type: 11 },
32
+ { name: 'cta', id: 16, type: 12 },
33
+ ];
34
+
35
+ // This provide a whitelist and a basic validation of OpenRTB native 1.2 options.
36
+ // https://www.iab.com/wp-content/uploads/2018/03/OpenRTB-Native-Ads-Specification-Final-1.2.pdf
37
+ const ORTB_NATIVE_PARAMS = {
38
+ context: value => [1, 2, 3].indexOf(value) !== -1,
39
+ plcmttype: value => [1, 2, 3, 4].indexOf(value) !== -1
40
+ };
41
+
42
+ // This provide a whitelist and a basic validation of OpenRTB 2.5 video options.
43
+ // https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf
44
+ const ORTB_VIDEO_PARAMS = {
45
+ mimes: value => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'),
46
+ minduration: value => isInteger(value),
47
+ maxduration: value => isInteger(value),
48
+ protocols: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].indexOf(v) !== -1),
49
+ w: value => isInteger(value),
50
+ h: value => isInteger(value),
51
+ startdelay: value => isInteger(value),
52
+ placement: value => [1, 2, 3, 4, 5].indexOf(value) !== -1,
53
+ linearity: value => [1, 2].indexOf(value) !== -1,
54
+ skip: value => [0, 1].indexOf(value) !== -1,
55
+ skipmin: value => isInteger(value),
56
+ skipafter: value => isInteger(value),
57
+ sequence: value => isInteger(value),
58
+ battr: value => Array.isArray(value) && value.every(v => arrayFrom({length: 17}, (_, i) => i + 1).indexOf(v) !== -1),
59
+ maxextended: value => isInteger(value),
60
+ minbitrate: value => isInteger(value),
61
+ maxbitrate: value => isInteger(value),
62
+ boxingallowed: value => [0, 1].indexOf(value) !== -1,
63
+ playbackmethod: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1),
64
+ playbackend: value => [1, 2, 3].indexOf(value) !== -1,
65
+ delivery: value => [1, 2, 3].indexOf(value) !== -1,
66
+ pos: value => [0, 1, 2, 3, 4, 5, 6, 7].indexOf(value) !== -1,
67
+ api: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1),
68
+ };
69
+
15
70
  /**
16
71
  * Detects the capability to reach window.top.
17
72
  *
@@ -83,6 +138,33 @@ function getFloor(bid, mediaType, size = '*') {
83
138
  return (!isNaN(floor.floor) && floor.currency === DEFAULT_CURRENCY) ? floor.floor : false
84
139
  }
85
140
 
141
+ /**
142
+ * Returns the highest floor price found when a bid have
143
+ * several mediaTypes.
144
+ *
145
+ * @param {*} bid a Prebid.js bid (request) object
146
+ * @returns {number|boolean}
147
+ */
148
+ function getHighestFloor(bid) {
149
+ const floors = [];
150
+
151
+ for (let mediaType in bid.mediaTypes) {
152
+ const floor = getFloor(bid, mediaType);
153
+
154
+ if (isNumber(floor)) {
155
+ floors.push(floor);
156
+ }
157
+ }
158
+
159
+ if (!floors.length) {
160
+ return false;
161
+ }
162
+
163
+ return floors.reduce((a, b) => {
164
+ return Math.max(a, b);
165
+ });
166
+ }
167
+
86
168
  /**
87
169
  * Returns an openRTB 2.5 object.
88
170
  * This one will be populated at each step of the buildRequest process.
@@ -153,6 +235,190 @@ function createBannerImp(bid) {
153
235
  }
154
236
  }
155
237
 
238
+ /**
239
+ * Returns an openRtb 2.5 native object with a native 1.2 request.
240
+ *
241
+ * @param {object} bid Prebid bid object from request
242
+ * @returns {object}
243
+ */
244
+ function createNativeImp(bid) {
245
+ if (!bid.nativeParams) {
246
+ logWarn(`${BIDDER_CODE}: bid.nativeParams object has not been found.`);
247
+ return
248
+ }
249
+
250
+ const nativeParams = deepClone(bid.nativeParams);
251
+
252
+ const nativeAdUnitParams = deepAccess(bid, 'mediaTypes.native', {});
253
+ const nativeBidderParams = deepAccess(bid, 'params.native', {});
254
+
255
+ const extraParams = {
256
+ ...nativeAdUnitParams,
257
+ ...nativeBidderParams
258
+ };
259
+
260
+ const nativeObject = {
261
+ ver: '1.2',
262
+ context: 1, // overwrited later if needed
263
+ plcmttype: 1, // overwrited later if needed
264
+ assets: []
265
+ }
266
+
267
+ Object.keys(ORTB_NATIVE_PARAMS).forEach(name => {
268
+ if (extraParams.hasOwnProperty(name)) {
269
+ if (ORTB_NATIVE_PARAMS[name](extraParams[name])) {
270
+ nativeObject[name] = extraParams[name];
271
+ } else {
272
+ logWarn(`${BIDDER_CODE}: the OpenRTB native param ${name} has been skipped due to misformating. Please refer to OpenRTB Native spec.`);
273
+ }
274
+ }
275
+ });
276
+
277
+ // just a helper function
278
+ const setImageAssetSizes = function(asset, param) {
279
+ if (param.sizes && param.sizes.length) {
280
+ asset.img.w = param.sizes ? param.sizes[0] : undefined;
281
+ asset.img.h = param.sizes ? param.sizes[1] : undefined;
282
+ }
283
+
284
+ if (!asset.img.w) {
285
+ asset.img.wmin = 0;
286
+ }
287
+
288
+ if (!asset.img.h) {
289
+ asset.img.hmin = 0;
290
+ }
291
+ }
292
+
293
+ // Prebid.js "image" type support.
294
+ // Add some defaults to support special type provided by Prebid.js `mediaTypes.native.type: "image"`
295
+ const nativeImageType = deepAccess(bid, 'mediaTypes.native.type');
296
+ if (nativeImageType === 'image') {
297
+ // Default value is ones of the recommended by the spec: https://www.iab.com/wp-content/uploads/2018/03/OpenRTB-Native-Ads-Specification-Final-1.2.pdf
298
+ nativeParams.title.len = 90;
299
+ }
300
+
301
+ for (let key in nativeParams) {
302
+ if (nativeParams.hasOwnProperty(key)) {
303
+ const internalNativeAsset = find(NATIVE_ASSETS_MAPPING, ref => ref.name === key);
304
+ if (!internalNativeAsset) {
305
+ logWarn(`${BIDDER_CODE}: the asset "${key}" has not been found in Prebid assets map. Skipped for request.`);
306
+ continue;
307
+ }
308
+
309
+ const param = nativeParams[key];
310
+
311
+ const asset = {
312
+ id: internalNativeAsset.id,
313
+ required: param.required ? 1 : 0
314
+ }
315
+
316
+ switch (key) {
317
+ case 'title':
318
+ if (param.len || param.length) {
319
+ asset.title = {
320
+ len: param.len || param.length,
321
+ ext: param.ext
322
+ }
323
+ } else {
324
+ logWarn(`${BIDDER_CODE}: "title.length" property for native asset is required. Skipped for request.`)
325
+ continue;
326
+ }
327
+ break;
328
+
329
+ case 'image':
330
+ asset.img = {
331
+ type: internalNativeAsset.type,
332
+ mimes: param.mimes,
333
+ ext: param.ext,
334
+ }
335
+
336
+ setImageAssetSizes(asset, param);
337
+
338
+ break;
339
+ case 'icon':
340
+ asset.img = {
341
+ type: internalNativeAsset.type,
342
+ mimes: param.mimes,
343
+ ext: param.ext,
344
+ }
345
+
346
+ setImageAssetSizes(asset, param);
347
+ break;
348
+
349
+ case 'sponsoredBy': // sponsored
350
+ case 'body': // desc
351
+ case 'rating':
352
+ case 'likes':
353
+ case 'downloads':
354
+ case 'price':
355
+ case 'salePrice':
356
+ case 'phone':
357
+ case 'address':
358
+ case 'body2': // desc2
359
+ case 'displayUrl':
360
+ case 'cta':
361
+ // generic asset.data
362
+ asset.data = {
363
+ type: internalNativeAsset.type,
364
+ len: param.len,
365
+ ext: param.ext
366
+ }
367
+ break;
368
+ }
369
+
370
+ nativeObject.assets.push(asset);
371
+ }
372
+ }
373
+
374
+ if (nativeObject.assets.length) {
375
+ return {
376
+ request: nativeObject
377
+ }
378
+ }
379
+ }
380
+
381
+ /**
382
+ * Returns an openRtb 2.5 video object.
383
+ *
384
+ * @param {object} bid Prebid bid object from request
385
+ * @returns {object}
386
+ */
387
+ function createVideoImp(bid) {
388
+ const videoAdUnitParams = deepAccess(bid, 'mediaTypes.video', {});
389
+ const videoBidderParams = deepAccess(bid, 'params.video', {});
390
+ const computedParams = {};
391
+
392
+ // Special case for playerSize.
393
+ // Eeach props will be overrided if they are defined in config.
394
+ if (Array.isArray(videoAdUnitParams.playerSize)) {
395
+ const tempSize = (Array.isArray(videoAdUnitParams.playerSize[0])) ? videoAdUnitParams.playerSize[0] : videoAdUnitParams.playerSize;
396
+ computedParams.w = tempSize[0];
397
+ computedParams.h = tempSize[1];
398
+ }
399
+
400
+ const videoParams = {
401
+ ...computedParams,
402
+ ...videoAdUnitParams,
403
+ ...videoBidderParams
404
+ };
405
+
406
+ const video = {};
407
+
408
+ // Only whitelisted OpenRTB options need to be validated.
409
+ Object.keys(ORTB_VIDEO_PARAMS).forEach(name => {
410
+ if (videoParams.hasOwnProperty(name)) {
411
+ if (ORTB_VIDEO_PARAMS[name](videoParams[name])) {
412
+ video[name] = videoParams[name];
413
+ } else {
414
+ logWarn(`${BIDDER_CODE}: the OpenRTB video param ${name} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.`);
415
+ }
416
+ }
417
+ });
418
+
419
+ return video
420
+ }
421
+
156
422
  /**
157
423
  * Create the OpenRTB 2.5 imp object.
158
424
  *
@@ -167,20 +433,34 @@ function createImp(bid) {
167
433
  secure: 1,
168
434
  };
169
435
 
436
+ // There is no default floor. bidfloor is set only
437
+ // if the priceFloors module is activated and returns a valid floor.
438
+ const floor = getHighestFloor(bid);
439
+ if (isNumber(floor)) {
440
+ imp.bidfloor = floor;
441
+ }
442
+
170
443
  // Only supports proper mediaTypes definition…
171
444
  for (let mediaType in bid.mediaTypes) {
172
- // There is no default floor. bidfloor is set only
173
- // if the priceFloors module is activated and returns a valid floor.
174
- const floor = getFloor(bid, mediaType);
175
- if (floor) {
176
- imp.bidfloor = floor;
177
- }
178
-
179
- if (mediaType === BANNER) {
180
- const banner = createBannerImp(bid);
181
- if (banner) {
182
- imp.banner = banner;
183
- }
445
+ switch (mediaType) {
446
+ case BANNER:
447
+ const banner = createBannerImp(bid);
448
+ if (banner) {
449
+ imp.banner = banner;
450
+ }
451
+ break;
452
+ case NATIVE:
453
+ const native = createNativeImp(bid);
454
+ if (native) {
455
+ imp.native = native;
456
+ }
457
+ break;
458
+ case VIDEO:
459
+ const video = createVideoImp(bid);
460
+ if (video) {
461
+ imp.video = video;
462
+ }
463
+ break;
184
464
  }
185
465
  }
186
466
 
@@ -213,6 +493,94 @@ function getPrimaryCatFromResponse(cat) {
213
493
  }
214
494
  }
215
495
 
496
+ /**
497
+ * Create the Prebid.js native object from response.
498
+ *
499
+ * @param {*} bid bid object from response
500
+ * @returns {object} Prebid.js native object used in response
501
+ */
502
+ function nativeBidResponseHandler(bid) {
503
+ const nativeAdm = JSON.parse(bid.adm);
504
+ if (!nativeAdm || !nativeAdm.assets.length) {
505
+ logError(`${BIDDER_CODE}: invalid native response.`);
506
+ return;
507
+ }
508
+
509
+ const native = {}
510
+
511
+ nativeAdm.assets.forEach(asset => {
512
+ if (asset.title) {
513
+ native.title = asset.title.text;
514
+ return;
515
+ }
516
+
517
+ if (asset.img) {
518
+ switch (asset.img.type) {
519
+ case 1:
520
+ native.icon = {
521
+ url: asset.img.url,
522
+ width: asset.img.w,
523
+ height: asset.img.h
524
+ };
525
+ break;
526
+ default:
527
+ native.image = {
528
+ url: asset.img.url,
529
+ width: asset.img.w,
530
+ height: asset.img.h
531
+ };
532
+ break;
533
+ }
534
+ return;
535
+ }
536
+
537
+ if (asset.data) {
538
+ const internalNativeAsset = find(NATIVE_ASSETS_MAPPING, ref => ref.id === asset.id);
539
+ if (internalNativeAsset) {
540
+ native[internalNativeAsset.name] = asset.data.value;
541
+ }
542
+ }
543
+ });
544
+
545
+ if (nativeAdm.link) {
546
+ if (nativeAdm.link.url) {
547
+ native.clickUrl = nativeAdm.link.url;
548
+ }
549
+ if (Array.isArray(nativeAdm.link.clicktrackers)) {
550
+ native.clickTrackers = nativeAdm.link.clicktrackers
551
+ }
552
+ }
553
+
554
+ if (Array.isArray(nativeAdm.eventtrackers)) {
555
+ native.impressionTrackers = [];
556
+ nativeAdm.eventtrackers.forEach(tracker => {
557
+ // Only Impression events are supported. Prebid does not support Viewability events yet.
558
+ if (tracker.event !== 1) {
559
+ return;
560
+ }
561
+
562
+ // methods:
563
+ // 1: image
564
+ // 2: js
565
+ // note: javascriptTrackers is a string. If there's more than one JS tracker in bid response, the last script will be used.
566
+ switch (tracker.method) {
567
+ case 1:
568
+ native.impressionTrackers.push(tracker.url);
569
+ break;
570
+ case 2:
571
+ native.javascriptTrackers = `<script src=\"${tracker.url}\"></script>`;
572
+ break;
573
+ }
574
+ });
575
+ }
576
+
577
+ if (nativeAdm.privacy) {
578
+ native.privacyLink = nativeAdm.privacy;
579
+ }
580
+
581
+ return native;
582
+ }
583
+
216
584
  export const spec = {
217
585
  code: BIDDER_CODE,
218
586
 
@@ -355,6 +723,29 @@ export const spec = {
355
723
  meta: cleanObj(meta)
356
724
  };
357
725
 
726
+ if (mediaType === NATIVE) {
727
+ const native = nativeBidResponseHandler(bid);
728
+ if (native) {
729
+ newBid.native = native;
730
+ }
731
+ }
732
+
733
+ if (mediaType === VIDEO) {
734
+ // Note:
735
+ // Mediakeys bid adapter expects a publisher has set his own video player
736
+ // in the `mediaTypes.video` configuration object.
737
+
738
+ // Mediakeys bidder does not provide inline XML in the bid response
739
+ // newBid.vastXml = bid.ext.vast_url;
740
+
741
+ // For instream video, disable server cache as vast is generated per bid request
742
+ newBid.videoCacheKey = 'no_cache';
743
+
744
+ // The vast URL is server independently and must be fetched before video rendering in the renderer
745
+ // appending '&no_cache' is safe and fast as the vast url always have parameters
746
+ newBid.vastUrl = bid.ext.vast_url + '&no_cache';
747
+ }
748
+
358
749
  bidResponses.push(newBid);
359
750
  });
360
751
  });
@@ -29,3 +29,111 @@ var adUnits = [
29
29
  }]
30
30
  },
31
31
  ```
32
+
33
+ ## Native only Ad Unit
34
+
35
+ The Mediakeys adapter accepts two optional params for native requests. Please see the [OpenRTB Native Ads Specification](https://www.iab.com/wp-content/uploads/2018/03/OpenRTB-Native-Ads-Specification-Final-1.2.pdf) for valid values.
36
+
37
+ ```
38
+ var adUnits = [
39
+ {
40
+ code: 'test',
41
+ mediaTypes: {
42
+ native: {
43
+ type: 'image',
44
+ }
45
+ },
46
+ bids: [{
47
+ bidder: 'mediakeys',
48
+ params: {
49
+ native: {
50
+ context: 1, // ORTB Native Context Type IDs. Default `1`.
51
+ plcmttype: 1, // ORTB Native Placement Type IDs. Default `1`.
52
+ }
53
+ }
54
+ }]
55
+ },
56
+ ```
57
+
58
+ ## Video only Ad Unit
59
+
60
+ The Mediakeys adapter accepts any valid openRTB 2.5 video property. Properties can be defined at the adUnit `mediaTypes.video` or `bid[].params` level.
61
+
62
+ ### Outstream context
63
+
64
+ ```
65
+ var adUnits = [
66
+ {
67
+ code: 'test',
68
+ mediaTypes: {
69
+ video: {
70
+ context: 'outstream',
71
+ playerSize: [300, 250],
72
+ // additional OpenRTB video params
73
+ // placement: 2,
74
+ // api: [1],
75
+ // …
76
+ }
77
+ },
78
+ renderer: {
79
+ url: 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js',
80
+ render: function (bid) {
81
+ var bidReqConfig = pbjs.adUnits.find(bidReq => bidReq.bidId === bid.impid);
82
+
83
+ if (bidReqConfig && bidReqConfig.mediaTypes && bidReqConfig.mediaTypes.video && bidReqConfig.mediaTypes.video.context === 'outstream') {
84
+ var adResponse = fetch(bid.vastUrl).then(resp => resp.text()).then(text => ({
85
+ ad: {
86
+ video: {
87
+ content: text,
88
+ player_width: bid.width || bidReqConfig.mediaTypes.video.playerSize[0],
89
+ player_height: bid.height || bidReqConfig.mediaTypes.video.playerSize[1],
90
+ }
91
+ }
92
+ }))
93
+
94
+ adResponse.then((ad) => {
95
+ bid.renderer.push(() => {
96
+ ANOutstreamVideo.renderAd({
97
+ targetId: bid.adUnitCode,
98
+ adResponse: ad
99
+ });
100
+ });
101
+ })
102
+ }
103
+ }
104
+ },
105
+ bids: [{
106
+ bidder: 'mediakeys',
107
+ params: {
108
+ video: {
109
+ // additional OpenRTB video params. Will be merged with params defined at mediaTypes level
110
+ }
111
+ }
112
+ }]
113
+ },
114
+ ```
115
+
116
+ ### Instream context
117
+
118
+ ```
119
+ var adUnits = [
120
+ {
121
+ code: 'test',
122
+ mediaTypes: {
123
+ video: {
124
+ context: 'instream',
125
+ playerSize: [300, 250],
126
+ // additional OpenRTB video params
127
+ // placement: 2,
128
+ // api: [1],
129
+ // …
130
+ }
131
+ },
132
+ bids: [{
133
+ bidder: 'mediakeys',
134
+ params: {
135
+ // additional OpenRTB video params. Will be merged with params defined at mediaTypes level
136
+ }
137
+ }]
138
+ },
139
+ ```
@@ -112,7 +112,7 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
112
112
  if (multiConfig[bid.bidderCode].prefix) bid.multibidPrefix = multiConfig[bid.bidderCode].prefix;
113
113
  bid.originalBidder = bid.bidderCode;
114
114
  // Check if stored bids for auction include adUnitCode.bidder and max limit not reach for ad unit
115
- if (deepAccess(multibidUnits, `${adUnitCode}.${bid.bidderCode}`)) {
115
+ if (deepAccess(multibidUnits, [adUnitCode, bid.bidderCode])) {
116
116
  // Store request id under new property originalRequestId, create new unique bidId,
117
117
  // and push bid into multibid stored bids for auction if max not reached and bid cpm above floor
118
118
  if (!multibidUnits[adUnitCode][bid.bidderCode].maxReached && (!floor || floor <= bid.cpm)) {
@@ -131,9 +131,9 @@ export function addBidResponseHook(fn, adUnitCode, bid) {
131
131
  logWarn(`Filtering multibid received from bidder ${bid.bidderCode}: ` + ((multibidUnits[adUnitCode][bid.bidderCode].maxReached) ? `Maximum bid limit reached for ad unit code ${adUnitCode}` : 'Bid cpm under floors value.'));
132
132
  }
133
133
  } else {
134
- if (deepAccess(bid, 'floorData.floorValue')) deepSetValue(multibidUnits, `${adUnitCode}.${bid.bidderCode}`, {floor: deepAccess(bid, 'floorData.floorValue')});
134
+ if (deepAccess(bid, 'floorData.floorValue')) deepSetValue(multibidUnits, [adUnitCode, bid.bidderCode], {floor: deepAccess(bid, 'floorData.floorValue')});
135
135
 
136
- deepSetValue(multibidUnits, `${adUnitCode}.${bid.bidderCode}`, {ads: [bid]});
136
+ deepSetValue(multibidUnits, [adUnitCode, bid.bidderCode], {ads: [bid]});
137
137
  if (multibidUnits[adUnitCode][bid.bidderCode].ads.length === multiConfig[bid.bidderCode].maxbids) multibidUnits[adUnitCode][bid.bidderCode].maxReached = true;
138
138
 
139
139
  fn.call(this, adUnitCode, bid);
@@ -0,0 +1,112 @@
1
+ import { _map } from '../src/utils.js';
2
+ import { config } from '../src/config.js';
3
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
4
+
5
+ const BIDDER_CODE = 'mytarget';
6
+ const BIDDER_URL = '//ad.mail.ru/hbid_prebid/';
7
+ const DEFAULT_CURRENCY = 'RUB';
8
+ const DEFAULT_TTL = 180;
9
+
10
+ function buildPlacement(bidRequest) {
11
+ let { bidId, params } = bidRequest;
12
+ let { placementId, position, response, bidfloor } = params;
13
+ let placement = {
14
+ placementId,
15
+ id: bidId,
16
+ position: position || 0,
17
+ response: response || 0
18
+ };
19
+
20
+ if (typeof bidfloor !== 'undefined') {
21
+ placement.bidfloor = bidfloor;
22
+ }
23
+
24
+ return placement;
25
+ }
26
+
27
+ function getSiteName(referrer) {
28
+ let sitename = config.getConfig('mytarget.sitename');
29
+
30
+ if (!sitename) {
31
+ const parsed = document.createElement('a');
32
+ parsed.href = decodeURIComponent(referrer);
33
+ sitename = parsed.hostname;
34
+ }
35
+
36
+ return sitename;
37
+ }
38
+
39
+ function generateRandomId() {
40
+ return Math.random().toString(16).substring(2);
41
+ }
42
+
43
+ export const spec = {
44
+ code: BIDDER_CODE,
45
+
46
+ isBidRequestValid: function(bid) {
47
+ return !!bid.params.placementId;
48
+ },
49
+
50
+ buildRequests: function(validBidRequests, bidderRequest) {
51
+ let referrer = '';
52
+
53
+ if (bidderRequest && bidderRequest.refererInfo) {
54
+ referrer = bidderRequest.refererInfo.referer;
55
+ }
56
+
57
+ const payload = {
58
+ places: _map(validBidRequests, buildPlacement),
59
+ site: {
60
+ sitename: getSiteName(referrer),
61
+ page: referrer
62
+ },
63
+ settings: {
64
+ currency: DEFAULT_CURRENCY,
65
+ windowSize: {
66
+ width: window.screen.width,
67
+ height: window.screen.height
68
+ }
69
+ }
70
+ };
71
+
72
+ return {
73
+ method: 'POST',
74
+ url: BIDDER_URL,
75
+ data: payload,
76
+ };
77
+ },
78
+
79
+ interpretResponse: function(serverResponse, bidRequest) {
80
+ let { body } = serverResponse;
81
+
82
+ if (body.bids) {
83
+ return _map(body.bids, (bid) => {
84
+ let bidResponse = {
85
+ requestId: bid.id,
86
+ cpm: bid.price,
87
+ width: bid.size.width,
88
+ height: bid.size.height,
89
+ ttl: bid.ttl || DEFAULT_TTL,
90
+ currency: bid.currency || DEFAULT_CURRENCY,
91
+ creativeId: bid.creativeId || generateRandomId(),
92
+ netRevenue: true,
93
+ meta: {
94
+ advertiserDomains: bid.adomain && bid.adomain.length > 0 ? bid.adomain : [],
95
+ }
96
+ }
97
+
98
+ if (bid.adm) {
99
+ bidResponse.ad = bid.adm;
100
+ } else {
101
+ bidResponse.adUrl = bid.displayUrl;
102
+ }
103
+
104
+ return bidResponse;
105
+ });
106
+ }
107
+
108
+ return [];
109
+ }
110
+ }
111
+
112
+ registerBidder(spec);