prebid.js 6.2.0 → 6.6.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 (169) hide show
  1. package/.circleci/config.yml +1 -1
  2. package/gulpfile.js +87 -82
  3. package/integrationExamples/gpt/weboramaRtdProvider_example.html +23 -14
  4. package/karma.conf.maker.js +1 -1
  5. package/modules/.submodules.json +2 -1
  6. package/modules/33acrossBidAdapter.js +189 -102
  7. package/modules/adagioBidAdapter.js +1 -1
  8. package/modules/addefendBidAdapter.js +1 -0
  9. package/modules/adkernelBidAdapter.js +148 -62
  10. package/modules/adlooxAdServerVideo.js +2 -2
  11. package/modules/adlooxAnalyticsAdapter.js +4 -4
  12. package/modules/admanBidAdapter.js +11 -4
  13. package/modules/admixerBidAdapter.js +1 -1
  14. package/modules/adnuntiusBidAdapter.js +3 -1
  15. package/modules/adomikAnalyticsAdapter.js +27 -9
  16. package/modules/adqueryIdSystem.js +103 -0
  17. package/modules/adqueryIdSystem.md +35 -0
  18. package/modules/adxcgBidAdapter.js +311 -359
  19. package/modules/adxcgBidAdapter.md +22 -21
  20. package/modules/adyoulikeBidAdapter.js +13 -9
  21. package/modules/aniviewBidAdapter.js +1 -1
  22. package/modules/appnexusBidAdapter.js +0 -1
  23. package/modules/beopBidAdapter.js +6 -4
  24. package/modules/bidViewability.js +3 -3
  25. package/modules/bidViewabilityIO.js +3 -3
  26. package/modules/bliinkBidAdapter.js +3 -2
  27. package/modules/colossussspBidAdapter.js +7 -0
  28. package/modules/compassBidAdapter.js +208 -0
  29. package/modules/compassBidAdapter.md +79 -0
  30. package/modules/consentManagement.js +7 -1
  31. package/modules/criteoBidAdapter.js +1 -1
  32. package/modules/criteoIdSystem.js +29 -7
  33. package/modules/currency.js +2 -2
  34. package/modules/cwireBidAdapter.js +3 -0
  35. package/modules/dailyhuntBidAdapter.js +435 -0
  36. package/modules/dailyhuntBidAdapter.md +4 -0
  37. package/modules/docereeBidAdapter.js +10 -1
  38. package/modules/docereeBidAdapter.md +2 -0
  39. package/modules/dspxBidAdapter.js +1 -1
  40. package/modules/engageyaBidAdapter.js +1 -1
  41. package/modules/feedadBidAdapter.js +2 -2
  42. package/modules/feedadBidAdapter.md +4 -2
  43. package/modules/futureads.md +48 -0
  44. package/modules/glimpseBidAdapter.js +82 -47
  45. package/modules/gptPreAuction.js +55 -7
  46. package/modules/gridBidAdapter.js +4 -3
  47. package/modules/gumgumBidAdapter.js +2 -2
  48. package/modules/idImportLibrary.js +45 -8
  49. package/modules/idImportLibrary.md +4 -0
  50. package/modules/improvedigitalBidAdapter.js +42 -4
  51. package/modules/instreamTracking.js +4 -4
  52. package/modules/invibesBidAdapter.js +49 -5
  53. package/modules/invibesBidAdapter.md +2 -1
  54. package/modules/ixBidAdapter.js +53 -18
  55. package/modules/kinessoIdSystem.js +1 -1
  56. package/modules/limelightDigitalBidAdapter.js +2 -1
  57. package/modules/livewrappedAnalyticsAdapter.js +3 -1
  58. package/modules/livewrappedBidAdapter.js +8 -2
  59. package/modules/loglyliftBidAdapter.js +79 -0
  60. package/modules/loglyliftBidAdapter.md +55 -0
  61. package/modules/lotamePanoramaIdSystem.js +80 -8
  62. package/modules/mediasquareBidAdapter.js +1 -9
  63. package/modules/nextMillenniumBidAdapter.js +39 -7
  64. package/modules/oguryBidAdapter.js +9 -2
  65. package/modules/onetagBidAdapter.js +4 -2
  66. package/modules/optimeraRtdProvider.js +8 -1
  67. package/modules/ozoneBidAdapter.js +21 -64
  68. package/modules/prebidServerBidAdapter/index.js +16 -12
  69. package/modules/proxistoreBidAdapter.js +0 -2
  70. package/modules/pubgeniusBidAdapter.js +1 -1
  71. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  72. package/modules/pubxaiAnalyticsAdapter.js +17 -0
  73. package/modules/richaudienceBidAdapter.js +4 -4
  74. package/modules/riseBidAdapter.js +1 -1
  75. package/modules/rtbhouseBidAdapter.js +14 -4
  76. package/modules/rtdModule/index.js +49 -18
  77. package/modules/rubiconBidAdapter.js +31 -19
  78. package/modules/sharedIdSystem.js +27 -1
  79. package/modules/showheroes-bsBidAdapter.js +13 -2
  80. package/modules/tappxBidAdapter.js +8 -5
  81. package/modules/targetVideoBidAdapter.js +187 -0
  82. package/modules/targetVideoBidAdapter.md +34 -0
  83. package/modules/teadsBidAdapter.js +1 -2
  84. package/modules/telariaBidAdapter.js +2 -2
  85. package/modules/trustxBidAdapter.js +8 -16
  86. package/modules/userId/eids.js +7 -1
  87. package/modules/userId/userId.md +8 -0
  88. package/modules/vidoomyBidAdapter.js +16 -10
  89. package/modules/weboramaRtdProvider.js +288 -73
  90. package/modules/weboramaRtdProvider.md +27 -10
  91. package/modules/welectBidAdapter.js +106 -0
  92. package/modules/yahoosspBidAdapter.js +5 -1
  93. package/modules/yieldmoBidAdapter.js +23 -5
  94. package/modules/zetaSspBidAdapter.md +33 -1
  95. package/modules/zeta_global_sspAnalyticsAdapter.js +97 -0
  96. package/modules/zeta_global_sspAnalyticsAdapter.md +24 -0
  97. package/modules/zeta_global_sspBidAdapter.js +22 -1
  98. package/package.json +1 -1
  99. package/plugins/pbjsGlobals.js +28 -1
  100. package/src/auction.js +2 -2
  101. package/src/config.js +27 -3
  102. package/src/hook.js +5 -1
  103. package/src/prebid.js +21 -6
  104. package/src/targeting.js +22 -1
  105. package/src/utils.js +46 -8
  106. package/test/helpers/prebidGlobal.js +1 -0
  107. package/test/spec/config_spec.js +279 -0
  108. package/test/spec/modules/33acrossBidAdapter_spec.js +300 -78
  109. package/test/spec/modules/adlooxAnalyticsAdapter_spec.js +6 -6
  110. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  111. package/test/spec/modules/adnuntiusBidAdapter_spec.js +17 -0
  112. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +9 -1
  113. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  114. package/test/spec/modules/adxcgBidAdapter_spec.js +820 -571
  115. package/test/spec/modules/adyoulikeBidAdapter_spec.js +49 -0
  116. package/test/spec/modules/beopBidAdapter_spec.js +1 -1
  117. package/test/spec/modules/bidViewabilityIO_spec.js +2 -2
  118. package/test/spec/modules/bidViewability_spec.js +4 -4
  119. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  120. package/test/spec/modules/colossussspBidAdapter_spec.js +9 -0
  121. package/test/spec/modules/compassBidAdapter_spec.js +398 -0
  122. package/test/spec/modules/consentManagement_spec.js +20 -0
  123. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  124. package/test/spec/modules/cwireBidAdapter_spec.js +10 -8
  125. package/test/spec/modules/dailyhuntBidAdapter_spec.js +404 -0
  126. package/test/spec/modules/docereeBidAdapter_spec.js +9 -1
  127. package/test/spec/modules/eids_spec.js +15 -0
  128. package/test/spec/modules/feedadBidAdapter_spec.js +15 -0
  129. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  130. package/test/spec/modules/gptPreAuction_spec.js +177 -2
  131. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  132. package/test/spec/modules/improvedigitalBidAdapter_spec.js +45 -1
  133. package/test/spec/modules/invibesBidAdapter_spec.js +119 -0
  134. package/test/spec/modules/ixBidAdapter_spec.js +112 -62
  135. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +75 -17
  136. package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +22 -0
  137. package/test/spec/modules/livewrappedBidAdapter_spec.js +31 -0
  138. package/test/spec/modules/loglyliftBidAdapter_spec.js +172 -0
  139. package/test/spec/modules/lotamePanoramaIdSystem_spec.js +227 -0
  140. package/test/spec/modules/mediasquareBidAdapter_spec.js +4 -4
  141. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +26 -1
  142. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  143. package/test/spec/modules/optimeraRtdProvider_spec.js +14 -1
  144. package/test/spec/modules/ozoneBidAdapter_spec.js +43 -31
  145. package/test/spec/modules/prebidServerBidAdapter_spec.js +43 -0
  146. package/test/spec/modules/pubgeniusBidAdapter_spec.js +3 -3
  147. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  148. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +11 -0
  149. package/test/spec/modules/realTimeDataModule_spec.js +147 -48
  150. package/test/spec/modules/richaudienceBidAdapter_spec.js +42 -2
  151. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  152. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  153. package/test/spec/modules/rubiconBidAdapter_spec.js +65 -9
  154. package/test/spec/modules/sharedIdSystem_spec.js +52 -6
  155. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  156. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  157. package/test/spec/modules/targetVideoBidAdapter_spec.js +96 -0
  158. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  159. package/test/spec/modules/userId_spec.js +68 -19
  160. package/test/spec/modules/weboramaRtdProvider_spec.js +408 -214
  161. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  162. package/test/spec/modules/yahoosspBidAdapter_spec.js +28 -1
  163. package/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +427 -0
  164. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +33 -1
  165. package/test/spec/unit/core/targeting_spec.js +72 -0
  166. package/test/spec/unit/pbjs_api_spec.js +3 -1
  167. package/test/spec/utils_spec.js +38 -0
  168. package/test/test_deps.js +3 -0
  169. package/test/test_index.js +1 -3
