prebid.js 7.29.0 → 7.31.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 (173) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/adkernelBidAdapter.js +1 -1
  7. package/dist/adrelevantisBidAdapter.js +1 -1
  8. package/dist/adtrgtmeBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/ajaBidAdapter.js +1 -1
  11. package/dist/amxBidAdapter.js +1 -1
  12. package/dist/amxIdSystem.js +1 -1
  13. package/dist/appierAnalyticsAdapter.js +1 -1
  14. package/dist/appnexusBidAdapter.js +1 -1
  15. package/dist/asoBidAdapter.js +1 -1
  16. package/dist/axonixBidAdapter.js +1 -1
  17. package/dist/bidViewability.js +1 -1
  18. package/dist/bidglassBidAdapter.js +1 -1
  19. package/dist/big-richmediaBidAdapter.js +1 -1
  20. package/dist/bridgewellBidAdapter.js +1 -1
  21. package/dist/brightMountainMediaBidAdapter.js +1 -1
  22. package/dist/byDataAnalyticsAdapter.js +1 -1
  23. package/dist/carodaBidAdapter.js +1 -1
  24. package/dist/ccxBidAdapter.js +1 -1
  25. package/dist/chtnwBidAdapter.js +1 -1
  26. package/dist/colossussspBidAdapter.js +1 -1
  27. package/dist/concertBidAdapter.js +1 -1
  28. package/dist/confiantRtdProvider.js +1 -0
  29. package/dist/connectadBidAdapter.js +1 -1
  30. package/dist/consentManagement.js +1 -1
  31. package/dist/consentManagementGpp.js +1 -0
  32. package/dist/consumableBidAdapter.js +1 -1
  33. package/dist/conversantBidAdapter.js +1 -1
  34. package/dist/craftBidAdapter.js +1 -1
  35. package/dist/criteoBidAdapter.js +1 -1
  36. package/dist/datawrkzBidAdapter.js +1 -1
  37. package/dist/dfpAdServerVideo.js +1 -1
  38. package/dist/dspxBidAdapter.js +1 -1
  39. package/dist/eplanningBidAdapter.js +1 -1
  40. package/dist/feedadBidAdapter.js +1 -1
  41. package/dist/finativeBidAdapter.js +1 -1
  42. package/dist/glimpseBidAdapter.js +1 -1
  43. package/dist/gmosspBidAdapter.js +1 -1
  44. package/dist/goldbachBidAdapter.js +1 -1
  45. package/dist/gridBidAdapter.js +1 -1
  46. package/dist/gridNMBidAdapter.js +1 -1
  47. package/dist/gumgumBidAdapter.js +1 -1
  48. package/dist/h12mediaBidAdapter.js +1 -1
  49. package/dist/id5IdSystem.js +1 -1
  50. package/dist/improvedigitalBidAdapter.js +1 -1
  51. package/dist/inmarBidAdapter.js +1 -1
  52. package/dist/insticatorBidAdapter.js +1 -1
  53. package/dist/ixBidAdapter.js +1 -1
  54. package/dist/justpremiumBidAdapter.js +1 -1
  55. package/dist/konduitAnalyticsAdapter.js +1 -1
  56. package/dist/kueezBidAdapter.js +1 -1
  57. package/dist/kueezRtbBidAdapter.js +1 -1
  58. package/dist/lassoBidAdapter.js +1 -1
  59. package/dist/lifestreetBidAdapter.js +1 -1
  60. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  61. package/dist/logicadBidAdapter.js +1 -1
  62. package/dist/loglyliftBidAdapter.js +1 -1
  63. package/dist/magniteAnalyticsAdapter.js +1 -1
  64. package/dist/malltvAnalyticsAdapter.js +1 -1
  65. package/dist/marsmediaBidAdapter.js +1 -1
  66. package/dist/mediafuseBidAdapter.js +1 -1
  67. package/dist/mediasquareBidAdapter.js +1 -1
  68. package/dist/mgidBidAdapter.js +1 -1
  69. package/dist/minutemediaBidAdapter.js +1 -1
  70. package/dist/nexx360BidAdapter.js +1 -1
  71. package/dist/not-for-prod/prebid.js +127 -124
  72. package/dist/oguryBidAdapter.js +1 -1
  73. package/dist/onetagBidAdapter.js +1 -1
  74. package/dist/ooloAnalyticsAdapter.js +1 -1
  75. package/dist/outbrainBidAdapter.js +1 -1
  76. package/dist/parrableIdSystem.js +1 -1
  77. package/dist/pbsExtensions.js +1 -1
  78. package/dist/pixfutureBidAdapter.js +1 -1
  79. package/dist/prebid-core.js +1 -1
  80. package/dist/prebidServerBidAdapter.js +1 -1
  81. package/dist/publinkIdSystem.js +1 -1
  82. package/dist/pubmaticBidAdapter.js +1 -1
  83. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  84. package/dist/pxyzBidAdapter.js +1 -1
  85. package/dist/quantcastBidAdapter.js +1 -1
  86. package/dist/readpeakBidAdapter.js +1 -1
  87. package/dist/relaidoBidAdapter.js +1 -1
  88. package/dist/rhythmoneBidAdapter.js +1 -1
  89. package/dist/riseBidAdapter.js +1 -1
  90. package/dist/rtdModule.js +1 -1
  91. package/dist/rubiconAnalyticsAdapter.js +1 -1
  92. package/dist/rubiconBidAdapter.js +1 -1
  93. package/dist/seedingAllianceBidAdapter.js +1 -1
  94. package/dist/seedtagBidAdapter.js +1 -1
  95. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  96. package/dist/sharethroughBidAdapter.js +1 -1
  97. package/dist/shinezBidAdapter.js +1 -1
  98. package/dist/smaatoBidAdapter.js +1 -1
  99. package/dist/smartadserverBidAdapter.js +1 -1
  100. package/dist/smartxBidAdapter.js +1 -1
  101. package/dist/smilewantedBidAdapter.js +1 -1
  102. package/dist/sonobiBidAdapter.js +1 -1
  103. package/dist/sovrnAnalyticsAdapter.js +1 -1
  104. package/dist/sovrnBidAdapter.js +1 -1
  105. package/dist/sspBCBidAdapter.js +1 -1
  106. package/dist/sublimeBidAdapter.js +1 -1
  107. package/dist/synacormediaBidAdapter.js +1 -1
  108. package/dist/targetVideoBidAdapter.js +1 -1
  109. package/dist/teadsBidAdapter.js +1 -1
  110. package/dist/trionBidAdapter.js +1 -1
  111. package/dist/tripleliftBidAdapter.js +1 -1
  112. package/dist/ttdBidAdapter.js +1 -1
  113. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  114. package/dist/uid2IdSystem.js +1 -1
  115. package/dist/underdogmediaBidAdapter.js +1 -1
  116. package/dist/undertoneBidAdapter.js +1 -1
  117. package/dist/vidazooBidAdapter.js +1 -1
  118. package/dist/videobyteBidAdapter.js +1 -1
  119. package/dist/viouslyBidAdapter.js +1 -0
  120. package/dist/visxBidAdapter.js +1 -1
  121. package/dist/vuukleBidAdapter.js +1 -1
  122. package/dist/widespaceBidAdapter.js +1 -1
  123. package/dist/winrBidAdapter.js +1 -1
  124. package/dist/yahoosspBidAdapter.js +1 -1
  125. package/dist/yieldmoBidAdapter.js +1 -1
  126. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  127. package/integrationExamples/gpt/gpp_us_hello_world.html +124 -0
  128. package/integrationExamples/gpt/gpp_us_hello_world_iframe.html +12 -0
  129. package/integrationExamples/gpt/gpp_us_hello_world_iframe_subpage.html +140 -0
  130. package/karma.conf.maker.js +1 -1
  131. package/libraries/pbsExtensions/processors/adUnitCode.js +13 -0
  132. package/libraries/pbsExtensions/processors/pbs.js +5 -0
  133. package/modules/.submodules.json +1 -0
  134. package/modules/adkernelBidAdapter.js +2 -1
  135. package/modules/appnexusBidAdapter.js +23 -2
  136. package/modules/bidViewability.js +6 -1
  137. package/modules/ccxBidAdapter.js +3 -2
  138. package/modules/colossussspBidAdapter.js +8 -0
  139. package/modules/confiantRtdProvider.js +128 -0
  140. package/modules/confiantRtdProvider.md +45 -0
  141. package/modules/consentManagement.js +4 -4
  142. package/modules/consentManagementGpp.js +386 -0
  143. package/modules/datawrkzBidAdapter.js +24 -4
  144. package/modules/dfpAdServerVideo.js +6 -1
  145. package/modules/feedadBidAdapter.js +11 -3
  146. package/modules/gridBidAdapter.js +1 -2
  147. package/modules/lassoBidAdapter.js +2 -2
  148. package/modules/magniteAnalyticsAdapter.js +9 -1
  149. package/modules/onetagBidAdapter.js +20 -29
  150. package/modules/prebidServerBidAdapter/index.js +19 -8
  151. package/modules/prebidServerBidAdapter/ortbConverter.js +1 -0
  152. package/modules/rtdModule/index.js +2 -1
  153. package/modules/viouslyBidAdapter.js +209 -0
  154. package/modules/viouslyBidAdapter.md +35 -0
  155. package/package.json +1 -1
  156. package/src/adapterManager.js +11 -10
  157. package/src/adapters/bidderFactory.js +5 -5
  158. package/src/adloader.js +2 -1
  159. package/src/consentHandler.js +11 -0
  160. package/src/prebid.js +9 -9
  161. package/test/helpers/hookSetup.js +5 -0
  162. package/test/spec/modules/ViouslyBidAdapter_spec.js +378 -0
  163. package/test/spec/modules/appnexusBidAdapter_spec.js +46 -0
  164. package/test/spec/modules/colossussspBidAdapter_spec.js +89 -2
  165. package/test/spec/modules/confiantRtdProvider_spec.js +107 -0
  166. package/test/spec/modules/consentManagementGpp_spec.js +577 -0
  167. package/test/spec/modules/feedadBidAdapter_spec.js +38 -13
  168. package/test/spec/modules/gridBidAdapter_spec.js +0 -18
  169. package/test/spec/modules/magniteAnalyticsAdapter_spec.js +36 -14
  170. package/test/spec/modules/onetagBidAdapter_spec.js +29 -23
  171. package/test/spec/modules/topicsFpdModule_spec.js +41 -22
  172. package/test/spec/ortbConverter/pbsExtensions/adUnitCode_spec.js +23 -0
  173. package/test/spec/unit/pbjs_api_spec.js +11 -0
