prebid.js 6.3.0 → 6.7.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 (157) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/gulpfile.js +87 -74
  3. package/integrationExamples/gpt/amp/creative.html +11 -33
  4. package/karma.conf.maker.js +1 -1
  5. package/modules/.submodules.json +2 -1
  6. package/modules/adbookpspBidAdapter.js +27 -10
  7. package/modules/adhashBidAdapter.js +3 -3
  8. package/modules/adkernelBidAdapter.js +148 -62
  9. package/modules/adlooxAdServerVideo.js +2 -2
  10. package/modules/adlooxAnalyticsAdapter.js +4 -4
  11. package/modules/admanBidAdapter.js +10 -4
  12. package/modules/adomikAnalyticsAdapter.js +27 -9
  13. package/modules/adqueryIdSystem.js +103 -0
  14. package/modules/adqueryIdSystem.md +35 -0
  15. package/modules/adyoulikeBidAdapter.js +13 -9
  16. package/modules/aniviewBidAdapter.js +1 -1
  17. package/modules/beopBidAdapter.js +1 -1
  18. package/modules/bidViewability.js +3 -3
  19. package/modules/bidViewabilityIO.js +3 -3
  20. package/modules/bliinkBidAdapter.js +3 -2
  21. package/modules/colossussspBidAdapter.js +12 -8
  22. package/modules/colossussspBidAdapter.md +15 -1
  23. package/modules/compassBidAdapter.js +208 -0
  24. package/modules/compassBidAdapter.md +79 -0
  25. package/modules/consentManagement.js +7 -1
  26. package/modules/consumableBidAdapter.md +1 -1
  27. package/modules/criteoBidAdapter.js +1 -1
  28. package/modules/criteoIdSystem.js +29 -7
  29. package/modules/currency.js +2 -2
  30. package/modules/dailyhuntBidAdapter.js +435 -0
  31. package/modules/dailyhuntBidAdapter.md +4 -0
  32. package/modules/docereeBidAdapter.js +10 -1
  33. package/modules/docereeBidAdapter.md +2 -0
  34. package/modules/engageyaBidAdapter.js +1 -1
  35. package/modules/feedadBidAdapter.js +2 -2
  36. package/modules/feedadBidAdapter.md +4 -2
  37. package/modules/glimpseBidAdapter.js +66 -44
  38. package/modules/gnetBidAdapter.js +3 -3
  39. package/modules/gnetBidAdapter.md +4 -4
  40. package/modules/gptPreAuction.js +55 -7
  41. package/modules/gridBidAdapter.js +4 -3
  42. package/modules/gumgumBidAdapter.js +4 -4
  43. package/modules/idImportLibrary.js +45 -8
  44. package/modules/idImportLibrary.md +4 -0
  45. package/modules/improvedigitalBidAdapter.js +42 -4
  46. package/modules/instreamTracking.js +4 -4
  47. package/modules/invibesBidAdapter.js +49 -5
  48. package/modules/invibesBidAdapter.md +2 -1
  49. package/modules/ixBidAdapter.js +53 -18
  50. package/modules/jwplayerRtdProvider.js +71 -6
  51. package/modules/jwplayerRtdProvider.md +27 -11
  52. package/modules/kargoBidAdapter.js +2 -2
  53. package/modules/limelightDigitalBidAdapter.js +2 -1
  54. package/modules/livewrappedAnalyticsAdapter.js +3 -1
  55. package/modules/livewrappedBidAdapter.js +8 -2
  56. package/modules/loglyliftBidAdapter.js +79 -0
  57. package/modules/loglyliftBidAdapter.md +55 -0
  58. package/modules/nextMillenniumBidAdapter.js +11 -7
  59. package/modules/oguryBidAdapter.js +9 -2
  60. package/modules/onetagBidAdapter.js +4 -2
  61. package/modules/optimeraRtdProvider.js +8 -1
  62. package/modules/ozoneBidAdapter.js +21 -64
  63. package/modules/pilotxBidAdapter.js +147 -0
  64. package/modules/pilotxBidAdapter.md +50 -0
  65. package/modules/proxistoreBidAdapter.js +0 -2
  66. package/modules/pubgeniusBidAdapter.js +1 -1
  67. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  68. package/modules/pubxaiAnalyticsAdapter.js +17 -0
  69. package/modules/richaudienceBidAdapter.js +3 -2
  70. package/modules/riseBidAdapter.js +1 -1
  71. package/modules/rtbhouseBidAdapter.js +14 -4
  72. package/modules/rtdModule/index.js +14 -15
  73. package/modules/rubiconAnalyticsAdapter.js +3 -2
  74. package/modules/rubiconBidAdapter.js +21 -11
  75. package/modules/seedingAllianceBidAdapter.js +3 -3
  76. package/modules/sharethroughBidAdapter.js +12 -17
  77. package/modules/showheroes-bsBidAdapter.js +13 -2
  78. package/modules/synacormediaBidAdapter.js +31 -10
  79. package/modules/tappxBidAdapter.js +8 -5
  80. package/modules/teadsBidAdapter.js +1 -2
  81. package/modules/telariaBidAdapter.js +2 -2
  82. package/modules/trustxBidAdapter.js +8 -16
  83. package/modules/userId/eids.js +7 -1
  84. package/modules/userId/userId.md +8 -0
  85. package/modules/viewability.js +177 -0
  86. package/modules/viewability.md +87 -0
  87. package/modules/welectBidAdapter.js +106 -0
  88. package/modules/yieldmoBidAdapter.js +23 -5
  89. package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
  90. package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
  91. package/package.json +1 -1
  92. package/src/auction.js +2 -2
  93. package/src/config.js +27 -3
  94. package/src/hook.js +5 -1
  95. package/src/prebid.js +20 -4
  96. package/src/secureCreatives.js +3 -2
  97. package/src/utils.js +12 -1
  98. package/test/helpers/prebidGlobal.js +1 -0
  99. package/test/spec/config_spec.js +279 -0
  100. package/test/spec/modules/adbookpspBidAdapter_spec.js +17 -3
  101. package/test/spec/modules/adhashBidAdapter_spec.js +2 -2
  102. package/test/spec/modules/adlooxAnalyticsAdapter_spec.js +6 -6
  103. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  104. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +9 -1
  105. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  106. package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
  107. package/test/spec/modules/beopBidAdapter_spec.js +1 -1
  108. package/test/spec/modules/bidViewabilityIO_spec.js +2 -2
  109. package/test/spec/modules/bidViewability_spec.js +4 -4
  110. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  111. package/test/spec/modules/colossussspBidAdapter_spec.js +5 -2
  112. package/test/spec/modules/compassBidAdapter_spec.js +398 -0
  113. package/test/spec/modules/consentManagement_spec.js +20 -0
  114. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  115. package/test/spec/modules/dailyhuntBidAdapter_spec.js +404 -0
  116. package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
  117. package/test/spec/modules/eids_spec.js +15 -0
  118. package/test/spec/modules/feedadBidAdapter_spec.js +15 -0
  119. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  120. package/test/spec/modules/gnetBidAdapter_spec.js +6 -6
  121. package/test/spec/modules/gptPreAuction_spec.js +177 -2
  122. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  123. package/test/spec/modules/improvedigitalBidAdapter_spec.js +45 -1
  124. package/test/spec/modules/invibesBidAdapter_spec.js +119 -0
  125. package/test/spec/modules/ixBidAdapter_spec.js +112 -62
  126. package/test/spec/modules/jwplayerRtdProvider_spec.js +195 -2
  127. package/test/spec/modules/kargoBidAdapter_spec.js +1 -1
  128. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
  129. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
  130. package/test/spec/modules/livewrappedBidAdapter_spec.js +31 -0
  131. package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
  132. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +9 -2
  133. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  134. package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
  135. package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
  136. package/test/spec/modules/pilotxBidAdapter_spec.js +244 -0
  137. package/test/spec/modules/pubgeniusBidAdapter_spec.js +3 -3
  138. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  139. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +11 -0
  140. package/test/spec/modules/realTimeDataModule_spec.js +67 -5
  141. package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
  142. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  143. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  144. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +30 -0
  145. package/test/spec/modules/rubiconBidAdapter_spec.js +48 -9
  146. package/test/spec/modules/sharethroughBidAdapter_spec.js +91 -6
  147. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  148. package/test/spec/modules/synacormediaBidAdapter_spec.js +70 -0
  149. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  150. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  151. package/test/spec/modules/userId_spec.js +68 -19
  152. package/test/spec/modules/viewability_spec.js +280 -0
  153. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  154. package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
  155. package/test/spec/unit/pbjs_api_spec.js +3 -1
  156. package/test/test_deps.js +3 -0
  157. package/test/test_index.js +1 -3