@@ -165,16 +165,26 @@ function mapBanner(slot) {
165
165
  * @returns {object} Site by OpenRTB 2.5 §3.2.13
166
166
  */
167
167
  function mapSite(slot, bidderRequest) {
168
- const pubId = slot && slot.length > 0
169
- ? slot[0].params.publisherId
170
- : 'unknown';
171
- return {
168
+ let pubId = 'unknown';
169
+ let channel = null;
170
+ if (slot && slot.length > 0) {
171
+ pubId = slot[0].params.publisherId;
172
+ channel = slot[0].params.channel &&
173
+ slot[0].params.channel
174
+ .toString()
175
+ .slice(0, 50);
176
+ }
177
+ let siteData = {
172
178
  publisher: {
173
179
  id: pubId.toString(),
174
180
  },
175
181
  page: bidderRequest.refererInfo.referer,
176
182
  name: getOrigin()
183
+ };
184
+ if (channel) {
185
+ siteData.channel = channel;
177
186
  }
187
+ return siteData;
178
188
  }
179
189
 
180
190
  /**
@@ -98,6 +98,15 @@
98
98
  * @param {UserConsentData} userConsent
99
99
  */
100
100
 
101
+ /**
102
+ * @function?
103
+ * @summary on bid requested event
104
+ * @name RtdSubmodule#onBidRequestEvent
105
+ * @param {Object} data
106
+ * @param {SubmoduleConfig} config
107
+ * @param {UserConsentData} userConsent
108
+ */
109
+
101
110
  /**
102
111
  * @interface ModuleConfig
103
112
  */
@@ -143,7 +152,7 @@
143
152
 
144
153
  import {config} from '../../src/config.js';
145
154
  import {module} from '../../src/hook.js';
146
- import { logError, logWarn } from '../../src/utils.js';
155
+ import {logError, logWarn} from '../../src/utils.js';
147
156
  import events from '../../src/events.js';
148
157
  import CONSTANTS from '../../src/constants.json';
149
158
  import {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js';
@@ -164,13 +173,51 @@ let _dataProviders = [];
164
173
  let _userConsent;
165
174
 
166
175
  /**
167
- * enable submodule in User ID
176
+ * Register a RTD submodule.
177
+ *
168
178
  * @param {RtdSubmodule} submodule
179
+ * @returns {function()} a de-registration function that will unregister the module when called.
169
180
  */
170
181
  export function attachRealTimeDataProvider(submodule) {
171
182
  registeredSubModules.push(submodule);
183
+ return function detach() {
184
+ const idx = registeredSubModules.indexOf(submodule)
185
+ if (idx >= 0) {
186
+ registeredSubModules.splice(idx, 1);
187
+ initSubModules();
188
+ }
189
+ }
172
190
  }
173
191
 
192
+ /**
193
+ * call each sub module event function by config order
194
+ */
195
+ const setEventsListeners = (function () {
196
+ let registered = false;
197
+ return function setEventsListeners() {
198
+ if (!registered) {
199
+ Object.entries({
200
+ [CONSTANTS.EVENTS.AUCTION_INIT]: ['onAuctionInitEvent'],
201
+ [CONSTANTS.EVENTS.AUCTION_END]: ['onAuctionEndEvent', getAdUnitTargeting],
202
+ [CONSTANTS.EVENTS.BID_RESPONSE]: ['onBidResponseEvent'],
203
+ [CONSTANTS.EVENTS.BID_REQUESTED]: ['onBidRequestEvent']
204
+ }).forEach(([ev, [handler, preprocess]]) => {
205
+ events.on(ev, (args) => {
206
+ preprocess && preprocess(args);
207
+ subModules.forEach(sm => {
208
+ try {
209
+ sm[handler] && sm[handler](args, sm.config, _userConsent)
210
+ } catch (e) {
211
+ logError(`RTD provider '${sm.name}': error in '${handler}':`, e);
212
+ }
213
+ });
214
+ })
215
+ });
216
+ registered = true;
217
+ }
218
+ }
219
+ })();
220
+
174
221
  export function init(config) {
175
222
  const confListener = config.getConfig(MODULE_NAME, ({realTimeData}) => {
176
223
  if (!realTimeData.dataProviders) {
@@ -211,22 +258,6 @@ function initSubModules() {
211
258
  subModules = subModulesByOrder;
212
259
  }
213
260
 
214
- /**
215
- * call each sub module event function by config order
216
- */
217
- function setEventsListeners() {
218
- events.on(CONSTANTS.EVENTS.AUCTION_INIT, (args) => {
219
- subModules.forEach(sm => { sm.onAuctionInitEvent && sm.onAuctionInitEvent(args, sm.config, _userConsent) })
220
- });
221
- events.on(CONSTANTS.EVENTS.AUCTION_END, (args) => {
222
- getAdUnitTargeting(args);
223
- subModules.forEach(sm => { sm.onAuctionEndEvent && sm.onAuctionEndEvent(args, sm.config, _userConsent) })
224
- });
225
- events.on(CONSTANTS.EVENTS.BID_RESPONSE, (args) => {
226
- subModules.forEach(sm => { sm.onBidResponseEvent && sm.onBidResponseEvent(args, sm.config, _userConsent) })
227
- });
228
- }
229
-
230
261
  /**
231
262
  * loop through configured data providers If the data provider has registered getBidRequestData,
232
263
  * call it, providing reqBidsConfigObj, consent data and module params
@@ -1,4 +1,4 @@
1
- import { mergeDeep, _each, logError, deepAccess, deepSetValue, isStr, isNumber, logWarn, convertTypes, isArray, parseSizesInput, logMessage } from '../src/utils.js';
1
+ import { mergeDeep, _each, logError, deepAccess, deepSetValue, isStr, isNumber, logWarn, convertTypes, isArray, parseSizesInput, logMessage, formatQS } from '../src/utils.js';
2
2
  import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import {config} from '../src/config.js';
4
4
  import {BANNER, VIDEO} from '../src/mediaTypes.js';
@@ -765,21 +765,23 @@ export const spec = {
765
765
  getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
766
766
  if (!hasSynced && syncOptions.iframeEnabled) {
767
767
  // data is only assigned if params are available to pass to syncEndpoint
768
- let params = '';
768
+ let params = {};
769
769
 
770
- if (gdprConsent && typeof gdprConsent.consentString === 'string') {
771
- // add 'gdpr' only if 'gdprApplies' is defined
770
+ if (gdprConsent) {
772
771
  if (typeof gdprConsent.gdprApplies === 'boolean') {
773
- params += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`;
774
- } else {
775
- params += `?gdpr_consent=${gdprConsent.consentString}`;
772
+ params['gdpr'] = Number(gdprConsent.gdprApplies);
773
+ }
774
+ if (typeof gdprConsent.consentString === 'string') {
775
+ params['gdpr_consent'] = gdprConsent.consentString;
776
776
  }
777
777
  }
778
778
 
779
779
  if (uspConsent) {
780
- params += `${params ? '&' : '?'}us_privacy=${encodeURIComponent(uspConsent)}`;
780
+ params['us_privacy'] = encodeURIComponent(uspConsent);
781
781
  }
782
782
 
783
+ params = Object.keys(params).length ? `?${formatQS(params)}` : '';
784
+
783
785
  hasSynced = true;
784
786
  return {
785
787
  type: 'iframe',
@@ -992,6 +994,8 @@ function applyFPD(bidRequest, mediaType, data) {
992
994
 
993
995
  let fpd = mergeDeep({}, config.getConfig('ortb2') || {}, BID_FPD);
994
996
  let impData = deepAccess(bidRequest.ortb2Imp, 'ext.data') || {};
997
+
998
+ const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid');
995
999
  const SEGTAX = {user: [4], site: [1, 2, 5, 6]};
996
1000
  const MAP = {user: 'tg_v.', site: 'tg_i.', adserver: 'tg_i.dfp_ad_unit_code', pbadslot: 'tg_i.pbadslot', keywords: 'kw'};
997
1001
  const validate = function(prop, key, parentName) {
@@ -1020,16 +1024,6 @@ function applyFPD(bidRequest, mediaType, data) {
1020
1024
  data[loc] = (data[loc]) ? data[loc].concat(',', val) : val;
1021
1025
  }
1022
1026
 
1023
- Object.keys(impData).forEach((key) => {
1024
- if (key === 'adserver') {
1025
- ['name', 'adslot'].forEach(prop => {
1026
- if (impData[key][prop]) impData[key][prop] = impData[key][prop].toString().replace(/^\/+/, '');
1027
- });
1028
- } else if (key === 'pbadslot') {
1029
- impData[key] = impData[key].toString().replace(/^\/+/, '');
1030
- }
1031
- });
1032
-
1033
1027
  if (mediaType === BANNER) {
1034
1028
  ['site', 'user'].forEach(name => {
1035
1029
  Object.keys(fpd[name]).forEach((key) => {
@@ -1045,12 +1039,30 @@ function applyFPD(bidRequest, mediaType, data) {
1045
1039
  });
1046
1040
  });
1047
1041
  Object.keys(impData).forEach((key) => {
1048
- (key === 'adserver') ? addBannerData(impData[key].adslot, name, key) : addBannerData(impData[key], 'site', key);
1042
+ if (key !== 'adserver') {
1043
+ addBannerData(impData[key], 'site', key);
1044
+ } else if (impData[key].name === 'gam') {
1045
+ addBannerData(impData[key].adslot, name, key)
1046
+ }
1049
1047
  });
1048
+
1049
+ // add in gpid
1050
+ if (gpid) {
1051
+ data['p_gpid'] = gpid;
1052
+ }
1053
+
1054
+ // only send one of pbadslot or dfp adunit code (prefer pbadslot)
1055
+ if (data['tg_i.pbadslot']) {
1056
+ delete data['tg_i.dfp_ad_unit_code'];
1057
+ }
1050
1058
  } else {
1051
1059
  if (Object.keys(impData).length) {
1052
1060
  mergeDeep(data.imp[0].ext, {data: impData});
1053
1061
  }
1062
+ // add in gpid
1063
+ if (gpid) {
1064
+ data.imp[0].ext.gpid = gpid;
1065
+ }
1054
1066
 
1055
1067
  mergeDeep(data, fpd);
1056
1068
  }
@@ -11,7 +11,7 @@ import { coppaDataHandler } from '../src/adapterManager.js';
11
11
  import {getStorageManager} from '../src/storageManager.js';
12
12
 
13
13
  const GVLID = 887;
14
- const storage = getStorageManager(GVLID, 'pubCommonId');
14
+ export const storage = getStorageManager(GVLID, 'pubCommonId');
15
15
  const COOKIE = 'cookie';
16
16
  const LOCAL_STORAGE = 'html5';
17
17
  const OPTOUT_NAME = '_pubcid_optout';
@@ -171,7 +171,33 @@ export const sharedIdSystemSubmodule = {
171
171
  return {id: storedId};
172
172
  }
173
173
  }
174
+ },
175
+
176
+ domainOverride: function () {
177
+ const domainElements = document.domain.split('.');
178
+ const cookieName = `_gd${Date.now()}`;
179
+ for (let i = 0, topDomain, testCookie; i < domainElements.length; i++) {
180
+ const nextDomain = domainElements.slice(i).join('.');
181
+
182
+ // write test cookie
183
+ storage.setCookie(cookieName, '1', undefined, undefined, nextDomain);
184
+
185
+ // read test cookie to verify domain was valid
186
+ testCookie = storage.getCookie(cookieName);
187
+
188
+ // delete test cookie
189
+ storage.setCookie(cookieName, '', 'Thu, 01 Jan 1970 00:00:01 GMT', undefined, nextDomain);
190
+
191
+ if (testCookie === '1') {
192
+ // cookie was written successfully using test domain so the topDomain is updated
193
+ topDomain = nextDomain;
194
+ } else {
195
+ // cookie failed to write using test domain so exit by returning the topDomain
196
+ return topDomain;
197
+ }
198
+ }
174
199
  }
200
+
175
201
  };
176
202
 
177
203
  submodule('userId', sharedIdSystemSubmodule);
@@ -61,15 +61,24 @@ export const spec = {
61
61
  }
62
62
  }
63
63
 
64
+ const consentData = bidderRequest.gdprConsent || {};
65
+
66
+ const gdprConsent = {
67
+ apiVersion: consentData.apiVersion || 2,
68
+ gdprApplies: consentData.gdprApplies || 0,
69
+ consentString: consentData.consentString || '',
70
+ }
71
+
64
72
  return {
65
73
  type: streamType,
74
+ adUnitCode: bid.adUnitCode,
66
75
  bidId: bid.bidId,
67
76
  mediaType: type,
68
77
  context: context,
69
78
  playerId: getBidIdParameter('playerId', bid.params),
70
79
  auctionId: bidderRequest.auctionId,
71
80
  bidderCode: BIDDER_CODE,
72
- gdprConsent: bidderRequest.gdprConsent,
81
+ gdprConsent: gdprConsent,
73
82
  start: +new Date(),
74
83
  timeout: 3000,
75
84
  size: {
@@ -159,6 +168,7 @@ function createBids(bidRes, reqData) {
159
168
  let bidUnit = {};
160
169
  bidUnit.cpm = bid.cpm;
161
170
  bidUnit.requestId = bid.bidId;
171
+ bidUnit.adUnitCode = reqBid.adUnitCode;
162
172
  bidUnit.currency = bid.currency;
163
173
  bidUnit.mediaType = bid.mediaType || VIDEO;
164
174
  bidUnit.ttl = TTL;
@@ -183,7 +193,8 @@ function createBids(bidRes, reqData) {
183
193
  } else if (bid.context === 'outstream') {
184
194
  const renderer = Renderer.install({
185
195
  id: bid.bidId,
186
- url: '//',
196
+ url: 'https://static.showheroes.com/renderer.js',
197
+ adUnitCode: reqBid.adUnitCode,
187
198
  config: {
188
199
  playerId: reqBid.playerId,
189
200
  width: bid.size.width,
@@ -53,7 +53,14 @@ export const spec = {
53
53
  * @return boolean True if this is a valid bid, and false otherwise.
54
54
  */
55
55
  isBidRequestValid: function(bid) {
56
- return validBasic(bid) && validMediaType(bid)
56
+ // bid.params.host
57
+ if ((new RegExp(`^(vz.*|zz.*)\\.*$`, 'i')).test(bid.params.host)) { // New endpoint
58
+ if ((new RegExp(`^(zz.*)\\.*$`, 'i')).test(bid.params.host)) return validBasic(bid)
59
+ else return validBasic(bid) && validMediaType(bid)
60
+ } else { // This is backward compatible feature. It will be remove in the future
61
+ if ((new RegExp(`^(ZZ.*)\\.*$`, 'i')).test(bid.params.endpoint)) return validBasic(bid)
62
+ else return validBasic(bid) && validMediaType(bid)
63
+ }
57
64
  },
58
65
 
59
66
  /**
@@ -169,10 +176,6 @@ function validMediaType(bid) {
169
176
  logWarn(LOG_PREFIX, 'Please review the mandatory Tappx parameters for Video. Video context not supported.');
170
177
  return false;
171
178
  }
172
- if (typeof video.mimes == 'undefined') {
173
- logWarn(LOG_PREFIX, 'Please review the mandatory Tappx parameters for Video. Mimes param is mandatory.');
174
- return false;
175
- }
176
179
  }
177
180
 
178
181
  return true;
@@ -0,0 +1,187 @@
1
+ import find from 'core-js-pure/features/array/find.js';
2
+ import { getBidRequest } from '../src/utils.js';
3
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
4
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
5
+
6
+ const SOURCE = 'pbjs';
7
+ const BIDDER_CODE = 'targetVideo';
8
+ const ENDPOINT_URL = 'https://ib.adnxs.com/ut/v3/prebid';
9
+ const MARGIN = 1.35;
10
+
11
+ export const spec = {
12
+
13
+ code: BIDDER_CODE,
14
+ supportedMediaTypes: [BANNER],
15
+
16
+ /**
17
+ * Determines whether or not the given bid request is valid.
18
+ *
19
+ * @param {object} bid The bid to validate.
20
+ * @return boolean True if this is a valid bid, and false otherwise.
21
+ */
22
+ isBidRequestValid: function(bid) {
23
+ return !!(bid && bid.params && bid.params.placementId);
24
+ },
25
+
26
+ /**
27
+ * Make a server request from the list of BidRequests.
28
+ *
29
+ * @param {BidRequest[]} bidRequests A non-empty list of bid requests which should be sent to the Server.
30
+ * @return ServerRequest Info describing the request to the server.
31
+ */
32
+ buildRequests: function(bidRequests, bidderRequest) {
33
+ const tags = bidRequests.map(createVideoTag);
34
+ const schain = bidRequests[0].schain;
35
+ const payload = {
36
+ tags: tags,
37
+ sdk: {
38
+ source: SOURCE,
39
+ version: '$prebid.version$'
40
+ },
41
+ schain: schain
42
+ };
43
+ return formatRequest(payload, bidderRequest);
44
+ },
45
+
46
+ /**
47
+ * Unpack the response from the server into a list of bids.
48
+ *
49
+ * @param {*} serverResponse A successful response from the server.
50
+ * @return {Bid[]} An array of bids which were nested inside the server.
51
+ */
52
+ interpretResponse: function(serverResponse, { bidderRequest }) {
53
+ serverResponse = serverResponse.body;
54
+ const bids = [];
55
+
56
+ if (serverResponse.tags) {
57
+ serverResponse.tags.forEach(serverBid => {
58
+ const rtbBid = getRtbBid(serverBid);
59
+ if (rtbBid && rtbBid.cpm !== 0 && rtbBid.ad_type == VIDEO) {
60
+ bids.push(newBid(serverBid, rtbBid, bidderRequest));
61
+ }
62
+ });
63
+ }
64
+
65
+ return bids;
66
+ }
67
+
68
+ }
69
+
70
+ function getSizes(request) {
71
+ let sizes = request.sizes;
72
+ if (!sizes && request.mediaTypes && request.mediaTypes.banner && request.mediaTypes.banner.sizes) {
73
+ sizes = request.mediaTypes.banner.sizes;
74
+ }
75
+ if (Array.isArray(sizes) && !Array.isArray(sizes[0])) {
76
+ sizes = [sizes[0], sizes[1]];
77
+ }
78
+ if (!Array.isArray(sizes) || !Array.isArray(sizes[0])) {
79
+ sizes = [[0, 0]];
80
+ }
81
+
82
+ return sizes;
83
+ }
84
+
85
+ function formatRequest(payload, bidderRequest) {
86
+ const options = {
87
+ withCredentials: true
88
+ };
89
+ const request = {
90
+ method: 'POST',
91
+ url: ENDPOINT_URL,
92
+ data: JSON.stringify(payload),
93
+ bidderRequest,
94
+ options
95
+ };
96
+
97
+ return request;
98
+ }
99
+
100
+ /**
101
+ * Create video auction.
102
+ *
103
+ * @param {*} serverResponse A successful response from the server.
104
+ * @return {Bid[]} An array of bids which were nested inside the server.
105
+ */
106
+ function createVideoTag(bid) {
107
+ const tag = {};
108
+ tag.id = parseInt(bid.params.placementId, 10);
109
+ tag.gpid = 'targetVideo';
110
+ tag.sizes = getSizes(bid);
111
+ tag.primary_size = tag.sizes[0];
112
+ tag.ad_types = [VIDEO];
113
+ tag.uuid = bid.bidId;
114
+ tag.allow_smaller_sizes = false;
115
+ tag.use_pmt_rule = false
116
+ tag.prebid = true;
117
+ tag.disable_psa = true;
118
+ tag.hb_source = 1;
119
+ tag.require_asset_url = true;
120
+ tag.video = {
121
+ playback_method: 2,
122
+ skippable: true
123
+ };
124
+
125
+ return tag;
126
+ }
127
+
128
+ /**
129
+ * Unpack the Server's Bid into a Prebid-compatible one.
130
+ * @param serverBid
131
+ * @param rtbBid
132
+ * @param bidderRequest
133
+ * @return Bid
134
+ */
135
+ function newBid(serverBid, rtbBid, bidderRequest) {
136
+ const bidRequest = getBidRequest(serverBid.uuid, [bidderRequest]);
137
+ const sizes = getSizes(bidRequest);
138
+ const bid = {
139
+ requestId: serverBid.uuid,
140
+ cpm: rtbBid.cpm * MARGIN,
141
+ creativeId: rtbBid.creative_id,
142
+ dealId: rtbBid.deal_id,
143
+ currency: 'USD',
144
+ netRevenue: true,
145
+ width: sizes[0][0],
146
+ height: sizes[0][1],
147
+ ttl: 300,
148
+ adUnitCode: bidRequest.adUnitCode,
149
+ appnexus: {
150
+ buyerMemberId: rtbBid.buyer_member_id,
151
+ dealPriority: rtbBid.deal_priority,
152
+ dealCode: rtbBid.deal_code
153
+ }
154
+ };
155
+
156
+ if (rtbBid.rtb.video) {
157
+ Object.assign(bid, {
158
+ vastImpUrl: rtbBid.notify_url,
159
+ ad: getBannerHtml(rtbBid.notify_url + '&redir=' + encodeURIComponent(rtbBid.rtb.video.asset_url)),
160
+ ttl: 3600
161
+ });
162
+ }
163
+
164
+ return bid;
165
+ }
166
+
167
+ function getRtbBid(tag) {
168
+ return tag && tag.ads && tag.ads.length && find(tag.ads, ad => ad.rtb);
169
+ }
170
+
171
+ function getBannerHtml(vastUrl) {
172
+ return `<!DOCTYPE html>
173
+ <html lang="en">
174
+ <head>
175
+ <meta charset="UTF-8">
176
+ <title></title>
177
+ <style>html, body {width: 100%; height: 100%; margin: 0;}</style>
178
+ </head>
179
+ <body>
180
+ <div id="targetVideoPlayer"></div>
181
+ <script src="https://player.target-video.com/custom/targetvideo-banner.js"></script>
182
+ <script>initPlayer("${vastUrl}");</script>
183
+ </body>
184
+ </html>`;
185
+ }
186
+
187
+ registerBidder(spec);
@@ -0,0 +1,34 @@
1
+ # Overview
2
+
3
+ ```
4
+ Module Name: Target Video Bid Adapter
5
+ Module Type: Bidder Adapter
6
+ Maintainer: grajzer@gmail.com
7
+ ```
8
+
9
+ # Description
10
+
11
+ Connects to Appnexus exchange for bids.
12
+
13
+ TargetVideo bid adapter supports Banner.
14
+
15
+ # Test Parameters
16
+ ```
17
+ var adUnits = [
18
+ // Banner adUnit
19
+ {
20
+ code: 'banner-div',
21
+ mediaTypes: {
22
+ banner: {
23
+ sizes: [[640, 480], [300, 250]],
24
+ }
25
+ },
26
+ bids: [{
27
+ bidder: 'targetVideo',
28
+ params: {
29
+ placementId: 13232361
30
+ }
31
+ }]
32
+ }
33
+ ];
34
+ ```
@@ -190,8 +190,7 @@ function buildRequestObject(bid) {
190
190
  const reqObj = {};
191
191
  let placementId = getValue(bid.params, 'placementId');
192
192
  let pageId = getValue(bid.params, 'pageId');
193
- const impressionData = deepAccess(bid, 'ortb2Imp.ext.data');
194
- const gpid = deepAccess(impressionData, 'pbadslot') || deepAccess(impressionData, 'adserver.adslot');
193
+ const gpid = deepAccess(bid, 'ortb2Imp.ext.gpid');
195
194
 
196
195
  reqObj.sizes = getSizes(bid);
197
196
  reqObj.bidId = getBidIdParameter('bidId', bid);
@@ -2,7 +2,7 @@ import { logError, isEmpty, deepAccess, triggerPixel, logWarn, isArray } from '.
2
2
  import {createBid as createBidFactory} from '../src/bidfactory.js';
3
3
  import {registerBidder} from '../src/adapters/bidderFactory.js';
4
4
  import {VIDEO} from '../src/mediaTypes.js';
5
- import {STATUS} from '../src/constants.json';
5
+ import CONSTANTS from '../src/constants.json';
6
6
 
7
7
  const BIDDER_CODE = 'telaria';
8
8
  const DOMAIN = 'tremorhub.com';
@@ -86,7 +86,7 @@ export const spec = {
86
86
  logError(errorMessage);
87
87
  } else if (!isEmpty(bidResult.seatbid)) {
88
88
  bidResult.seatbid[0].bid.forEach(tag => {
89
- bids.push(createBid(STATUS.GOOD, bidderRequest, tag, width, height, BIDDER_CODE));
89
+ bids.push(createBid(CONSTANTS.STATUS.GOOD, bidderRequest, tag, width, height, BIDDER_CODE));
90
90
  });
91
91
  }
92
92
 
@@ -6,9 +6,8 @@ import { config } from '../src/config.js';
6
6
 
7
7
  const BIDDER_CODE = 'trustx';
8
8
  const ENDPOINT_URL = 'https://grid.bidswitch.net/hbjson?sp=trustx';
9
- const ADDITIONAL_SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid';
10
9
  const TIME_TO_LIVE = 360;
11
- const ADAPTER_SYNC_URL = 'https://sofia.trustx.org/push_sync';
10
+ const ADAPTER_SYNC_URL = 'https://x.bidswitch.net/sync?ssp=themediagrid';
12
11
  const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js';
13
12
 
14
13
  const LOG_ERROR_MESS = {
@@ -281,12 +280,12 @@ export const spec = {
281
280
  },
282
281
  getUserSyncs: function(syncOptions, responses, gdprConsent, uspConsent) {
283
282
  if (syncOptions.pixelEnabled) {
284
- const syncsPerBidder = config.getConfig('userSync.syncsPerBidder');
285
283
  let params = [];
286
- if (gdprConsent && typeof gdprConsent.consentString === 'string') {
284
+ if (gdprConsent) {
287
285
  if (typeof gdprConsent.gdprApplies === 'boolean') {
288
- params.push(`gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`);
289
- } else {
286
+ params.push(`gdpr=${Number(gdprConsent.gdprApplies)}`);
287
+ }
288
+ if (typeof gdprConsent.consentString === 'string') {
290
289
  params.push(`gdpr_consent=${gdprConsent.consentString}`);
291
290
  }
292
291
  }
@@ -294,17 +293,10 @@ export const spec = {
294
293
  params.push(`us_privacy=${uspConsent}`);
295
294
  }
296
295
  const stringParams = params.join('&');
297
- const syncs = [{
296
+ return {
298
297
  type: 'image',
299
- url: ADAPTER_SYNC_URL + (stringParams ? `?${stringParams}` : '')
300
- }];
301
- if (syncsPerBidder > 1) {
302
- syncs.push({
303
- type: 'image',
304
- url: ADDITIONAL_SYNC_URL + (stringParams ? `&${stringParams}` : '')
305
- });
306
- }
307
- return syncs;
298
+ url: ADAPTER_SYNC_URL + stringParams
299
+ };
308
300
  }
309
301
  }
310
302
  }
@@ -257,7 +257,13 @@ const USER_IDS_CONFIG = {
257
257
  'connectId': {
258
258
  source: 'yahoo.com',
259
259
  atype: 3
260
- }
260
+ },
261
+
262
+ // Adquery ID
263
+ 'qid': {
264
+ source: 'adquery.io',
265
+ atype: 1
266
+ },
261
267
  };
262
268
 
263
269
  // this function will create an eid object for the given UserId sub-module
@@ -297,6 +297,14 @@ pbjs.setConfig({
297
297
  type: 'html5',
298
298
  expires: 15
299
299
  }
300
+ }
301
+ {
302
+ name: "qid",
303
+ storage: {
304
+ type: "html5",
305
+ name: "qid",
306
+ expires: 365
307
+ }
300
308
  }],
301
309
  syncDelay: 5000
302
310
  }