@@ -8,7 +8,7 @@ import { deepAccess, isEmpty, logError, parseSizesInput, formatQS, parseUrl, bui
8
8
  import { config } from '../src/config.js';
9
9
  import { getHook, submodule } from '../src/hook.js';
10
10
  import { auctionManager } from '../src/auctionManager.js';
11
- import { gdprDataHandler, uspDataHandler } from '../src/adapterManager.js';
11
+ import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js';
12
12
  import * as events from '../src/events.js';
13
13
  import CONSTANTS from '../src/constants.json';
14
14
  import {getPPID} from '../src/adserver.js';
@@ -119,6 +119,11 @@ export function buildDfpVideoUrl(options) {
119
119
  const uspConsent = uspDataHandler.getConsentData();
120
120
  if (uspConsent) { queryParams.us_privacy = uspConsent; }
121
121
 
122
+ const gppConsent = gppDataHandler.getConsentData();
123
+ if (gppConsent) {
124
+ // TODO - need to know what to set here for queryParams...
125
+ }
126
+
122
127
  if (!queryParams.ppid) {
123
128
  const ppid = getPPID();
124
129
  if (ppid != null) {
@@ -7,7 +7,7 @@ import {ajax} from '../src/ajax.js';
7
7
  * Version of the FeedAd bid adapter
8
8
  * @type {string}
9
9
  */
10
- const VERSION = '1.0.3';
10
+ const VERSION = '1.0.4';
11
11
 
12
12
  /**
13
13
  * @typedef {object} FeedAdApiBidRequest
@@ -294,12 +294,20 @@ function trackingHandlerFactory(klass) {
294
294
  /**
295
295
  * Reads the user syncs off the server responses and converts them into Prebid.JS format
296
296
  * @param {SyncOptions} syncOptions
297
- * @param {FeedAdApiBidResponse[]} serverResponses
297
+ * @param {ServerResponse[]} serverResponses
298
298
  * @param gdprConsent
299
299
  * @param uspConsent
300
300
  */
301
301
  function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
302
- return serverResponses.map(response => response.ext)
302
+ return serverResponses.map(response => {
303
+ // validate response format
304
+ const ext = deepAccess(response, 'body.ext', []);
305
+ if (ext == null) {
306
+ return null;
307
+ }
308
+ return ext;
309
+ })
310
+ .filter(ext => ext != null)
303
311
  .flatMap(extension => {
304
312
  // extract user syncs from extension
305
313
  const pixels = syncOptions.pixelEnabled && extension.pixels ? extension.pixels : [];
@@ -94,8 +94,7 @@ export const spec = {
94
94
  let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo} = bidderRequest || {};
95
95
 
96
96
  const referer = refererInfo ? encodeURIComponent(refererInfo.page) : '';
97
- const bidderTimeout = config.getConfig('bidderTimeout') || timeout;
98
- const tmax = timeout ? Math.min(bidderTimeout, timeout) : bidderTimeout;
97
+ const tmax = timeout || config.getConfig('bidderTimeout');
99
98
  const imp = [];
100
99
  const bidsMap = {};
101
100
  const requests = [];
@@ -40,14 +40,14 @@ export const spec = {
40
40
  auctionId: bidRequest.auctionId,
41
41
  bidId: bidRequest.bidId,
42
42
  transactionId: bidRequest.transactionId,
43
- device: JSON.stringify(getDeviceData()),
43
+ device: encodeURIComponent(JSON.stringify(getDeviceData())),
44
44
  sizes,
45
45
  aimXR,
46
46
  uid: '$UID',
47
47
  params: JSON.stringify(bidRequest.params),
48
48
  crumbs: JSON.stringify(bidRequest.crumbs),
49
49
  prebidVersion: '$prebid.version$',
50
- version: 2,
50
+ version: 3,
51
51
  coppa: config.getConfig('coppa') == true ? 1 : 0,
52
52
  ccpa: bidderRequest.uspConsent || undefined
53
53
  }
@@ -643,7 +643,15 @@ magniteAdapter.disableAnalytics = function () {
643
643
  accountId = undefined;
644
644
  resetConfs();
645
645
  magniteAdapter.originDisableAnalytics();
646
- }
646
+ };
647
+
648
+ magniteAdapter.onDataDeletionRequest = function () {
649
+ if (storage.localStorageIsEnabled()) {
650
+ storage.removeDataFromLocalStorage(COOKIE_NAME);
651
+ } else {
652
+ throw Error('Unable to access local storage, no data deleted');
653
+ }
654
+ };
647
655
 
648
656
  magniteAdapter.MODULE_INITIALIZED_TIME = Date.now();
649
657
  magniteAdapter.referrerHostname = '';
@@ -3,7 +3,7 @@
3
3
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
4
4
  import { INSTREAM, OUTSTREAM } from '../src/video.js';
5
5
  import { Renderer } from '../src/Renderer.js';
6
- import {find} from '../src/polyfill.js';
6
+ import { find } from '../src/polyfill.js';
7
7
  import { getStorageManager } from '../src/storageManager.js';
8
8
  import { registerBidder } from '../src/adapters/bidderFactory.js';
9
9
  import { deepClone, logError, deepAccess } from '../src/utils.js';
@@ -13,7 +13,7 @@ const USER_SYNC_ENDPOINT = 'https://onetag-sys.com/usync/';
13
13
  const BIDDER_CODE = 'onetag';
14
14
  const GVLID = 241;
15
15
 
16
- const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE});
16
+ const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE });
17
17
 
18
18
  /**
19
19
  * Determines whether or not the given bid request is valid.
@@ -53,7 +53,7 @@ export function isValid(type, bid) {
53
53
  function buildRequests(validBidRequests, bidderRequest) {
54
54
  const payload = {
55
55
  bids: requestsToBids(validBidRequests),
56
- ...getPageInfo()
56
+ ...getPageInfo(bidderRequest)
57
57
  };
58
58
  if (bidderRequest && bidderRequest.gdprConsent) {
59
59
  payload.gdprConsent = {
@@ -74,7 +74,10 @@ function buildRequests(validBidRequests, bidderRequest) {
74
74
  if (storage.hasLocalStorage()) {
75
75
  payload.onetagSid = storage.getDataFromLocalStorage('onetag_sid');
76
76
  }
77
- } catch (e) {}
77
+ } catch (e) { }
78
+ const connection = navigator.connection || navigator.webkitConnection;
79
+ payload.networkConnectionType = (connection && connection.type) ? connection.type : null;
80
+ payload.networkEffectiveConnectionType = (connection && connection.effectiveType) ? connection.effectiveType : null;
78
81
  return {
79
82
  method: 'POST',
80
83
  url: ENDPOINT,
@@ -112,7 +115,7 @@ function interpretResponse(serverResponse, bidderRequest) {
112
115
  if (bid.mediaType === BANNER) {
113
116
  responseBid.ad = bid.ad;
114
117
  } else if (bid.mediaType === VIDEO) {
115
- const {context, adUnitCode} = find(requestData.bids, (item) =>
118
+ const { context, adUnitCode } = find(requestData.bids, (item) =>
116
119
  item.bidId === bid.requestId &&
117
120
  item.type === VIDEO
118
121
  );
@@ -141,7 +144,7 @@ function createRenderer(bid, rendererOptions = {}) {
141
144
  loaded: false
142
145
  });
143
146
  try {
144
- renderer.setRender(({renderer, width, height, vastXml, adUnitCode}) => {
147
+ renderer.setRender(({ renderer, width, height, vastXml, adUnitCode }) => {
145
148
  renderer.push(() => {
146
149
  window.onetag.Player.init({
147
150
  ...bid,
@@ -162,7 +165,6 @@ function createRenderer(bid, rendererOptions = {}) {
162
165
  function getFrameNesting() {
163
166
  let topmostFrame = window;
164
167
  let parent = window.parent;
165
- let currentFrameNesting = 0;
166
168
  try {
167
169
  while (topmostFrame !== topmostFrame.parent) {
168
170
  parent = topmostFrame.parent;
@@ -170,13 +172,8 @@ function getFrameNesting() {
170
172
  parent.location.href;
171
173
  topmostFrame = topmostFrame.parent;
172
174
  }
173
- } catch (e) {
174
- currentFrameNesting = parent === topmostFrame.top ? 1 : 2;
175
- }
176
- return {
177
- topmostFrame,
178
- currentFrameNesting
179
- }
175
+ } catch (e) { }
176
+ return topmostFrame;
180
177
  }
181
178
 
182
179
  function getDocumentVisibility(window) {
@@ -197,21 +194,15 @@ function getDocumentVisibility(window) {
197
194
 
198
195
  /**
199
196
  * Returns information about the page needed by the server in an object to be converted in JSON
200
- * @returns {{location: *, referrer: (*|string), masked: *, wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}}
197
+ * @returns {{location: *, referrer: (*|string), stack: (*|Array.<String>), numIframes: (*|Number), wWidth: (*|Number), wHeight: (*|Number), sWidth, sHeight, date: string, timeOffset: number}}
201
198
  */
202
- function getPageInfo() {
203
- const { topmostFrame, currentFrameNesting } = getFrameNesting();
199
+ function getPageInfo(bidderRequest) {
200
+ const topmostFrame = getFrameNesting();
204
201
  return {
205
- location: topmostFrame.location.href,
206
- referrer:
207
- topmostFrame.document.referrer !== ''
208
- ? topmostFrame.document.referrer
209
- : null,
210
- ancestorOrigin:
211
- window.location.ancestorOrigins && window.location.ancestorOrigins.length > 0
212
- ? window.location.ancestorOrigins[window.location.ancestorOrigins.length - 1]
213
- : null,
214
- masked: currentFrameNesting,
202
+ location: deepAccess(bidderRequest, 'refererInfo.page', null),
203
+ referrer: deepAccess(bidderRequest, 'refererInfo.ref', null),
204
+ stack: deepAccess(bidderRequest, 'refererInfo.stack', []),
205
+ numIframes: deepAccess(bidderRequest, 'refererInfo.numIframes', 0),
215
206
  wWidth: topmostFrame.innerWidth,
216
207
  wHeight: topmostFrame.innerHeight,
217
208
  oWidth: topmostFrame.outerWidth,
@@ -230,7 +221,7 @@ function getPageInfo() {
230
221
  timing: getTiming(),
231
222
  version: {
232
223
  prebid: '$prebid.version$',
233
- adapter: '1.1.0'
224
+ adapter: '1.1.1'
234
225
  }
235
226
  };
236
227
  }
@@ -344,7 +335,7 @@ function getSizes(sizes) {
344
335
  const ret = [];
345
336
  for (let i = 0; i < sizes.length; i++) {
346
337
  const size = sizes[i];
347
- ret.push({width: size[0], height: size[1]})
338
+ ret.push({ width: size[0], height: size[1] })
348
339
  }
349
340
  return ret;
350
341
  }
@@ -216,7 +216,7 @@ export function resetSyncedStatus() {
216
216
  /**
217
217
  * @param {Array} bidderCodes list of bidders to request user syncs for.
218
218
  */
219
- function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) {
219
+ function queueSync(bidderCodes, gdprConsent, uspConsent, gppConsent, s2sConfig) {
220
220
  if (_s2sConfigs.length === _syncCount) {
221
221
  return;
222
222
  }
@@ -246,6 +246,15 @@ function queueSync(bidderCodes, gdprConsent, uspConsent, s2sConfig) {
246
246
  payload.us_privacy = uspConsent;
247
247
  }
248
248
 
249
+ if (gppConsent) {
250
+ // proposing the following formatting, can adjust if needed...
251
+ // update - leaving this param as an array, since it's part of a POST payload where the [] characters shouldn't matter too much
252
+ payload.gpp_sid = gppConsent.applicableSections
253
+ // should we add check if applicableSections was not equal to -1 (where user was out of scope)?
254
+ // this would be similar to what was done above for TCF
255
+ payload.gpp = gppConsent.gppString;
256
+ }
257
+
249
258
  if (typeof s2sConfig.coopSync === 'boolean') {
250
259
  payload.coopSync = s2sConfig.coopSync;
251
260
  }
@@ -330,7 +339,7 @@ function doBidderSync(type, url, bidder, done, timeout) {
330
339
  *
331
340
  * @param {Array} bidders a list of bidder names
332
341
  */
333
- function doClientSideSyncs(bidders, gdprConsent, uspConsent) {
342
+ function doClientSideSyncs(bidders, gdprConsent, uspConsent, gppConsent) {
334
343
  bidders.forEach(bidder => {
335
344
  let clientAdapter = adapterManager.getBidAdapter(bidder);
336
345
  if (clientAdapter && clientAdapter.registerSyncs) {
@@ -341,7 +350,8 @@ function doClientSideSyncs(bidders, gdprConsent, uspConsent) {
341
350
  clientAdapter,
342
351
  [],
343
352
  gdprConsent,
344
- uspConsent
353
+ uspConsent,
354
+ gppConsent
345
355
  )
346
356
  );
347
357
  }
@@ -411,12 +421,13 @@ function getMatchingConsentUrl(urlProp, gdprConsent) {
411
421
  }
412
422
 
413
423
  function getConsentData(bidRequests) {
414
- let gdprConsent, uspConsent;
424
+ let gdprConsent, uspConsent, gppConsent;
415
425
  if (Array.isArray(bidRequests) && bidRequests.length > 0) {
416
426
  gdprConsent = bidRequests[0].gdprConsent;
417
427
  uspConsent = bidRequests[0].uspConsent;
428
+ gppConsent = bidRequests[0].gppConsent;
418
429
  }
419
- return { gdprConsent, uspConsent };
430
+ return { gdprConsent, uspConsent, gppConsent };
420
431
  }
421
432
 
422
433
  /**
@@ -433,7 +444,7 @@ export function PrebidServer() {
433
444
  done = adapterMetrics.startTiming('total').stopBefore(done);
434
445
  bidRequests.forEach(req => useMetrics(req.metrics).join(adapterMetrics, {continuePropagation: false}));
435
446
 
436
- let { gdprConsent, uspConsent } = getConsentData(bidRequests);
447
+ let { gdprConsent, uspConsent, gppConsent } = getConsentData(bidRequests);
437
448
 
438
449
  if (Array.isArray(_s2sConfigs)) {
439
450
  if (s2sBidRequest.s2sConfig && s2sBidRequest.s2sConfig.syncEndpoint && getMatchingConsentUrl(s2sBidRequest.s2sConfig.syncEndpoint, gdprConsent)) {
@@ -441,7 +452,7 @@ export function PrebidServer() {
441
452
  .map(bidder => adapterManager.aliasRegistry[bidder] || bidder)
442
453
  .filter((bidder, index, array) => (array.indexOf(bidder) === index));
443
454
 
444
- queueSync(syncBidders, gdprConsent, uspConsent, s2sBidRequest.s2sConfig);
455
+ queueSync(syncBidders, gdprConsent, uspConsent, gppConsent, s2sBidRequest.s2sConfig);
445
456
  }
446
457
 
447
458
  processPBSRequest(s2sBidRequest, bidRequests, ajax, {
@@ -450,7 +461,7 @@ export function PrebidServer() {
450
461
  bidRequests.forEach(bidderRequest => events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest));
451
462
  }
452
463
  done();
453
- doClientSideSyncs(requestedBidders, gdprConsent, uspConsent);
464
+ doClientSideSyncs(requestedBidders, gdprConsent, uspConsent, gppConsent);
454
465
  },
455
466
  onError: done,
456
467
  onBid: function ({adUnit, bid}) {
@@ -246,6 +246,7 @@ export function buildPBSRequest(s2sBidRequest, bidderRequests, adUnits, requeste
246
246
  impIds.add(impId)
247
247
  proxyBidRequests.push({
248
248
  ...adUnit,
249
+ adUnitCode: adUnit.code,
249
250
  ...getDefinedParams(actualBidRequests.values().next().value || {}, ['userId', 'userIdAsEids', 'schain']),
250
251
  pbsData: {impId, actualBidRequests, adUnit}
251
252
  });
@@ -163,7 +163,7 @@ import {getHook, module} from '../../src/hook.js';
163
163
  import {logError, logInfo, logWarn} from '../../src/utils.js';
164
164
  import * as events from '../../src/events.js';
165
165
  import CONSTANTS from '../../src/constants.json';
166
- import adapterManager, {gdprDataHandler, uspDataHandler} from '../../src/adapterManager.js';
166
+ import adapterManager, {gdprDataHandler, uspDataHandler, gppDataHandler} from '../../src/adapterManager.js';
167
167
  import {find} from '../../src/polyfill.js';
168
168
  import {timedAuctionHook} from '../../src/utils/perfMetrics.js';
169
169
 
@@ -246,6 +246,7 @@ function getConsentData() {
246
246
  return {
247
247
  gdpr: gdprDataHandler.getConsentData(),
248
248
  usp: uspDataHandler.getConsentData(),
249
+ gpp: gppDataHandler.getConsentData(),
249
250
  coppa: !!(config.getConfig('coppa'))
250
251
  }
251
252
  }
@@ -0,0 +1,209 @@
1
+ import { deepAccess, logError, parseUrl, parseSizesInput, triggerPixel } from '../src/utils.js';
2
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
3
+ import { config } from '../src/config.js';
4
+ import { VIDEO } from '../src/mediaTypes.js';
5
+ import find from 'core-js-pure/features/array/find.js'; // eslint-disable-line prebid/validate-imports
6
+
7
+ const BIDDER_CODE = 'viously';
8
+ // const GVLID = 1028;
9
+ const CURRENCY = 'EUR';
10
+ const TTL = 60;
11
+ const HTTP_METHOD = 'POST';
12
+ const REQUEST_URL = 'https://bidder.viously.com/bid';
13
+ const REQUIRED_VIDEO_PARAMS = ['context', 'playbackmethod', 'playerSize'];
14
+ const REQUIRED_VIOUSLY_PARAMS = ['pid'];
15
+
16
+ export const spec = {
17
+ code: BIDDER_CODE,
18
+ // gvlid: GVLID,
19
+ supportedMediaTypes: [VIDEO],
20
+
21
+ /**
22
+ * Determines whether or not the given bid request is valid.
23
+ *
24
+ * @param {BidRequest} bid The bid params to validate.
25
+ * @return boolean True if this is a valid bid, and false otherwise.
26
+ */
27
+ isBidRequestValid: function(bid) {
28
+ let videoParams = deepAccess(bid, 'mediaTypes.video');
29
+
30
+ if (!bid.params) {
31
+ logError('The bid params are missing');
32
+ return false;
33
+ }
34
+
35
+ if (!videoParams) {
36
+ logError('The placement must be of video type');
37
+ return false;
38
+ }
39
+
40
+ /**
41
+ * VIDEO checks
42
+ */
43
+
44
+ let areParamsValid = true;
45
+
46
+ REQUIRED_VIDEO_PARAMS.forEach(function(videoParam) {
47
+ if (typeof videoParams[videoParam] === 'undefined') {
48
+ logError('mediaTypes.video.' + videoParam + ' must be set for video placement.');
49
+ areParamsValid = false;
50
+ }
51
+ });
52
+
53
+ if (parseSizesInput(videoParams.playerSize).length === 0) {
54
+ logError('mediaTypes.video.playerSize must be set for video placement at the right format.');
55
+ return false;
56
+ }
57
+
58
+ /**
59
+ * Viously checks
60
+ */
61
+
62
+ REQUIRED_VIOUSLY_PARAMS.forEach(function(viouslyParam) {
63
+ if (typeof bid.params[viouslyParam] === 'undefined') {
64
+ logError('The ' + viouslyParam + ' is missing.');
65
+ areParamsValid = false;
66
+ }
67
+ });
68
+
69
+ if (!areParamsValid) {
70
+ return false;
71
+ }
72
+
73
+ return true;
74
+ },
75
+
76
+ buildRequests: function(validBidRequests, bidderRequest) {
77
+ let payload = {};
78
+
79
+ /** Viously Publisher ID */
80
+ if (validBidRequests[0].params.pid) {
81
+ payload.pid = validBidRequests[0].params.pid;
82
+ }
83
+
84
+ // Referer Info
85
+ if (config.getConfig('pageUrl')) {
86
+ let parsedUrl = parseUrl(config.getConfig('pageUrl'));
87
+
88
+ payload.domain = parsedUrl.hostname;
89
+ payload.page_domain = config.getConfig('pageUrl');
90
+ } else if (bidderRequest && bidderRequest.refererInfo) {
91
+ let parsedUrl = parseUrl(bidderRequest.refererInfo.page);
92
+
93
+ payload.domain = parsedUrl.hostname;
94
+ payload.page_domain = bidderRequest.refererInfo.page;
95
+ }
96
+ if (payload.domain) {
97
+ /** Make sur that the scheme is not part of the domain */
98
+ payload.domain = payload.domain.replace(/(^\w+:|^)\/\//, '');
99
+ payload.domain = payload.domain.replace(/\/$/, '');
100
+ }
101
+
102
+ // Handle GDPR
103
+ if (bidderRequest && bidderRequest.gdprConsent) {
104
+ payload.gdpr = bidderRequest.gdprConsent.gdprApplies;
105
+ payload.gdpr_consent = bidderRequest.gdprConsent.consentString;
106
+ if (bidderRequest.gdprConsent.addtlConsent && bidderRequest.gdprConsent.addtlConsent.indexOf('~') !== -1) {
107
+ payload.addtl_consent = bidderRequest.gdprConsent.addtlConsent;
108
+ }
109
+ }
110
+
111
+ // US Privacy
112
+ if (bidderRequest && bidderRequest.uspConsent) {
113
+ payload.us_privacy = bidderRequest.uspConsent;
114
+ }
115
+
116
+ // Schain
117
+ if (validBidRequests[0].schain) {
118
+ payload.schain = validBidRequests[0].schain;
119
+ }
120
+ // Currency
121
+ payload.currency_code = CURRENCY;
122
+
123
+ // User IDs
124
+ if (validBidRequests[0].userIdAsEids) {
125
+ payload.users_uid = validBidRequests[0].userIdAsEids;
126
+ }
127
+
128
+ // Placements
129
+ payload.placements = validBidRequests.map(bidRequest => {
130
+ let request = {
131
+ id: bidRequest.adUnitCode,
132
+ bid_id: bidRequest.bidId
133
+ };
134
+
135
+ request.video_params = {
136
+ context: deepAccess(bidRequest, 'mediaTypes.video.context'),
137
+ playbackmethod: deepAccess(bidRequest, 'mediaTypes.video.playbackmethod'),
138
+ size: parseSizesInput(deepAccess(bidRequest, 'mediaTypes.video.playerSize'))
139
+ };
140
+
141
+ return request;
142
+ });
143
+
144
+ return {
145
+ method: HTTP_METHOD,
146
+ url: validBidRequests[0].params.endpoint ? validBidRequests[0].params.endpoint : REQUEST_URL,
147
+ data: payload
148
+ };
149
+ },
150
+
151
+ interpretResponse: function(serverResponse, requests) {
152
+ const bidResponses = [];
153
+ const responseBody = serverResponse.body;
154
+
155
+ if (responseBody.ads && responseBody.ads.length > 0) {
156
+ responseBody.ads.forEach(function(bidResponse) {
157
+ if (bidResponse.bid) {
158
+ let bidRequest = find(requests.data.placements, bid => bid.bid_id === bidResponse.bid_id);
159
+
160
+ if (bidRequest) {
161
+ let sizes = bidResponse.size.split('x');
162
+
163
+ const bid = {
164
+ requestId: bidRequest.bid_id,
165
+ id: bidResponse.id,
166
+ cpm: bidResponse.cpm,
167
+ width: sizes[0],
168
+ height: sizes[1],
169
+ creativeId: bidResponse.creative_id || '',
170
+ currency: CURRENCY,
171
+ netRevenue: true,
172
+ ttl: TTL,
173
+ mediaType: 'video',
174
+ meta: {},
175
+ // Tracking data
176
+ nurl: bidResponse.nurl ? bidResponse.nurl : []
177
+ };
178
+
179
+ if (bidResponse.ad_url) {
180
+ bid.vastUrl = bidResponse.ad_url;
181
+ } else {
182
+ bid.vastXml = bidResponse.ad;
183
+ }
184
+
185
+ bidResponses.push(bid);
186
+ }
187
+ }
188
+ });
189
+ }
190
+
191
+ return bidResponses;
192
+ },
193
+
194
+ getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {},
195
+
196
+ onTimeout: function(timeoutData) {},
197
+
198
+ onBidWon: function(bid) {
199
+ if (bid && bid.nurl && bid.nurl.length > 0) {
200
+ bid.nurl.forEach(function(winUrl) {
201
+ triggerPixel(winUrl, null);
202
+ });
203
+ }
204
+ },
205
+
206
+ onSetTargeting: function(bid) {}
207
+ };
208
+
209
+ registerBidder(spec);
@@ -0,0 +1,35 @@
1
+ # Overview
2
+
3
+ ```
4
+ Module Name: Viously Bidder Adapter
5
+ Module Type: Bidder Adapter
6
+ Maintainer: prebid@viously.com
7
+ ```
8
+
9
+ # Description
10
+
11
+ Module that connects to Viously's demand sources
12
+
13
+ # Test Parameters
14
+ ```
15
+ var adUnits = [
16
+ {
17
+ code: 'test-div',
18
+ mediaTypes: {
19
+ video: {
20
+ playerSize: [640, 360],
21
+ context: 'instream',
22
+ playbackmethod: [1, 2, 3, 4, 5, 6]
23
+ }
24
+ },
25
+ bids: [
26
+ {
27
+ bidder: 'viously',
28
+ params: {
29
+ pid: '20d30b78-43ec-11ed-b878-0242ac120002'
30
+ }
31
+ }
32
+ ]
33
+ }
34
+ ];
35
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "7.29.0",
3
+ "version": "7.31.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -31,7 +31,7 @@ import {hook} from './hook.js';
31
31
  import {find, includes} from './polyfill.js';
32
32
  import {adunitCounter} from './adUnits.js';
33
33
  import {getRefererInfo} from './refererDetection.js';
34
- import {GdprConsentHandler, UspConsentHandler} from './consentHandler.js';
34
+ import {GdprConsentHandler, UspConsentHandler, GppConsentHandler} from './consentHandler.js';
35
35
  import * as events from './events.js';
36
36
  import CONSTANTS from './constants.json';
37
37
  import {useMetrics} from './utils/perfMetrics.js';
@@ -161,6 +161,7 @@ function getAdUnitCopyForClientAdapters(adUnits) {
161
161
 
162
162
  export let gdprDataHandler = new GdprConsentHandler();
163
163
  export let uspDataHandler = new UspConsentHandler();
164
+ export let gppDataHandler = new GppConsentHandler();
164
165
 
165
166
  export let coppaDataHandler = {
166
167
  getCoppa: function() {
@@ -309,17 +310,17 @@ adapterManager.makeBidRequests = hook('sync', function (adUnits, auctionStart, a
309
310
  }
310
311
  });
311
312
 
312
- if (gdprDataHandler.getConsentData()) {
313
- bidRequests.forEach(bidRequest => {
313
+ bidRequests.forEach(bidRequest => {
314
+ if (gdprDataHandler.getConsentData()) {
314
315
  bidRequest['gdprConsent'] = gdprDataHandler.getConsentData();
315
- });
316
- }
317
-
318
- if (uspDataHandler.getConsentData()) {
319
- bidRequests.forEach(bidRequest => {
316
+ }
317
+ if (uspDataHandler.getConsentData()) {
320
318
  bidRequest['uspConsent'] = uspDataHandler.getConsentData();
321
- });
322
- }
319
+ }
320
+ if (gppDataHandler.getConsentData()) {
321
+ bidRequest['gppConsent'] = gppDataHandler.getConsentData();
322
+ }
323
+ });
323
324
 
324
325
  bidRequests.forEach(bidRequest => {
325
326
  config.runWithBidder(bidRequest.bidderCode, () => {
@@ -214,7 +214,7 @@ export function newBidder(spec) {
214
214
  done();
215
215
  config.runWithBidder(spec.code, () => {
216
216
  events.emit(CONSTANTS.EVENTS.BIDDER_DONE, bidderRequest);
217
- registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent);
217
+ registerSyncs(responses, bidderRequest.gdprConsent, bidderRequest.uspConsent, bidderRequest.gppConsent);
218
218
  });
219
219
  }
220
220
 
@@ -295,8 +295,8 @@ export function newBidder(spec) {
295
295
  return false;
296
296
  }
297
297
 
298
- function registerSyncs(responses, gdprConsent, uspConsent) {
299
- registerSyncInner(spec, responses, gdprConsent, uspConsent);
298
+ function registerSyncs(responses, gdprConsent, uspConsent, gppConsent) {
299
+ registerSyncInner(spec, responses, gdprConsent, uspConsent, gppConsent);
300
300
  }
301
301
 
302
302
  function filterAndWarn(bid) {
@@ -448,14 +448,14 @@ export const processBidderRequests = hook('sync', function (spec, bids, bidderRe
448
448
  })
449
449
  }, 'processBidderRequests')
450
450
 
451
- export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent) {
451
+ export const registerSyncInner = hook('async', function(spec, responses, gdprConsent, uspConsent, gppConsent) {
452
452
  const aliasSyncEnabled = config.getConfig('userSync.aliasSyncEnabled');
453
453
  if (spec.getUserSyncs && (aliasSyncEnabled || !adapterManager.aliasRegistry[spec.code])) {
454
454
  let filterConfig = config.getConfig('userSync.filterSettings');
455
455
  let syncs = spec.getUserSyncs({
456
456
  iframeEnabled: !!(filterConfig && (filterConfig.iframe || filterConfig.all)),
457
457
  pixelEnabled: !!(filterConfig && (filterConfig.image || filterConfig.all)),
458
- }, responses, gdprConsent, uspConsent);
458
+ }, responses, gdprConsent, uspConsent, gppConsent);
459
459
  if (syncs) {
460
460
  if (!Array.isArray(syncs)) {
461
461
  syncs = [syncs];