@@ -52,7 +52,7 @@ aliases:
52
52
  - &unit_test_steps
53
53
  - checkout
54
54
  - restore_cache: *restore_dep_cache
55
- - run: npm install
55
+ - run: npm ci
56
56
  - save_cache: *save_dep_cache
57
57
  - run: *install
58
58
  - run: *setup_browserstack
package/gulpfile.js CHANGED
@@ -115,32 +115,6 @@ function viewReview(done) {
115
115
 
116
116
  viewReview.displayName = 'view-review';
117
117
 
118
- // Watch Task with Live Reload
119
- function watch(done) {
120
- var mainWatcher = gulp.watch([
121
- 'src/**/*.js',
122
- 'modules/**/*.js',
123
- 'test/spec/**/*.js',
124
- '!test/spec/loaders/**/*.js'
125
- ]);
126
- var loaderWatcher = gulp.watch([
127
- 'loaders/**/*.js',
128
- 'test/spec/loaders/**/*.js'
129
- ]);
130
-
131
- connect.server({
132
- https: argv.https,
133
- port: port,
134
- host: FAKE_SERVER_HOST,
135
- root: './',
136
- livereload: true
137
- });
138
-
139
- mainWatcher.on('all', gulp.series(clean, gulp.parallel(lint, 'build-bundle-dev', test)));
140
- loaderWatcher.on('all', gulp.series(lint));
141
- done();
142
- };
143
-
144
118
  function makeDevpackPkg() {
145
119
  var cloned = _.cloneDeep(webpackConfig);
146
120
  cloned.devtool = 'source-map';
@@ -247,60 +221,68 @@ function bundle(dev, moduleArr) {
247
221
  // If --browsers is given, browsers can be chosen explicitly. e.g. --browsers=chrome,firefox,ie9
248
222
  // If --notest is given, it will immediately skip the test task (useful for developing changes with `gulp serve --notest`)
249
223
 
250
- function test(done) {
251
- if (argv.notest) {
252
- done();
253
- } else if (argv.e2e) {
254
- let wdioCmd = path.join(__dirname, 'node_modules/.bin/wdio');
255
- let wdioConf = path.join(__dirname, 'wdio.conf.js');
256
- let wdioOpts;
257
-
258
- if (argv.file) {
259
- wdioOpts = [
260
- wdioConf,
261
- `--spec`,
262
- `${argv.file}`
263
- ]
264
- } else {
265
- wdioOpts = [
266
- wdioConf
267
- ];
268
- }
224
+ function testTaskMaker(options = {}) {
225
+ ['watch', 'e2e', 'file', 'browserstack', 'notest'].forEach(opt => {
226
+ options[opt] = options[opt] || argv[opt];
227
+ })
269
228
 
270
- // run fake-server
271
- const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]);
272
- fakeServer.stdout.on('data', (data) => {
273
- console.log(`stdout: ${data}`);
274
- });
275
- fakeServer.stderr.on('data', (data) => {
276
- console.log(`stderr: ${data}`);
277
- });
229
+ return function test(done) {
230
+ if (options.notest) {
231
+ done();
232
+ } else if (options.e2e) {
233
+ let wdioCmd = path.join(__dirname, 'node_modules/.bin/wdio');
234
+ let wdioConf = path.join(__dirname, 'wdio.conf.js');
235
+ let wdioOpts;
236
+
237
+ if (options.file) {
238
+ wdioOpts = [
239
+ wdioConf,
240
+ `--spec`,
241
+ `${options.file}`
242
+ ]
243
+ } else {
244
+ wdioOpts = [
245
+ wdioConf
246
+ ];
247
+ }
278
248
 
279
- execa(wdioCmd, wdioOpts, { stdio: 'inherit' })
280
- .then(stdout => {
281
- // kill fake server
282
- fakeServer.kill('SIGINT');
283
- done();
284
- process.exit(0);
285
- })
286
- .catch(err => {
287
- // kill fake server
288
- fakeServer.kill('SIGINT');
289
- done(new Error(`Tests failed with error: ${err}`));
290
- process.exit(1);
249
+ // run fake-server
250
+ const fakeServer = spawn('node', ['./test/fake-server/index.js', `--port=${FAKE_SERVER_PORT}`]);
251
+ fakeServer.stdout.on('data', (data) => {
252
+ console.log(`stdout: ${data}`);
253
+ });
254
+ fakeServer.stderr.on('data', (data) => {
255
+ console.log(`stderr: ${data}`);
291
256
  });
292
- } else {
293
- var karmaConf = karmaConfMaker(false, argv.browserstack, argv.watch, argv.file);
294
257
 
295
- var browserOverride = helpers.parseBrowserArgs(argv);
296
- if (browserOverride.length > 0) {
297
- karmaConf.browsers = browserOverride;
298
- }
258
+ execa(wdioCmd, wdioOpts, { stdio: 'inherit' })
259
+ .then(stdout => {
260
+ // kill fake server
261
+ fakeServer.kill('SIGINT');
262
+ done();
263
+ process.exit(0);
264
+ })
265
+ .catch(err => {
266
+ // kill fake server
267
+ fakeServer.kill('SIGINT');
268
+ done(new Error(`Tests failed with error: ${err}`));
269
+ process.exit(1);
270
+ });
271
+ } else {
272
+ var karmaConf = karmaConfMaker(false, options.browserstack, options.watch, options.file);
299
273
 
300
- new KarmaServer(karmaConf, newKarmaCallback(done)).start();
274
+ var browserOverride = helpers.parseBrowserArgs(argv);
275
+ if (browserOverride.length > 0) {
276
+ karmaConf.browsers = browserOverride;
277
+ }
278
+
279
+ new KarmaServer(karmaConf, newKarmaCallback(done)).start();
280
+ }
301
281
  }
302
282
  }
303
283
 
284
+ const test = testTaskMaker();
285
+
304
286
  function newKarmaCallback(done) {
305
287
  return function (exitCode) {
306
288
  if (exitCode) {
@@ -377,6 +359,35 @@ function startFakeServer() {
377
359
  });
378
360
  }
379
361
 
362
+ // Watch Task with Live Reload
363
+ function watchTaskMaker(options = {}) {
364
+ if (options.livereload == null) {
365
+ options.livereload = true;
366
+ }
367
+ options.alsoWatch = options.alsoWatch || [];
368
+
369
+ return function watch(done) {
370
+ var mainWatcher = gulp.watch([
371
+ 'src/**/*.js',
372
+ 'modules/**/*.js',
373
+ ].concat(options.alsoWatch));
374
+
375
+ connect.server({
376
+ https: argv.https,
377
+ port: port,
378
+ host: FAKE_SERVER_HOST,
379
+ root: './',
380
+ livereload: options.livereload
381
+ });
382
+
383
+ mainWatcher.on('all', options.task());
384
+ done();
385
+ }
386
+ }
387
+
388
+ const watch = watchTaskMaker({alsoWatch: ['test/**/*.js'], task: () => gulp.series(clean, gulp.parallel(lint, 'build-bundle-dev', test))});
389
+ const watchFast = watchTaskMaker({livereload: false, task: () => gulp.series('build-bundle-dev')});
390
+
380
391
  // support tasks
381
392
  gulp.task(lint);
382
393
  gulp.task(watch);
@@ -389,7 +400,8 @@ gulp.task('build-bundle-dev', gulp.series(makeDevpackPkg, gulpBundle.bind(null,
389
400
  gulp.task('build-bundle-prod', gulp.series(makeWebpackPkg, gulpBundle.bind(null, false)));
390
401
 
391
402
  // public tasks (dependencies are needed for each task since they can be ran on their own)
392
- gulp.task('test', gulp.series(clean, lint, test));
403
+ gulp.task('test-only', test);
404
+ gulp.task('test', gulp.series(clean, lint, 'test-only'));
393
405
 
394
406
  gulp.task('test-coverage', gulp.series(clean, testCoverage));
395
407
  gulp.task(viewCoverage);
@@ -400,7 +412,8 @@ gulp.task('build', gulp.series(clean, 'build-bundle-prod'));
400
412
  gulp.task('build-postbid', gulp.series(escapePostbidConfig, buildPostbid));
401
413
 
402
414
  gulp.task('serve', gulp.series(clean, lint, gulp.parallel('build-bundle-dev', watch, test)));
403
- gulp.task('serve-fast', gulp.series(clean, gulp.parallel('build-bundle-dev', watch)));
415
+ gulp.task('serve-fast', gulp.series(clean, gulp.parallel('build-bundle-dev', watchFast)));
416
+ gulp.task('serve-and-test', gulp.series(clean, gulp.parallel('build-bundle-dev', watchFast, testTaskMaker({watch: true}))));
404
417
  gulp.task('serve-fake', gulp.series(clean, gulp.parallel('build-bundle-dev', watch), injectFakeServerEndpointDev, test, startFakeServer));
405
418
 
406
419
  gulp.task('default', gulp.series(clean, makeWebpackPkg));
@@ -1,38 +1,16 @@
1
1
  <!-- This script tag should be returned by your ad server -->
2
2
 
3
+ <script src="https://cdn.jsdelivr.net/npm/prebid-universal-creative@latest/dist/creative.js"></script>
3
4
  <script>
4
- // This is the `renderAd` function from Prebid.js moved within the creative iframe
5
- var renderAd = function (ev) {
6
- var key = ev.message ? "message" : "data";
7
- var data = {};
8
- try {
9
- data = JSON.parse(ev[key]);
10
- } catch (e) {
11
- // Do nothing. No ad found.
12
- }
13
- if (data.ad || data.adUrl) {
14
- if (data.ad) {
15
- document.write(data.ad);
16
- document.close();
17
- } else if (data.adUrl) {
18
- document.write('<IFRAME SRC="' + data.adUrl + '" WIDTH="'+ data.width +'" HEIGHT="'+ data.height +'" FRAMEBORDER="0" SCROLLING="no" MARGINHEIGHT="0" MARGINWIDTH="0" TOPMARGIN="0" LEFTMARGIN="0" ALLOWTRANSPARENCY="true"></IFRAME>');
19
- document.close();
20
- }
21
- }
22
- };
5
+ var ucTagData = {};
6
+ ucTagData.adServerDomain = "";
7
+ ucTagData.pubUrl = "%%PATTERN:url%%";
8
+ ucTagData.targetingMap = "%%PATTERN:TARGETINGMAP%%";
9
+ ucTagData.hbPb = "%%PATTERN:hb_pb%%";
23
10
 
24
- var requestAdFromPrebid = function () {
25
- var message = JSON.stringify({
26
- message: 'Prebid creative requested: %%PATTERN:hb_adid%%',
27
- adId: '%%PATTERN:hb_adid%%'
28
- });
29
- window.parent.postMessage(message, '*');
30
- };
31
-
32
- var listenAdFromPrebid = function () {
33
- window.addEventListener("message", renderAd, false);
34
- };
35
-
36
- listenAdFromPrebid();
37
- requestAdFromPrebid();
11
+ try {
12
+ ucTag.renderAd(document, ucTagData);
13
+ } catch (e) {
14
+ console.log(e);
15
+ }
38
16
  </script>
@@ -111,7 +111,7 @@ module.exports = function(codeCoverage, browserstack, watchMode, file) {
111
111
  var webpackConfig = newWebpackConfig(codeCoverage);
112
112
  var plugins = newPluginsArray(browserstack);
113
113
 
114
- var files = file ? ['test/helpers/prebidGlobal.js', file] : ['test/test_index.js'];
114
+ var files = file ? ['test/test_deps.js', file] : ['test/test_index.js'];
115
115
  // This file opens the /debug.html tab automatically.
116
116
  // It has no real value unless you're running --watch, and intend to do some debugging in the browser.
117
117
  if (watchMode) {
@@ -35,7 +35,8 @@
35
35
  "uid2IdSystem",
36
36
  "unifiedIdSystem",
37
37
  "verizonMediaIdSystem",
38
- "zeotapIdPlusIdSystem"
38
+ "zeotapIdPlusIdSystem",
39
+ "adqueryIdSystem"
39
40
  ],
40
41
  "adpod": [
41
42
  "freeWheelAdserverVideo",
@@ -363,7 +363,7 @@ function impBidsToPrebidBids(
363
363
  }
364
364
 
365
365
  const impToPrebidBid =
366
- (bidderRequestBody, bidResponseCurrency, referrer, targetingMap) => (bid) => {
366
+ (bidderRequestBody, bidResponseCurrency, referrer, targetingMap) => (bid, bidIndex) => {
367
367
  try {
368
368
  const bidRequest = findBidRequest(bidderRequestBody, bid);
369
369
 
@@ -377,7 +377,7 @@ const impToPrebidBid =
377
377
  let prebidBid = {
378
378
  ad: bid.adm,
379
379
  adId: bid.adid,
380
- adserverTargeting: targetingMap[bid.impid],
380
+ adserverTargeting: targetingMap[bidIndex],
381
381
  adUnitCode: bidRequest.tagid,
382
382
  bidderRequestId: bidderRequestBody.id,
383
383
  bidId: bid.id,
@@ -408,6 +408,9 @@ const impToPrebidBid =
408
408
  };
409
409
  }
410
410
 
411
+ if (deepAccess(bid, 'ext.pa_win') === true) {
412
+ prebidBid.auctionWinner = true;
413
+ }
411
414
  return prebidBid;
412
415
  } catch (error) {
413
416
  logError(`${BIDDER_CODE}: Error while building bid`, error);
@@ -429,29 +432,43 @@ function buildTargetingMap(bids) {
429
432
  const values = impIds.reduce((result, id) => {
430
433
  result[id] = {
431
434
  lineItemIds: [],
435
+ orderIds: [],
432
436
  dealIds: [],
433
437
  adIds: [],
438
+ adAndOrderIndexes: []
434
439
  };
435
440
 
436
441
  return result;
437
442
  }, {});
438
443
 
439
- bids.forEach((bid) => {
440
- values[bid.impid].lineItemIds.push(bid.ext.liid);
441
- values[bid.impid].dealIds.push(bid.dealid);
442
- values[bid.impid].adIds.push(bid.adid);
444
+ bids.forEach((bid, bidIndex) => {
445
+ let impId = bid.impid;
446
+ values[impId].lineItemIds.push(bid.ext.liid);
447
+ values[impId].dealIds.push(bid.dealid);
448
+ values[impId].adIds.push(bid.adid);
449
+
450
+ if (deepAccess(bid, 'ext.ordid')) {
451
+ values[impId].orderIds.push(bid.ext.ordid);
452
+ bid.ext.ordid.split(TARGETING_VALUE_SEPARATOR).forEach((ordid, ordIndex) => {
453
+ let adIdIndex = values[impId].adIds.indexOf(bid.adid);
454
+ values[impId].adAndOrderIndexes.push(adIdIndex + '_' + ordIndex)
455
+ })
456
+ }
443
457
  });
444
458
 
445
459
  const targetingMap = {};
446
460
 
447
- for (const id of impIds) {
448
- targetingMap[id] = {
461
+ bids.forEach((bid, bidIndex) => {
462
+ let id = bid.impid;
463
+
464
+ targetingMap[bidIndex] = {
449
465
  hb_liid_adbookpsp: values[id].lineItemIds.join(TARGETING_VALUE_SEPARATOR),
450
466
  hb_deal_adbookpsp: values[id].dealIds.join(TARGETING_VALUE_SEPARATOR),
467
+ hb_ad_ord_adbookpsp: values[id].adAndOrderIndexes.join(TARGETING_VALUE_SEPARATOR),
451
468
  hb_adid_c_adbookpsp: values[id].adIds.join(TARGETING_VALUE_SEPARATOR),
469
+ hb_ordid_adbookpsp: values[id].orderIds.join(TARGETING_VALUE_SEPARATOR),
452
470
  };
453
- }
454
-
471
+ })
455
472
  return targetingMap;
456
473
  }
457
474
 
@@ -6,7 +6,7 @@ const VERSION = '1.0';
6
6
 
7
7
  export const spec = {
8
8
  code: 'adhash',
9
- url: 'https://bidder.adhash.org/rtb?version=' + VERSION + '&prebid=true',
9
+ url: 'https://bidder.adhash.com/rtb?version=' + VERSION + '&prebid=true',
10
10
  supportedMediaTypes: [ BANNER ],
11
11
 
12
12
  isBidRequestValid: (bid) => {
@@ -37,7 +37,7 @@ export const spec = {
37
37
  var size = validBidRequests[i].sizes[index].join('x');
38
38
  bidRequests.push({
39
39
  method: 'POST',
40
- url: url,
40
+ url: url + '&publisher=' + validBidRequests[i].params.publisherId,
41
41
  bidRequest: validBidRequests[i],
42
42
  data: {
43
43
  timezone: new Date().getTimezoneOffset() / 60,
@@ -87,7 +87,7 @@ export const spec = {
87
87
  cpm: responseBody.creatives[0].costEUR,
88
88
  ad:
89
89
  `<div id="${oneTimeId}"></div>
90
- <script src="https://bidder.adhash.org/static/scripts/creative.min.js"></script>
90
+ <script src="https://bidder.adhash.com/static/scripts/creative.min.js"></script>
91
91
  <script>callAdvertiser(${bidderResponse},['${oneTimeId}'],${requestData},${publisherURL})</script>`,
92
92
  width: request.bidRequest.sizes[0][0],
93
93
  height: request.bidRequest.sizes[0][1],
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isStr, isArray, isPlainObject, deepSetValue, isNumber, deepAccess, getAdUnitSizes, parseGPTSingleSizeArrayToRtbSize,
3
- cleanObj, contains, getDNT, parseUrl, createTrackPixelHtml, _each, isArrayOfNums
3
+ cleanObj, contains, getDNT, parseUrl, createTrackPixelHtml, _each, isArrayOfNums, mergeDeep, isEmpty, inIframe
4
4
  } from '../src/utils.js';
5
5
  import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js';
6
6
  import {registerBidder} from '../src/adapters/bidderFactory.js';
@@ -77,7 +77,8 @@ export const spec = {
77
77
  {code: 'unibots'},
78
78
  {code: 'catapultx'},
79
79
  {code: 'ergadx'},
80
- {code: 'turktelekom'}
80
+ {code: 'turktelekom'},
81
+ {code: 'felixads'}
81
82
  ],
82
83
  supportedMediaTypes: [BANNER, VIDEO, NATIVE],
83
84
 
@@ -103,17 +104,16 @@ export const spec = {
103
104
  * @returns {ServerRequest[]}
104
105
  */
105
106
  buildRequests: function (bidRequests, bidderRequest) {
106
- let impDispatch = dispatchImps(bidRequests, bidderRequest.refererInfo);
107
+ let impGroups = groupImpressionsByHostZone(bidRequests, bidderRequest.refererInfo);
107
108
  let requests = [];
108
109
  let schain = bidRequests[0].schain;
109
- Object.keys(impDispatch).forEach(host => {
110
- Object.keys(impDispatch[host]).forEach(zoneId => {
111
- const request = buildRtbRequest(impDispatch[host][zoneId], bidderRequest, schain);
112
- requests.push({
113
- method: 'POST',
114
- url: `https://${host}/hb?zone=${zoneId}&v=${VERSION}`,
115
- data: JSON.stringify(request)
116
- });
110
+ _each(impGroups, impGroup => {
111
+ let {host, zoneId, imps} = impGroup;
112
+ const request = buildRtbRequest(imps, bidderRequest, schain);
113
+ requests.push({
114
+ method: 'POST',
115
+ url: `https://${host}/hb?zone=${zoneId}&v=${VERSION}`,
116
+ data: JSON.stringify(request)
117
117
  });
118
118
  });
119
119
  return requests;
@@ -209,17 +209,19 @@ registerBidder(spec);
209
209
  * @param bidRequests {BidRequest[]}
210
210
  * @param refererInfo {refererInfo}
211
211
  */
212
- function dispatchImps(bidRequests, refererInfo) {
212
+ function groupImpressionsByHostZone(bidRequests, refererInfo) {
213
213
  let secure = (refererInfo && refererInfo.referer.indexOf('https:') === 0);
214
- return bidRequests.map(bidRequest => buildImp(bidRequest, secure))
215
- .reduce((acc, curr, index) => {
216
- let bidRequest = bidRequests[index];
217
- let {zoneId, host} = bidRequest.params;
218
- acc[host] = acc[host] || {};
219
- acc[host][zoneId] = acc[host][zoneId] || [];
220
- acc[host][zoneId].push(curr);
221
- return acc;
222
- }, {});
214
+ return Object.values(
215
+ bidRequests.map(bidRequest => buildImp(bidRequest, secure))
216
+ .reduce((acc, curr, index) => {
217
+ let bidRequest = bidRequests[index];
218
+ let {zoneId, host} = bidRequest.params;
219
+ let key = `${host}_${zoneId}`;
220
+ acc[key] = acc[key] || {host: host, zoneId: zoneId, imps: []};
221
+ acc[key].imps.push(curr);
222
+ return acc;
223
+ }, {})
224
+ );
223
225
  }
224
226
 
225
227
  function getBidFloor(bid, mediaType, sizes) {
@@ -365,57 +367,142 @@ function getAllowedSyncMethod(bidderCode) {
365
367
  }
366
368
 
367
369
  /**
368
- * Builds complete rtb request
369
- * @param imps {Object} Collection of rtb impressions
370
- * @param bidderRequest {BidderRequest}
371
- * @param schain {Object=} Supply chain config
372
- * @return {Object} Complete rtb request
370
+ * Create device object from fpd and host-collected data
371
+ * @param fpd {Object}
372
+ * @returns {{device: Object}}
373
373
  */
374
- function buildRtbRequest(imps, bidderRequest, schain) {
375
- let {bidderCode, gdprConsent, auctionId, refererInfo, timeout, uspConsent} = bidderRequest;
376
- let coppa = config.getConfig('coppa');
377
- let req = {
378
- 'id': auctionId,
379
- 'imp': imps,
380
- 'site': createSite(refererInfo),
381
- 'at': 1,
382
- 'device': {
383
- 'ip': 'caller',
384
- 'ipv6': 'caller',
385
- 'ua': 'caller',
386
- 'js': 1,
387
- 'language': getLanguage()
388
- },
389
- 'tmax': parseInt(timeout)
390
- };
374
+ function makeDevice(fpd) {
375
+ let device = mergeDeep({
376
+ 'ip': 'caller',
377
+ 'ipv6': 'caller',
378
+ 'ua': 'caller',
379
+ 'js': 1,
380
+ 'language': getLanguage()
381
+ }, fpd.device || {});
391
382
  if (getDNT()) {
392
- req.device.dnt = 1;
383
+ device.dnt = 1;
384
+ }
385
+ return {device: device};
386
+ }
387
+
388
+ /**
389
+ * Create site or app description object
390
+ * @param bidderRequest {BidderRequest}
391
+ * @param fpd {Object}
392
+ * @returns {{site: Object}|{app: Object}}
393
+ */
394
+ function makeSiteOrApp(bidderRequest, fpd) {
395
+ let {refererInfo} = bidderRequest;
396
+ let appConfig = config.getConfig('app');
397
+ if (isEmpty(appConfig)) {
398
+ return {site: createSite(refererInfo, fpd)}
399
+ } else {
400
+ return {app: appConfig};
393
401
  }
402
+ }
403
+
404
+ /**
405
+ * Create user description object
406
+ * @param bidderRequest {BidderRequest}
407
+ * @param fpd {Object}
408
+ * @returns {{user: Object} | undefined}
409
+ */
410
+ function makeUser(bidderRequest, fpd) {
411
+ let {gdprConsent} = bidderRequest;
412
+ let user = fpd.user || {};
413
+ if (gdprConsent && gdprConsent.consentString !== undefined) {
414
+ deepSetValue(user, 'ext.consent', gdprConsent.consentString);
415
+ }
416
+ let eids = getExtendedUserIds(bidderRequest);
417
+ if (eids) {
418
+ deepSetValue(user, 'ext.eids', eids);
419
+ }
420
+ if (!isEmpty(user)) { return {user: user}; }
421
+ }
422
+
423
+ /**
424
+ * Create privacy regulations object
425
+ * @param bidderRequest {BidderRequest}
426
+ * @returns {{regs: Object} | undefined}
427
+ */
428
+ function makeRegulations(bidderRequest) {
429
+ let {gdprConsent, uspConsent} = bidderRequest;
430
+ let regs = {};
394
431
  if (gdprConsent) {
395
432
  if (gdprConsent.gdprApplies !== undefined) {
396
- deepSetValue(req, 'regs.ext.gdpr', ~~gdprConsent.gdprApplies);
397
- }
398
- if (gdprConsent.consentString !== undefined) {
399
- deepSetValue(req, 'user.ext.consent', gdprConsent.consentString);
433
+ deepSetValue(regs, 'regs.ext.gdpr', ~~gdprConsent.gdprApplies);
400
434
  }
401
435
  }
402
436
  if (uspConsent) {
403
- deepSetValue(req, 'regs.ext.us_privacy', uspConsent);
437
+ deepSetValue(regs, 'regs.ext.us_privacy', uspConsent);
438
+ }
439
+ if (config.getConfig('coppa')) {
440
+ deepSetValue(regs, 'regs.coppa', 1);
404
441
  }
405
- if (coppa) {
406
- deepSetValue(req, 'regs.coppa', 1);
442
+ if (!isEmpty(regs)) {
443
+ return regs;
407
444
  }
445
+ }
446
+
447
+ /**
448
+ * Create top-level request object
449
+ * @param bidderRequest {BidderRequest}
450
+ * @param imps {Object} Impressions
451
+ * @param fpd {Object} First party data
452
+ * @returns
453
+ */
454
+ function makeBaseRequest(bidderRequest, imps, fpd) {
455
+ let {auctionId, timeout} = bidderRequest;
456
+ let request = {
457
+ 'id': auctionId,
458
+ 'imp': imps,
459
+ 'at': 1,
460
+ 'tmax': parseInt(timeout)
461
+ };
462
+ if (!isEmpty(fpd.bcat)) {
463
+ request.bcat = fpd.bcat;
464
+ }
465
+ if (!isEmpty(fpd.badv)) {
466
+ request.badv = fpd.badv;
467
+ }
468
+ return request;
469
+ }
470
+
471
+ /**
472
+ * Initialize sync capabilities
473
+ * @param bidderRequest {BidderRequest}
474
+ */
475
+ function makeSyncInfo(bidderRequest) {
476
+ let {bidderCode} = bidderRequest;
408
477
  let syncMethod = getAllowedSyncMethod(bidderCode);
409
478
  if (syncMethod) {
410
- deepSetValue(req, 'ext.adk_usersync', syncMethod);
479
+ let res = {};
480
+ deepSetValue(res, 'ext.adk_usersync', syncMethod);
481
+ return res;
411
482
  }
483
+ }
484
+
485
+ /**
486
+ * Builds complete rtb request
487
+ * @param imps {Object} Collection of rtb impressions
488
+ * @param bidderRequest {BidderRequest}
489
+ * @param schain {Object=} Supply chain config
490
+ * @return {Object} Complete rtb request
491
+ */
492
+ function buildRtbRequest(imps, bidderRequest, schain) {
493
+ let fpd = config.getConfig('ortb2') || {};
494
+
495
+ let req = mergeDeep(
496
+ makeBaseRequest(bidderRequest, imps, fpd),
497
+ makeDevice(fpd),
498
+ makeSiteOrApp(bidderRequest, fpd),
499
+ makeUser(bidderRequest, fpd),
500
+ makeRegulations(bidderRequest),
501
+ makeSyncInfo(bidderRequest)
502
+ );
412
503
  if (schain) {
413
504
  deepSetValue(req, 'source.ext.schain', schain);
414
505
  }
415
- let eids = getExtendedUserIds(bidderRequest);
416
- if (eids) {
417
- deepSetValue(req, 'user.ext.eids', eids);
418
- }
419
506
  return req;
420
507
  }
421
508
 
@@ -431,18 +518,17 @@ function getLanguage() {
431
518
  /**
432
519
  * Creates site description object
433
520
  */
434
- function createSite(refInfo) {
521
+ function createSite(refInfo, fpd) {
435
522
  let url = parseUrl(refInfo.referer);
436
523
  let site = {
437
524
  'domain': url.hostname,
438
525
  'page': `${url.protocol}://${url.hostname}${url.pathname}`
439
526
  };
440
- if (self === top && document.referrer) {
527
+ mergeDeep(site, fpd.site);
528
+ if (!inIframe() && document.referrer) {
441
529
  site.ref = document.referrer;
442
- }
443
- let keywords = document.getElementsByTagName('meta')['keywords'];
444
- if (keywords && keywords.content) {
445
- site.keywords = keywords.content;
530
+ } else {
531
+ delete site.ref;
446
532
  }
447
533
  return site;
448
534
  }