prebid.js 6.5.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 (56) hide show
  1. package/modules/.submodules.json +2 -1
  2. package/modules/adkernelBidAdapter.js +2 -1
  3. package/modules/admanBidAdapter.js +10 -4
  4. package/modules/adomikAnalyticsAdapter.js +23 -11
  5. package/modules/adqueryIdSystem.js +103 -0
  6. package/modules/adqueryIdSystem.md +35 -0
  7. package/modules/bliinkBidAdapter.js +2 -1
  8. package/modules/compassBidAdapter.js +9 -2
  9. package/modules/criteoBidAdapter.js +1 -1
  10. package/modules/criteoIdSystem.js +29 -7
  11. package/modules/glimpseBidAdapter.js +66 -44
  12. package/modules/idImportLibrary.js +45 -8
  13. package/modules/idImportLibrary.md +4 -0
  14. package/modules/improvedigitalBidAdapter.js +24 -2
  15. package/modules/nextMillenniumBidAdapter.js +3 -1
  16. package/modules/oguryBidAdapter.js +9 -2
  17. package/modules/onetagBidAdapter.js +4 -2
  18. package/modules/proxistoreBidAdapter.js +0 -2
  19. package/modules/pubmaticAnalyticsAdapter.js +16 -0
  20. package/modules/richaudienceBidAdapter.js +3 -2
  21. package/modules/riseBidAdapter.js +1 -1
  22. package/modules/rtbhouseBidAdapter.js +14 -4
  23. package/modules/rtdModule/index.js +6 -5
  24. package/modules/showheroes-bsBidAdapter.js +13 -2
  25. package/modules/tappxBidAdapter.js +8 -5
  26. package/modules/teadsBidAdapter.js +1 -2
  27. package/modules/userId/eids.js +7 -1
  28. package/modules/userId/userId.md +8 -0
  29. package/modules/welectBidAdapter.js +106 -0
  30. package/package.json +1 -1
  31. package/src/hook.js +5 -1
  32. package/src/prebid.js +18 -4
  33. package/test/spec/modules/admanBidAdapter_spec.js +2 -2
  34. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +3 -1
  35. package/test/spec/modules/adqueryIdSystem_spec.js +74 -0
  36. package/test/spec/modules/bliinkBidAdapter_spec.js +2 -0
  37. package/test/spec/modules/compassBidAdapter_spec.js +1 -0
  38. package/test/spec/modules/criteoIdSystem_spec.js +6 -3
  39. package/test/spec/modules/eids_spec.js +15 -0
  40. package/test/spec/modules/glimpseBidAdapter_spec.js +0 -18
  41. package/test/spec/modules/idImportLibrary_spec.js +197 -10
  42. package/test/spec/modules/improvedigitalBidAdapter_spec.js +42 -0
  43. package/test/spec/modules/loglyliftBidAdapter_spec.js +1 -1
  44. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +1 -1
  45. package/test/spec/modules/oguryBidAdapter_spec.js +10 -2
  46. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +13 -1
  47. package/test/spec/modules/realTimeDataModule_spec.js +16 -3
  48. package/test/spec/modules/richaudienceBidAdapter_spec.js +40 -0
  49. package/test/spec/modules/riseBidAdapter_spec.js +1 -1
  50. package/test/spec/modules/rtbhouseBidAdapter_spec.js +20 -0
  51. package/test/spec/modules/showheroes-bsBidAdapter_spec.js +2 -0
  52. package/test/spec/modules/tappxBidAdapter_spec.js +0 -19
  53. package/test/spec/modules/teadsBidAdapter_spec.js +14 -59
  54. package/test/spec/modules/userId_spec.js +68 -19
  55. package/test/spec/modules/welectBidAdapter_spec.js +211 -0
  56. package/test/spec/unit/pbjs_api_spec.js +3 -1
@@ -1,4 +1,4 @@
1
- import { deepSetValue, logError, _each, getBidRequest, isNumber, isArray, deepAccess, isFn, isPlainObject, logWarn, getBidIdParameter, getUniqueIdentifierStr, isEmpty, isInteger } from '../src/utils.js';
1
+ import { deepSetValue, logError, _each, getBidRequest, isNumber, isArray, deepAccess, isFn, isPlainObject, logWarn, getBidIdParameter, getUniqueIdentifierStr, isEmpty, isInteger, isStr } 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, NATIVE, VIDEO } from '../src/mediaTypes.js';
@@ -11,7 +11,7 @@ const RENDERER_URL = 'https://acdn.adnxs.com/video/outstream/ANOutstreamVideo.js
11
11
  const VIDEO_TARGETING = ['skip', 'skipmin', 'skipafter'];
12
12
 
13
13
  export const spec = {
14
- version: '7.5.0',
14
+ version: '7.6.0',
15
15
  code: BIDDER_CODE,
16
16
  gvlid: 253,
17
17
  aliases: ['id'],
@@ -73,6 +73,22 @@ export const spec = {
73
73
  requestParameters.referrer = bidderRequest.refererInfo.referer;
74
74
  }
75
75
 
76
+ // Adding first party data
77
+ const site = config.getConfig('ortb2.site');
78
+ if (site) {
79
+ const pageCategory = site.pagecat || site.cat;
80
+ if (pageCategory && isArray(pageCategory)) {
81
+ requestParameters.pagecat = pageCategory.filter((category) => {
82
+ return category && isStr(category)
83
+ });
84
+ }
85
+ const genre = deepAccess(site, 'content.genre');
86
+ if (genre && isStr(genre)) {
87
+ requestParameters.genre = genre;
88
+ }
89
+ }
90
+ // End of adding first party data
91
+
76
92
  requestParameters.schain = bidRequests[0].schain;
77
93
 
78
94
  if (bidRequests[0].userId) {
@@ -621,6 +637,12 @@ export function ImproveDigitalAdServerJSClient(endPoint) {
621
637
  if (requestParameters.schain) {
622
638
  impressionBidRequestObject.schain = requestParameters.schain;
623
639
  }
640
+ if (requestParameters.pagecat) {
641
+ impressionBidRequestObject.pagecat = requestParameters.pagecat;
642
+ }
643
+ if (requestParameters.genre) {
644
+ impressionBidRequestObject.genre = requestParameters.genre;
645
+ }
624
646
  if (requestParameters.user) {
625
647
  impressionBidRequestObject.user = requestParameters.user;
626
648
  }
@@ -25,12 +25,14 @@ export const spec = {
25
25
  window.nmmRefreshCounts[bid.adUnitCode] = window.nmmRefreshCounts[bid.adUnitCode] || 0;
26
26
  const postBody = {
27
27
  'id': bid.auctionId,
28
- 'refresh_count': window.nmmRefreshCounts[bid.adUnitCode]++,
29
28
  'ext': {
30
29
  'prebid': {
31
30
  'storedrequest': {
32
31
  'id': getBidIdParameter('placement_id', bid.params)
33
32
  }
33
+ },
34
+ 'nextMillennium': {
35
+ 'refresh_count': window.nmmRefreshCounts[bid.adUnitCode]++,
34
36
  }
35
37
  }
36
38
  }
@@ -10,6 +10,7 @@ const DEFAULT_TIMEOUT = 1000;
10
10
  const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request';
11
11
  const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io';
12
12
  const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io';
13
+ const ADAPTER_VERSION = '1.2.7';
13
14
 
14
15
  function isBidRequestValid(bid) {
15
16
  const adUnitSizes = getAdUnitSizes(bid);
@@ -55,7 +56,11 @@ function buildRequests(validBidRequests, bidderRequest) {
55
56
  consent: ''
56
57
  }
57
58
  },
58
- imp: []
59
+ imp: [],
60
+ ext: {
61
+ adapterversion: ADAPTER_VERSION,
62
+ prebidversion: '$prebid.version$'
63
+ }
59
64
  };
60
65
 
61
66
  if (bidderRequest.hasOwnProperty('gdprConsent') &&
@@ -123,7 +128,9 @@ function interpretResponse(openRtbBidResponse) {
123
128
  meta: {
124
129
  advertiserDomains: bid.adomain
125
130
  },
126
- nurl: bid.nurl
131
+ nurl: bid.nurl,
132
+ adapterVersion: ADAPTER_VERSION,
133
+ prebidVersion: '$prebid.version$'
127
134
  };
128
135
 
129
136
  bidResponse.ad = bid.adm;
@@ -347,11 +347,13 @@ function getSizes(sizes) {
347
347
  function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent) {
348
348
  let syncs = [];
349
349
  let params = '';
350
- if (gdprConsent && typeof gdprConsent.consentString === 'string') {
351
- params += '&gdpr_consent=' + gdprConsent.consentString;
350
+ if (gdprConsent) {
352
351
  if (typeof gdprConsent.gdprApplies === 'boolean') {
353
352
  params += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0);
354
353
  }
354
+ if (typeof gdprConsent.consentString === 'string') {
355
+ params += '&gdpr_consent=' + gdprConsent.consentString;
356
+ }
355
357
  }
356
358
  if (uspConsent && typeof uspConsent === 'string') {
357
359
  params += '&us_privacy=' + uspConsent;
@@ -172,8 +172,6 @@ function interpretResponse(serverResponse, bidRequest) {
172
172
 
173
173
  function _assignFloor(bid) {
174
174
  if (!isFn(bid.getFloor)) {
175
- // eslint-disable-next-line no-console
176
- console.log(bid.params.bidFloor);
177
175
  return bid.params.bidFloor ? bid.params.bidFloor : null;
178
176
  }
179
177
  const floor = bid.getFloor({
@@ -200,6 +200,21 @@ function getAdapterNameForAlias(aliasName) {
200
200
  return adapterManager.aliasRegistry[aliasName] || aliasName;
201
201
  }
202
202
 
203
+ function getAdDomain(bidResponse) {
204
+ if (bidResponse.meta && bidResponse.meta.advertiserDomains) {
205
+ let adomain = bidResponse.meta.advertiserDomains[0]
206
+ if (adomain) {
207
+ try {
208
+ let hostname = (new URL(adomain));
209
+ return hostname.hostname.replace('www.', '');
210
+ } catch (e) {
211
+ logWarn(LOG_PRE_FIX + 'Adomain URL (Not a proper URL):', adomain);
212
+ return adomain.replace('www.', '');
213
+ }
214
+ }
215
+ }
216
+ }
217
+
203
218
  function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) {
204
219
  highestBid = (highestBid && highestBid.length > 0) ? highestBid[0] : null;
205
220
  return Object.keys(adUnit.bids).reduce(function(partnerBids, bidId) {
@@ -218,6 +233,7 @@ function gatherPartnerBidsForAdUnitForLogger(adUnit, adUnitId, highestBid) {
218
233
  'dc': bid.bidResponse ? (bid.bidResponse.dealChannel || EMPTY_STRING) : EMPTY_STRING,
219
234
  'l1': bid.bidResponse ? bid.clientLatencyTimeMs : 0,
220
235
  'l2': 0,
236
+ 'adv': bid.bidResponse ? getAdDomain(bid.bidResponse) || undefined : undefined,
221
237
  'ss': (s2sBidders.indexOf(bid.bidder) > -1) ? 1 : 0,
222
238
  't': (bid.status == ERROR && bid.error.code == TIMEOUT_ERROR) ? 1 : 0,
223
239
  'wb': (highestBid && highestBid.requestId === bid.bidId ? 1 : 0),
@@ -1,4 +1,4 @@
1
- import { isEmpty, deepAccess, isStr } from '../src/utils.js';
1
+ import {isEmpty, deepAccess, isStr} 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';
@@ -52,7 +52,8 @@ export const spec = {
52
52
  videoData: raiGetVideoInfo(bid),
53
53
  scr_rsl: raiGetResolution(),
54
54
  cpuc: (typeof window.navigator != 'undefined' ? window.navigator.hardwareConcurrency : null),
55
- kws: (!isEmpty(bid.params.keywords) ? bid.params.keywords : null)
55
+ kws: (!isEmpty(bid.params.keywords) ? bid.params.keywords : null),
56
+ schain: bid.schain
56
57
  };
57
58
 
58
59
  REFERER = (typeof bidderRequest.refererInfo.referer != 'undefined' ? encodeURIComponent(bidderRequest.refererInfo.referer) : null)
@@ -159,7 +159,7 @@ function getSupplyChain(schainObject) {
159
159
  scStr += '!';
160
160
  scStr += `${getEncodedValIfNotEmpty(node.asi)},`;
161
161
  scStr += `${getEncodedValIfNotEmpty(node.sid)},`;
162
- scStr += `${getEncodedValIfNotEmpty(node.hp)},`;
162
+ scStr += `${node.hp ? encodeURIComponent(node.hp) : ''},`;
163
163
  scStr += `${getEncodedValIfNotEmpty(node.rid)},`;
164
164
  scStr += `${getEncodedValIfNotEmpty(node.name)},`;
165
165
  scStr += `${getEncodedValIfNotEmpty(node.domain)}`;
@@ -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
  /**
@@ -197,12 +197,13 @@ const setEventsListeners = (function () {
197
197
  return function setEventsListeners() {
198
198
  if (!registered) {
199
199
  Object.entries({
200
- [CONSTANTS.EVENTS.AUCTION_INIT]: 'onAuctionInitEvent',
201
- [CONSTANTS.EVENTS.AUCTION_END]: 'onAuctionEndEvent',
202
- [CONSTANTS.EVENTS.BID_RESPONSE]: 'onBidResponseEvent',
203
- [CONSTANTS.EVENTS.BID_REQUESTED]: 'onBidRequestEvent'
204
- }).forEach(([ev, handler]) => {
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
205
  events.on(ev, (args) => {
206
+ preprocess && preprocess(args);
206
207
  subModules.forEach(sm => {
207
208
  try {
208
209
  sm[handler] && sm[handler](args, sm.config, _userConsent)
@@ -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;
@@ -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);
@@ -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
  }
@@ -0,0 +1,106 @@
1
+ import { deepAccess } from '../src/utils.js';
2
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
3
+
4
+ const BIDDER_CODE = 'welect';
5
+ const DEFAULT_DOMAIN = 'www.welect.de';
6
+
7
+ export const spec = {
8
+ code: BIDDER_CODE,
9
+ aliases: ['wlt'],
10
+ gvlid: 282,
11
+ supportedMediaTypes: ['video'],
12
+
13
+ // short code
14
+ /**
15
+ * Determines whether or not the given bid request is valid.
16
+ *
17
+ * @param {BidRequest} bid The bid params to validate.
18
+ * @return boolean True if this is a valid bid, and false otherwise.
19
+ */
20
+ isBidRequestValid: function (bid) {
21
+ return (
22
+ deepAccess(bid, 'mediaTypes.video.context') === 'instream' &&
23
+ !!bid.params.placementId
24
+ );
25
+ },
26
+ /**
27
+ * Make a server request from the list of BidRequests.
28
+ *
29
+ * @param {validBidRequests[]} - an array of bids
30
+ * @return ServerRequest Info describing the request to the server.
31
+ */
32
+ buildRequests: function (validBidRequests) {
33
+ return validBidRequests.map((bidRequest) => {
34
+ let rawSizes =
35
+ deepAccess(bidRequest, 'mediaTypes.video.playerSize') ||
36
+ bidRequest.sizes;
37
+ let size = rawSizes[0];
38
+
39
+ let domain = bidRequest.params.domain || DEFAULT_DOMAIN;
40
+
41
+ let url = `https://${domain}/api/v2/preflight/${bidRequest.params.placementId}`;
42
+
43
+ let gdprConsent = null;
44
+
45
+ if (bidRequest && bidRequest.gdprConsent) {
46
+ gdprConsent = {
47
+ gdpr_consent: {
48
+ gdprApplies: bidRequest.gdprConsent.gdprApplies,
49
+ tcString: bidRequest.gdprConsent.gdprConsent,
50
+ },
51
+ };
52
+ }
53
+
54
+ const data = {
55
+ width: size[0],
56
+ height: size[1],
57
+ bid_id: bidRequest.bidId,
58
+ ...gdprConsent,
59
+ };
60
+
61
+ return {
62
+ method: 'POST',
63
+ url: url,
64
+ data: data,
65
+ options: {
66
+ contentType: 'application/json',
67
+ withCredentials: false,
68
+ crossOrigin: true,
69
+ },
70
+ };
71
+ });
72
+ },
73
+ /**
74
+ * Unpack the response from the server into a list of bids.
75
+ *
76
+ * @param {ServerResponse} serverResponse A successful response from the server.
77
+ * @return {Bid[]} An array of bids which were nested inside the server.
78
+ */
79
+ interpretResponse: function (serverResponse, bidRequest) {
80
+ const responseBody = serverResponse.body;
81
+
82
+ if (typeof responseBody !== 'object' || responseBody.available !== true) {
83
+ return [];
84
+ }
85
+
86
+ const bidResponses = [];
87
+ const bidResponse = {
88
+ requestId: responseBody.bidResponse.requestId,
89
+ cpm: responseBody.bidResponse.cpm,
90
+ width: responseBody.bidResponse.width,
91
+ height: responseBody.bidResponse.height,
92
+ creativeId: responseBody.bidResponse.creativeId,
93
+ currency: responseBody.bidResponse.currency,
94
+ netRevenue: responseBody.bidResponse.netRevenue,
95
+ ttl: responseBody.bidResponse.ttl,
96
+ ad: responseBody.bidResponse.ad,
97
+ vastUrl: responseBody.bidResponse.vastUrl,
98
+ meta: {
99
+ advertiserDomains: responseBody.bidResponse.meta.advertiserDomains
100
+ }
101
+ };
102
+ bidResponses.push(bidResponse);
103
+ return bidResponses;
104
+ },
105
+ };
106
+ registerBidder(spec);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "6.5.0",
3
+ "version": "6.6.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
package/src/hook.js CHANGED
@@ -13,14 +13,18 @@ export function setupBeforeHookFnOnce(baseFn, hookFn, priority = 15) {
13
13
  baseFn.before(hookFn, priority);
14
14
  }
15
15
  }
16
+ const submoduleInstallMap = {};
16
17
 
17
- export function module(name, install) {
18
+ export function module(name, install, {postInstallAllowed = false} = {}) {
18
19
  hook('async', function (submodules) {
19
20
  submodules.forEach(args => install(...args));
21
+ if (postInstallAllowed) submoduleInstallMap[name] = install;
20
22
  }, name)([]); // will be queued until hook.ready() called in pbjs.processQueue();
21
23
  }
22
24
 
23
25
  export function submodule(name, ...args) {
26
+ const install = submoduleInstallMap[name];
27
+ if (install) return install(...args);
24
28
  getHook(name).before((next, modules) => {
25
29
  modules.push(args);
26
30
  next(modules);
package/src/prebid.js CHANGED
@@ -402,10 +402,23 @@ function emitAdRenderSucceeded({ doc, bid, id }) {
402
402
  events.emit(AD_RENDER_SUCCEEDED, data);
403
403
  }
404
404
 
405
+ /**
406
+ * This function will check for presence of given node in given parent. If not present - will inject it.
407
+ * @param {Node} node node, whose existance is in question
408
+ * @param {Document} doc document element do look in
409
+ * @param {string} tagName tag name to look in
410
+ */
411
+ function reinjectNodeIfRemoved(node, doc, tagName) {
412
+ const injectionNode = doc.querySelector(tagName);
413
+ if (!node.parentNode || node.parentNode !== injectionNode) {
414
+ insertElement(node, doc, tagName);
415
+ }
416
+ }
417
+
405
418
  /**
406
419
  * This function will render the ad (based on params) in the given iframe document passed through.
407
420
  * Note that doc SHOULD NOT be the parent document page as we can't doc.write() asynchronously
408
- * @param {HTMLDocument} doc document
421
+ * @param {Document} doc document
409
422
  * @param {string} id bid id to locate the ad
410
423
  * @alias module:pbjs.renderAd
411
424
  */
@@ -449,10 +462,11 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
449
462
  const {height, width, ad, mediaType, adUrl, renderer} = bid;
450
463
 
451
464
  const creativeComment = document.createComment(`Creative ${bid.creativeId} served by ${bid.bidder} Prebid.js Header Bidding`);
465
+ insertElement(creativeComment, doc, 'html');
452
466
 
453
467
  if (isRendererRequired(renderer)) {
454
468
  executeRenderer(renderer, bid);
455
- insertElement(creativeComment, doc, 'html');
469
+ reinjectNodeIfRemoved(creativeComment, doc, 'html');
456
470
  emitAdRenderSucceeded({ doc, bid, id });
457
471
  } else if ((doc === document && !inIframe()) || mediaType === 'video') {
458
472
  const message = `Error trying to write ad. Ad render call ad id ${id} was prevented from writing to the main document.`;
@@ -471,7 +485,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
471
485
  doc.write(ad);
472
486
  doc.close();
473
487
  setRenderSize(doc, width, height);
474
- insertElement(creativeComment, doc, 'html');
488
+ reinjectNodeIfRemoved(creativeComment, doc, 'html');
475
489
  callBurl(bid);
476
490
  emitAdRenderSucceeded({ doc, bid, id });
477
491
  } else if (adUrl) {
@@ -484,7 +498,7 @@ $$PREBID_GLOBAL$$.renderAd = hook('async', function (doc, id, options) {
484
498
 
485
499
  insertElement(iframe, doc, 'body');
486
500
  setRenderSize(doc, width, height);
487
- insertElement(creativeComment, doc, 'html');
501
+ reinjectNodeIfRemoved(creativeComment, doc, 'html');
488
502
  callBurl(bid);
489
503
  emitAdRenderSucceeded({ doc, bid, id });
490
504
  } else {
@@ -175,13 +175,13 @@ describe('AdmanAdapter', function () {
175
175
  });
176
176
 
177
177
  describe('getUserSyncs', function () {
178
- let userSync = spec.getUserSyncs();
178
+ let userSync = spec.getUserSyncs({});
179
179
  it('Returns valid URL and type', function () {
180
180
  expect(userSync).to.be.an('array').with.lengthOf(1);
181
181
  expect(userSync[0].type).to.exist;
182
182
  expect(userSync[0].url).to.exist;
183
183
  expect(userSync[0].type).to.be.equal('image');
184
- expect(userSync[0].url).to.be.equal('https://pub.admanmedia.com/?c=o&m=sync');
184
+ expect(userSync[0].url).to.be.equal('https://pub.admanmedia.com/image?pbjs=1&coppa=0');
185
185
  });
186
186
  });
187
187
  });
@@ -1,5 +1,5 @@
1
1
  import adomikAnalytics from 'modules/adomikAnalyticsAdapter.js';
2
- import {expect} from 'chai';
2
+ import { expect } from 'chai';
3
3
 
4
4
  let events = require('src/events');
5
5
  let adapterManager = require('src/adapterManager').default;
@@ -73,6 +73,7 @@ describe('Adomik Prebid Analytic', function () {
73
73
  expect(adomikAnalytics.currentContext).to.deep.equal({
74
74
  uid: '123456',
75
75
  url: 'testurl',
76
+ sampling: undefined,
76
77
  testId: '12345',
77
78
  testValue: '1000',
78
79
  id: '',
@@ -85,6 +86,7 @@ describe('Adomik Prebid Analytic', function () {
85
86
  expect(adomikAnalytics.currentContext).to.deep.equal({
86
87
  uid: '123456',
87
88
  url: 'testurl',
89
+ sampling: undefined,
88
90
  testId: '12345',
89
91
  testValue: '1000',
90
92
  id: 'test-test-test',
@@ -0,0 +1,74 @@
1
+ import { adqueryIdSubmodule, storage } from 'modules/adqueryIdSystem.js';
2
+ import { server } from 'test/mocks/xhr.js';
3
+ import {amxIdSubmodule} from '../../../modules/amxIdSystem';
4
+ import * as utils from '../../../src/utils';
5
+
6
+ const config = {
7
+ storage: {
8
+ type: 'html5',
9
+ },
10
+ };
11
+
12
+ describe('AdqueryIdSystem', function () {
13
+ describe('qid submodule', () => {
14
+ it('should expose a "name" property containing qid', () => {
15
+ expect(adqueryIdSubmodule.name).to.equal('qid');
16
+ });
17
+
18
+ it('should expose a "gvlid" property containing the GVL ID 902', () => {
19
+ expect(adqueryIdSubmodule.gvlid).to.equal(902);
20
+ });
21
+ });
22
+
23
+ describe('getId', function() {
24
+ let getDataFromLocalStorageStub;
25
+
26
+ beforeEach(function() {
27
+ getDataFromLocalStorageStub = sinon.stub(storage, 'getDataFromLocalStorage');
28
+ });
29
+
30
+ afterEach(function () {
31
+ getDataFromLocalStorageStub.restore();
32
+ });
33
+
34
+ it('gets a adqueryId', function() {
35
+ const config = {
36
+ params: {}
37
+ };
38
+ const callbackSpy = sinon.spy();
39
+ const callback = adqueryIdSubmodule.getId(config).callback;
40
+ callback(callbackSpy);
41
+ const request = server.requests[0];
42
+ expect(request.url).to.eq(`https://bidder.adquery.io/prebid/qid`);
43
+ request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ qid: 'qid' }));
44
+ expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'qid'});
45
+ });
46
+
47
+ it('gets a cached adqueryId', function() {
48
+ const config = {
49
+ params: {}
50
+ };
51
+ getDataFromLocalStorageStub.withArgs('qid').returns('qid');
52
+
53
+ const callbackSpy = sinon.spy();
54
+ const callback = adqueryIdSubmodule.getId(config).callback;
55
+ callback(callbackSpy);
56
+ expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'qid'});
57
+ });
58
+
59
+ it('allows configurable id url', function() {
60
+ const config = {
61
+ params: {
62
+ url: 'https://bidder.adquery.io'
63
+ }
64
+ };
65
+ const callbackSpy = sinon.spy();
66
+ const callback = adqueryIdSubmodule.getId(config).callback;
67
+ callback(callbackSpy);
68
+ const request = server.requests[0];
69
+ expect(request.url).to.eq('https://bidder.adquery.io');
70
+ request.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({ qid: 'testqid' }));
71
+ expect(callbackSpy.lastCall.lastArg).to.deep.equal({qid: 'testqid'});
72
+ });
73
+ });
74
+ });
@@ -477,6 +477,8 @@ const testsBuildRequests = [
477
477
  refererInfo: getConfigBuildRequest('banner').refererInfo
478
478
  },
479
479
  data: {
480
+ gdpr: false,
481
+ gdpr_consent: '',
480
482
  height: 250,
481
483
  width: 300,
482
484
  keywords: '',