prebid.js 7.16.0 → 7.17.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 (131) hide show
  1. package/.circleci/config.yml +0 -18
  2. package/dist/1plusXRtdProvider.js +1 -1
  3. package/dist/33acrossBidAdapter.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.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/bidglassBidAdapter.js +1 -1
  18. package/dist/big-richmediaBidAdapter.js +1 -1
  19. package/dist/bridgewellBidAdapter.js +1 -1
  20. package/dist/brightMountainMediaBidAdapter.js +1 -1
  21. package/dist/carodaBidAdapter.js +1 -0
  22. package/dist/concertBidAdapter.js +1 -1
  23. package/dist/connectadBidAdapter.js +1 -1
  24. package/dist/consumableBidAdapter.js +1 -1
  25. package/dist/conversantBidAdapter.js +1 -1
  26. package/dist/craftBidAdapter.js +1 -1
  27. package/dist/criteoBidAdapter.js +1 -1
  28. package/dist/dspxBidAdapter.js +1 -1
  29. package/dist/eplanningBidAdapter.js +1 -1
  30. package/dist/finativeBidAdapter.js +1 -1
  31. package/dist/glimpseBidAdapter.js +1 -1
  32. package/dist/gmosspBidAdapter.js +1 -1
  33. package/dist/goldbachBidAdapter.js +1 -1
  34. package/dist/gridBidAdapter.js +1 -1
  35. package/dist/gridNMBidAdapter.js +1 -1
  36. package/dist/gumgumBidAdapter.js +1 -1
  37. package/dist/h12mediaBidAdapter.js +1 -1
  38. package/dist/id5IdSystem.js +1 -1
  39. package/dist/improvedigitalBidAdapter.js +1 -1
  40. package/dist/inmarBidAdapter.js +1 -1
  41. package/dist/insticatorBidAdapter.js +1 -1
  42. package/dist/ixBidAdapter.js +1 -1
  43. package/dist/justpremiumBidAdapter.js +1 -1
  44. package/dist/konduitAnalyticsAdapter.js +1 -1
  45. package/dist/kueezBidAdapter.js +1 -1
  46. package/dist/lassoBidAdapter.js +1 -1
  47. package/dist/lifestreetBidAdapter.js +1 -1
  48. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  49. package/dist/logicadBidAdapter.js +1 -1
  50. package/dist/loglyliftBidAdapter.js +1 -1
  51. package/dist/malltvAnalyticsAdapter.js +1 -1
  52. package/dist/marsmediaBidAdapter.js +1 -1
  53. package/dist/mediafuseBidAdapter.js +1 -1
  54. package/dist/mediagoBidAdapter.js +1 -1
  55. package/dist/mediasquareBidAdapter.js +1 -1
  56. package/dist/mgidBidAdapter.js +1 -1
  57. package/dist/minutemediaBidAdapter.js +1 -1
  58. package/dist/not-for-prod/prebid.js +108 -107
  59. package/dist/oguryBidAdapter.js +1 -1
  60. package/dist/onetagBidAdapter.js +1 -1
  61. package/dist/ooloAnalyticsAdapter.js +1 -1
  62. package/dist/outbrainBidAdapter.js +1 -1
  63. package/dist/parrableIdSystem.js +1 -1
  64. package/dist/pixfutureBidAdapter.js +1 -1
  65. package/dist/prebid-core.js +1 -1
  66. package/dist/publinkIdSystem.js +1 -1
  67. package/dist/pubmaticBidAdapter.js +1 -1
  68. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  69. package/dist/pxyzBidAdapter.js +1 -1
  70. package/dist/quantcastBidAdapter.js +1 -1
  71. package/dist/readpeakBidAdapter.js +1 -1
  72. package/dist/relaidoBidAdapter.js +1 -1
  73. package/dist/rhythmoneBidAdapter.js +1 -1
  74. package/dist/riseBidAdapter.js +1 -1
  75. package/dist/rubiconAnalyticsAdapter.js +1 -1
  76. package/dist/rubiconBidAdapter.js +1 -1
  77. package/dist/seedingAllianceBidAdapter.js +1 -1
  78. package/dist/seedtagBidAdapter.js +1 -1
  79. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  80. package/dist/sharethroughBidAdapter.js +1 -1
  81. package/dist/shinezBidAdapter.js +1 -1
  82. package/dist/smaatoBidAdapter.js +1 -1
  83. package/dist/smartadserverBidAdapter.js +1 -1
  84. package/dist/smartxBidAdapter.js +1 -1
  85. package/dist/smilewantedBidAdapter.js +1 -1
  86. package/dist/sonobiBidAdapter.js +1 -1
  87. package/dist/sovrnAnalyticsAdapter.js +1 -1
  88. package/dist/sovrnBidAdapter.js +1 -1
  89. package/dist/sspBCBidAdapter.js +1 -1
  90. package/dist/sublimeBidAdapter.js +1 -1
  91. package/dist/synacormediaBidAdapter.js +1 -1
  92. package/dist/targetVideoBidAdapter.js +1 -1
  93. package/dist/teadsBidAdapter.js +1 -1
  94. package/dist/trionBidAdapter.js +1 -1
  95. package/dist/tripleliftBidAdapter.js +1 -1
  96. package/dist/ttdBidAdapter.js +1 -1
  97. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  98. package/dist/underdogmediaBidAdapter.js +1 -1
  99. package/dist/undertoneBidAdapter.js +1 -1
  100. package/dist/vidazooBidAdapter.js +1 -1
  101. package/dist/videobyteBidAdapter.js +1 -1
  102. package/dist/visxBidAdapter.js +1 -1
  103. package/dist/vuukleBidAdapter.js +1 -1
  104. package/dist/widespaceBidAdapter.js +1 -1
  105. package/dist/winrBidAdapter.js +1 -1
  106. package/dist/yahoosspBidAdapter.js +1 -1
  107. package/dist/yieldmoBidAdapter.js +1 -1
  108. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  109. package/karma.conf.maker.js +2 -4
  110. package/modules/1plusXRtdProvider.js +27 -7
  111. package/modules/adagioBidAdapter.js +16 -2
  112. package/modules/adagioBidAdapter.md +11 -1
  113. package/modules/appnexusBidAdapter.js +24 -22
  114. package/modules/carodaBidAdapter.js +217 -0
  115. package/modules/carodaBidAdapter.md +43 -0
  116. package/modules/improvedigitalBidAdapter.js +3 -1
  117. package/modules/ixBidAdapter.js +17 -12
  118. package/modules/mediagoBidAdapter.js +15 -11
  119. package/modules/mediasquareBidAdapter.js +1 -1
  120. package/modules/rubiconAnalyticsAdapter.js +2 -2
  121. package/modules/rubiconBidAdapter.js +16 -6
  122. package/package.json +1 -1
  123. package/test/spec/modules/1plusXRtdProvider_spec.js +77 -1
  124. package/test/spec/modules/adagioBidAdapter_spec.js +23 -2
  125. package/test/spec/modules/appnexusBidAdapter_spec.js +76 -0
  126. package/test/spec/modules/carodaBidAdapter_spec.js +494 -0
  127. package/test/spec/modules/improvedigitalBidAdapter_spec.js +10 -0
  128. package/test/spec/modules/ixBidAdapter_spec.js +32 -16
  129. package/test/spec/modules/mediasquareBidAdapter_spec.js +2 -0
  130. package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +7 -7
  131. package/test/spec/modules/rubiconBidAdapter_spec.js +28 -35
@@ -57,16 +57,39 @@ export const extractConfig = (moduleConfig, reqBidsConfigObj) => {
57
57
  return { customerId, timeout, bidders };
58
58
  }
59
59
 
60
+ export const extractConsent = ({ gdpr }) => {
61
+ if (!gdpr) {
62
+ return null
63
+ }
64
+ const { gdprApplies, consentString } = gdpr
65
+ if (!(gdprApplies == '0' || gdprApplies == '1')) {
66
+ throw 'TCF Consent: gdprApplies has wrong format'
67
+ }
68
+ if (!(typeof consentString === 'string')) {
69
+ throw 'TCF Consent: consentString is not string'
70
+ }
71
+ const result = {
72
+ 'gdpr_applies': gdprApplies,
73
+ 'consent_string': consentString
74
+ }
75
+ return result
76
+ }
60
77
  /**
61
78
  * Gets the URL of Profile Api from which targeting data will be fetched
62
79
  * @param {Object} config
63
80
  * @param {string} config.customerId
64
81
  * @returns {string} URL to access 1plusX Profile API
65
82
  */
66
- const getPapiUrl = ({ customerId }) => {
83
+ export const getPapiUrl = (customerId, consent) => {
67
84
  // https://[yourClientId].profiles.tagger.opecloud.com/[VERSION]/targeting?url=
68
85
  const currentUrl = encodeURIComponent(window.location.href);
69
- const papiUrl = `https://${customerId}.profiles.tagger.opecloud.com/${PAPI_VERSION}/targeting?url=${currentUrl}`;
86
+ var papiUrl = `https://${customerId}.profiles.tagger.opecloud.com/${PAPI_VERSION}/targeting?url=${currentUrl}`;
87
+ if (consent) {
88
+ Object.entries(consent).forEach(([key, value]) => {
89
+ papiUrl += `&${key}=${value}`
90
+ })
91
+ }
92
+
70
93
  return papiUrl;
71
94
  }
72
95
 
@@ -216,14 +239,14 @@ const init = (config, userConsent) => {
216
239
  * @param {Object} reqBidsConfigObj Bid request configuration object
217
240
  * @param {Function} callback Called on completion
218
241
  * @param {Object} moduleConfig Configuration for 1plusX RTD module
219
- * @param {boolean} userConsent
242
+ * @param {Object} userConsent
220
243
  */
221
244
  const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, userConsent) => {
222
245
  try {
223
246
  // Get the required config
224
247
  const { customerId, bidders } = extractConfig(moduleConfig, reqBidsConfigObj);
225
248
  // Get PAPI URL
226
- const papiUrl = getPapiUrl({ customerId })
249
+ const papiUrl = getPapiUrl(customerId, extractConsent(userConsent) || {})
227
250
  // Call PAPI
228
251
  getTargetingDataFromPapi(papiUrl)
229
252
  .then((papiResponse) => {
@@ -231,9 +254,6 @@ const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, userConsent
231
254
  setTargetingDataToConfig(papiResponse, { bidders });
232
255
  callback();
233
256
  })
234
- .catch((error) => {
235
- throw error;
236
- })
237
257
  } catch (error) {
238
258
  logError(LOG_PREFIX, error);
239
259
  callback();
@@ -532,7 +532,12 @@ function _parseNativeBidResponse(bid) {
532
532
  native.impressionTrackers.push(tracker.url);
533
533
  break;
534
534
  case 2:
535
- native.javascriptTrackers = `<script src=\"${tracker.url}\"></script>`;
535
+ const script = `<script async src=\"${tracker.url}\"></script>`;
536
+ if (!native.javascriptTrackers) {
537
+ native.javascriptTrackers = script;
538
+ } else {
539
+ native.javascriptTrackers += `\n${script}`;
540
+ }
536
541
  break;
537
542
  }
538
543
  });
@@ -623,7 +628,16 @@ export function setExtraParam(bid, paramName) {
623
628
 
624
629
  const detected = adgGlobalConf[paramName] || deepAccess(ortb2Conf, `site.ext.data.${paramName}`, null);
625
630
  if (detected) {
626
- bid.params[paramName] = detected;
631
+ // First Party Data can be an array.
632
+ // As we consider that params detected from FPD are fallbacks, we just keep the 1st value.
633
+ if (Array.isArray(detected)) {
634
+ if (detected.length) {
635
+ bid.params[paramName] = detected[0].toString();
636
+ }
637
+ return;
638
+ }
639
+
640
+ bid.params[paramName] = detected.toString();
627
641
  }
628
642
  }
629
643
 
@@ -10,7 +10,7 @@ Connects to Adagio demand source to fetch bids.
10
10
 
11
11
  ## Configuration
12
12
 
13
- Adagio require several params. These params must be set at Prebid.js global config level or at adUnit level.
13
+ Adagio require several params. These params must be set at Prebid.js BidderConfig config level or at adUnit level.
14
14
 
15
15
  Below, the list of Adagio params and where they can be set.
16
16
 
@@ -58,6 +58,16 @@ pbjs.setConfig({
58
58
  });
59
59
  ```
60
60
 
61
+ #### Note on FPD support
62
+
63
+ Adagio will use FPD data as fallback for the params below:
64
+ - pagetype
65
+ - environment
66
+ - category
67
+ - subcategory
68
+
69
+ If the FPD value is an array, the 1st value of this array will be used.
70
+
61
71
  ### adUnit configuration
62
72
 
63
73
  ```javascript
@@ -250,10 +250,10 @@ export const spec = {
250
250
  // need to convert the string values into array of strings, to properly merge values with other existing keys later
251
251
  Object.keys(anAuctionKeywords).forEach(k => { if (isStr(anAuctionKeywords[k]) || isNumber(anAuctionKeywords[k])) anAuctionKeywords[k] = [anAuctionKeywords[k]] });
252
252
  // combine all sources of keywords (converted from string comma list to object format) into one object (that combines the values for shared keys)
253
- let mergedAuctionKeywrds = mergeDeep({}, anAuctionKeywords, ...ortb2KeywordsObjList);
253
+ let mergedAuctionKeywords = mergeDeep({}, anAuctionKeywords, ...ortb2KeywordsObjList);
254
254
 
255
255
  // convert to final format used by adserver
256
- let auctionKeywords = transformBidderParamKeywords(mergedAuctionKeywrds);
256
+ let auctionKeywords = transformBidderParamKeywords(mergedAuctionKeywords);
257
257
  if (auctionKeywords.length > 0) {
258
258
  auctionKeywords.forEach(deleteValues);
259
259
  payload.keywords = auctionKeywords;
@@ -1202,28 +1202,30 @@ function convertKeywordsToString(keywords) {
1202
1202
  function convertStringToKeywordsObj(keyStr) {
1203
1203
  let result = {};
1204
1204
 
1205
- // will split based on commas and will eat white space before/after the comma
1206
- let keywordList = keyStr.split(/\s*(?:,)\s*/);
1207
- keywordList.forEach(kw => {
1208
- // if = exists, then split
1209
- if (kw.indexOf('=') !== -1) {
1210
- let kwPair = kw.split('=');
1211
- let key = kwPair[0];
1212
- let val = kwPair[1];
1213
-
1214
- // then check for existing key in result > if so add value to the array > if not, add new key and create value array
1215
- if (result.hasOwnProperty(key)) {
1216
- result[key].push(val);
1205
+ if (isStr(keyStr) && keyStr !== '') {
1206
+ // will split based on commas and will eat white space before/after the comma
1207
+ let keywordList = keyStr.split(/\s*(?:,)\s*/);
1208
+ keywordList.forEach(kw => {
1209
+ // if = exists, then split
1210
+ if (kw.indexOf('=') !== -1) {
1211
+ let kwPair = kw.split('=');
1212
+ let key = kwPair[0];
1213
+ let val = kwPair[1];
1214
+
1215
+ // then check for existing key in result > if so add value to the array > if not, add new key and create value array
1216
+ if (result.hasOwnProperty(key)) {
1217
+ result[key].push(val);
1218
+ } else {
1219
+ result[key] = [val];
1220
+ }
1217
1221
  } else {
1218
- result[key] = [val];
1219
- }
1220
- } else {
1221
- // make a key with '' value; if key already exists > don't add
1222
- if (!result.hasOwnProperty(kw)) {
1223
- result[kw] = [''];
1222
+ // make a key with '' value; if key already exists > don't add
1223
+ if (!result.hasOwnProperty(kw)) {
1224
+ result[kw] = [''];
1225
+ }
1224
1226
  }
1225
- }
1226
- });
1227
+ });
1228
+ }
1227
1229
 
1228
1230
  return result;
1229
1231
  }
@@ -0,0 +1,217 @@
1
+ // jshint esversion: 6, es3: false, node: true
2
+ 'use strict'
3
+
4
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
5
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
6
+ import {
7
+ deepAccess,
8
+ deepSetValue,
9
+ logError,
10
+ mergeDeep,
11
+ parseSizesInput
12
+ } from '../src/utils.js';
13
+ import { config } from '../src/config.js';
14
+
15
+ const { getConfig } = config;
16
+
17
+ const BIDDER_CODE = 'caroda';
18
+ const GVLID = 954;
19
+
20
+ // some state info is required to synchronize with Caroda ad server
21
+ const topUsableWindow = getTopUsableWindow();
22
+
23
+ export const spec = {
24
+ code: BIDDER_CODE,
25
+ gvlid: GVLID,
26
+ supportedMediaTypes: [BANNER, VIDEO],
27
+ isBidRequestValid: bid => {
28
+ const params = bid.params || {};
29
+ const { ctok, placementId, priceType } = params;
30
+ return typeof ctok === 'string' && (
31
+ typeof placementId === 'string' ||
32
+ typeof placementId === 'undefined'
33
+ ) && (
34
+ typeof priceType === 'undefined' ||
35
+ priceType === 'gross' ||
36
+ priceType === 'net'
37
+ );
38
+ },
39
+ buildRequests: (validBidRequests, bidderRequest) => {
40
+ topUsableWindow.carodaPageViewId = topUsableWindow.carodaPageViewId || Math.floor(Math.random() * 1e9);
41
+ const pageViewId = topUsableWindow.carodaPageViewId;
42
+ const ortbCommon = getORTBCommon(bidderRequest);
43
+ const priceType =
44
+ getFirstWithKey(validBidRequests, 'params.priceType') ||
45
+ 'net';
46
+ const test = getFirstWithKey(validBidRequests, 'params.test');
47
+ const currency = getConfig('currency.adServerCurrency');
48
+ const eids = getFirstWithKey(validBidRequests, 'userIdAsEids');
49
+ const schain = getFirstWithKey(validBidRequests, 'schain');
50
+ const request = {
51
+ auctionId: bidderRequest.auctionId,
52
+ currency,
53
+ hb_version: '$prebid.version$',
54
+ ...ortbCommon,
55
+ price_type: priceType
56
+ };
57
+ if (test) {
58
+ request.test = 1;
59
+ }
60
+ if (schain) {
61
+ request.schain = schain;
62
+ }
63
+ if (config.getConfig('coppa')) {
64
+ deepSetValue(request, 'privacy.coppa', 1);
65
+ }
66
+ if (deepAccess(bidderRequest, 'gdprConsent.gdprApplies') !== undefined) {
67
+ deepSetValue(
68
+ request,
69
+ 'privacy.gdpr_consent',
70
+ bidderRequest.gdprConsent.consentString
71
+ );
72
+ deepSetValue(
73
+ request,
74
+ 'privacy.gdpr',
75
+ bidderRequest.gdprConsent.gdprApplies & 1
76
+ );
77
+ }
78
+ if (bidderRequest.uspConsent) {
79
+ deepSetValue(request, 'privacy.us_privacy', bidderRequest.uspConsent);
80
+ }
81
+ if (eids) {
82
+ deepSetValue(request, 'user.eids', eids);
83
+ }
84
+ return getImps(validBidRequests, request).map(imp => ({
85
+ method: 'POST',
86
+ url: 'https://prebid.caroda.io/api/hb?entry_id=' + pageViewId,
87
+ data: JSON.stringify(imp)
88
+ }));
89
+ },
90
+ interpretResponse: (serverResponse) => {
91
+ if (!serverResponse.body) {
92
+ return;
93
+ }
94
+ const { ok, error } = serverResponse.body
95
+ if (error) {
96
+ logError(BIDDER_CODE, ': server caught', error.message);
97
+ return;
98
+ }
99
+ try {
100
+ return JSON.parse(ok.value)
101
+ .map((bid) => {
102
+ const ret = {
103
+ requestId: bid.bid_id,
104
+ cpm: bid.cpm,
105
+ creativeId: bid.creative_id,
106
+ ttl: 300,
107
+ netRevenue: true,
108
+ currency: bid.currency,
109
+ width: bid.w,
110
+ height: bid.h,
111
+ meta: {
112
+ advertiserDomains: bid.adomain || []
113
+ },
114
+ ad: bid.ad,
115
+ placementId: bid.placement_id
116
+ }
117
+ if (bid.adserver_targeting) {
118
+ ret.adserverTargeting = bid.adserver_targeting
119
+ }
120
+ return ret
121
+ })
122
+ .filter(Boolean);
123
+ } catch (e) {
124
+ logError(BIDDER_CODE, ': caught', e);
125
+ }
126
+ }
127
+ }
128
+
129
+ registerBidder(spec)
130
+
131
+ function getFirstWithKey (collection, key) {
132
+ for (let i = 0, result; i < collection.length; i++) {
133
+ result = deepAccess(collection[i], key);
134
+ if (result) {
135
+ return result;
136
+ }
137
+ }
138
+ }
139
+
140
+ function getTopUsableWindow () {
141
+ let res = window;
142
+ try {
143
+ while (window.top !== res && res.parent.location.href.length) {
144
+ res = res.parent;
145
+ }
146
+ } catch (e) {}
147
+ return res;
148
+ }
149
+
150
+ function getORTBCommon (bidderRequest) {
151
+ let app, site;
152
+ const commonFpd = bidderRequest.ortb2 || {};
153
+ let { user } = commonFpd;
154
+ if (typeof getConfig('app') === 'object') {
155
+ app = getConfig('app') || {}
156
+ if (commonFpd.app) {
157
+ mergeDeep(app, commonFpd.app);
158
+ }
159
+ } else {
160
+ site = getConfig('site') || {};
161
+ if (commonFpd.site) {
162
+ mergeDeep(site, commonFpd.site);
163
+ }
164
+ if (!site.page) {
165
+ site.page = bidderRequest.refererInfo.page;
166
+ }
167
+ }
168
+ const device = getConfig('device') || {};
169
+ device.w = device.w || window.innerWidth;
170
+ device.h = device.h || window.innerHeight;
171
+ device.ua = device.ua || navigator.userAgent;
172
+ return {
173
+ app,
174
+ site,
175
+ user,
176
+ device
177
+ };
178
+ }
179
+
180
+ function getImps (validBidRequests, common) {
181
+ return validBidRequests.map((bid) => {
182
+ const floorInfo = bid.getFloor
183
+ ? bid.getFloor({ currency: common.currency || 'EUR' })
184
+ : {};
185
+ const bidfloor = floorInfo.floor;
186
+ const bidfloorcur = floorInfo.currency;
187
+ const { ctok, placementId } = bid.params;
188
+ const imp = {
189
+ bid_id: bid.bidId,
190
+ ctok,
191
+ bidfloor,
192
+ bidfloorcur,
193
+ ...common
194
+ };
195
+ const bannerParams = deepAccess(bid, 'mediaTypes.banner');
196
+ if (bannerParams && bannerParams.sizes) {
197
+ const sizes = parseSizesInput(bannerParams.sizes);
198
+ const format = sizes.map(size => {
199
+ const [width, height] = size.split('x');
200
+ const w = parseInt(width, 10);
201
+ const h = parseInt(height, 10);
202
+ return { w, h };
203
+ });
204
+ imp.banner = {
205
+ format
206
+ };
207
+ }
208
+ if (placementId) {
209
+ imp.placement_id = placementId;
210
+ }
211
+ const videoParams = deepAccess(bid, 'mediaTypes.video');
212
+ if (videoParams) {
213
+ imp.video = videoParams;
214
+ }
215
+ return imp;
216
+ })
217
+ }
@@ -0,0 +1,43 @@
1
+ # Overview
2
+
3
+ Module Name: Caroda Adapter
4
+ Module Type: Bidder Adapter
5
+ Maintainer: dev@caroda.io
6
+
7
+ # Description
8
+
9
+ Module that connects to Caroda demand sources to fetch bids.
10
+ Banner and video formats are supported.
11
+ Use `caroda` as bidder.
12
+
13
+ # Test Parameters
14
+ ```
15
+ var adUnits = [{
16
+ code: '/19968336/prebid_banner_example_1',
17
+ mediaTypes: {
18
+ banner: {
19
+ sizes: [[ 300, 250 ]]
20
+ }
21
+ }
22
+ bids: [{
23
+ bidder: 'caroda',
24
+ params: {
25
+ ctok: '230ce9490c5434354'
26
+ }
27
+ }]
28
+ }, {
29
+ code: '/19968336/prebid_video_example_1',
30
+ mediaTypes: {
31
+ video: {
32
+ context: 'outstream',
33
+ mimes: ['video/mp4']
34
+ }
35
+ }
36
+ bids: [{
37
+ bidder: 'caroda',
38
+ params: {
39
+ ctok: '230ce9490c5434354'
40
+ }
41
+ }]
42
+ }];
43
+ ```
@@ -25,6 +25,7 @@ const BIDDER_CODE = 'improvedigital';
25
25
  const CREATIVE_TTL = 300;
26
26
 
27
27
  const AD_SERVER_URL = 'https://ad.360yield.com/pb';
28
+ const BASIC_ADS_URL = 'https://ad.360yield-basic.com/pb';
28
29
  const EXTEND_URL = 'https://pbs.360yield.com/openrtb2/auction';
29
30
  const IFRAME_SYNC_URL = 'https://hb.360yield.com/prebid-universal-creative/load-cookie.html';
30
31
 
@@ -282,9 +283,10 @@ const ID_REQUEST = {
282
283
  if (transactionId) {
283
284
  deepSetValue(request, 'source.tid', transactionId);
284
285
  }
286
+ const adServerUrl = hasPurpose1Consent(bidderRequest?.gdprConsent) ? AD_SERVER_URL : BASIC_ADS_URL;
285
287
  return {
286
288
  method: 'POST',
287
- url: extendMode ? EXTEND_URL : AD_SERVER_URL,
289
+ url: extendMode ? EXTEND_URL : adServerUrl,
288
290
  data: JSON.stringify(request),
289
291
  bidderRequest
290
292
  }
@@ -13,7 +13,6 @@ import {
13
13
  logError,
14
14
  logWarn,
15
15
  mergeDeep,
16
- parseGPTSingleSizeArray,
17
16
  parseQueryStringParameters
18
17
  } from '../src/utils.js';
19
18
  import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js';
@@ -127,10 +126,6 @@ function bidToBannerImp(bid) {
127
126
  if (impSize) {
128
127
  imp.banner.w = impSize[0];
129
128
  imp.banner.h = impSize[1];
130
- // populate sid with size if not id
131
- if (!deepAccess(imp, 'ext.sid')) {
132
- imp.ext.sid = parseGPTSingleSizeArray(impSize);
133
- }
134
129
  }
135
130
 
136
131
  imp.banner.topframe = inIframe() ? 0 : 1;
@@ -197,9 +192,6 @@ function bidToVideoImp(bid) {
197
192
  if (impSize) {
198
193
  imp.video.w = impSize[0];
199
194
  imp.video.h = impSize[1];
200
- if (!(deepAccess(imp, 'ext.sid'))) {
201
- imp.ext.sid = parseGPTSingleSizeArray(impSize);
202
- }
203
195
  } else {
204
196
  logWarn('IX Bid Adapter: Video size is missing in [mediaTypes.video]');
205
197
  return {};
@@ -253,8 +245,8 @@ function bidToImp(bid) {
253
245
  imp.ext = {};
254
246
  imp.ext.siteID = bid.params.siteId.toString();
255
247
 
256
- if (bid.params.hasOwnProperty('id') &&
257
- (typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) {
248
+ // populate imp level sid
249
+ if (bid.params.hasOwnProperty('id') && (typeof bid.params.id === 'string' || typeof bid.params.id === 'number')) {
258
250
  imp.ext.sid = String(bid.params.id);
259
251
  }
260
252
 
@@ -758,6 +750,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
758
750
  const gpid = impressions[transactionIds[adUnitIndex]].gpid;
759
751
  const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code;
760
752
  const tid = impressions[transactionIds[adUnitIndex]].tid;
753
+ const sid = impressions[transactionIds[adUnitIndex]].sid
761
754
 
762
755
  if (impressionObjects.length && BANNER in impressionObjects[0]) {
763
756
  const { id, banner: { topframe } } = impressionObjects[0];
@@ -769,16 +762,24 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
769
762
  },
770
763
  };
771
764
 
765
+ // We add sid in imp.ext.sid therefore, remove from banner.format[].ext
766
+ for (let bannerFormat of _bannerImpression.banner.format) {
767
+ if (bannerFormat.ext != null && bannerFormat.ext.sid != null) {
768
+ delete bannerFormat.ext.sid;
769
+ }
770
+ }
771
+
772
772
  const position = impressions[transactionIds[adUnitIndex]].pos;
773
773
  if (isInteger(position)) {
774
774
  _bannerImpression.banner.pos = position;
775
775
  }
776
776
 
777
- if (dfpAdUnitCode || gpid || tid) {
777
+ if (dfpAdUnitCode || gpid || tid || sid) {
778
778
  _bannerImpression.ext = {};
779
779
  _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode;
780
780
  _bannerImpression.ext.gpid = gpid;
781
781
  _bannerImpression.ext.tid = tid;
782
+ _bannerImpression.ext.sid = sid;
782
783
  }
783
784
 
784
785
  if ('bidfloor' in impressionObjects[0]) {
@@ -1040,6 +1041,11 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps) {
1040
1041
  bannerImps[validBidRequest.transactionId].tagId = deepAccess(validBidRequest, 'params.tagId');
1041
1042
  bannerImps[validBidRequest.transactionId].pos = deepAccess(validBidRequest, 'mediaTypes.banner.pos');
1042
1043
 
1044
+ const sid = deepAccess(validBidRequest, 'params.id');
1045
+ if (sid && (typeof sid === 'string' || typeof sid === 'number')) {
1046
+ bannerImps[validBidRequest.transactionId].sid = String(sid);
1047
+ }
1048
+
1043
1049
  const adUnitCode = validBidRequest.adUnitCode;
1044
1050
  const divId = document.getElementById(adUnitCode) ? adUnitCode : getGptSlotInfoForAdUnitCode(adUnitCode).divId;
1045
1051
  bannerImps[validBidRequest.transactionId].adUnitCode = adUnitCode;
@@ -1094,7 +1100,6 @@ function updateMissingSizes(validBidRequest, missingBannerSizes, imp) {
1094
1100
  */
1095
1101
  function createMissingBannerImp(bid, imp, newSize) {
1096
1102
  const newImp = deepClone(imp);
1097
- newImp.ext.sid = parseGPTSingleSizeArray(newSize);
1098
1103
  newImp.banner.w = newSize[0];
1099
1104
  newImp.banner.h = newSize[1];
1100
1105
 
@@ -293,14 +293,19 @@ function getItems(validBidRequests, bidderRequest) {
293
293
  */
294
294
  function getParam(validBidRequests, bidderRequest) {
295
295
  const pubcid = utils.deepAccess(validBidRequests[0], 'crumbs.pubcid');
296
- // console.log('wjh getParam', validBidRequests, bidderRequest);
296
+ const sharedid =
297
+ utils.deepAccess(validBidRequests[0], 'userId.sharedid.id') ||
298
+ utils.deepAccess(validBidRequests[0], 'userId.pubcid');
297
299
  let isMobile = isMobileAndTablet() ? 1 : 0;
298
300
  let isTest = 0;
299
301
  let auctionId = getProperty(bidderRequest, 'auctionId');
300
302
  let items = getItems(validBidRequests, bidderRequest);
301
303
 
302
- const domain = document.domain;
303
- const location = utils.deepAccess(bidderRequest, 'refererInfo.referer');
304
+ const domain =
305
+ utils.deepAccess(bidderRequest, 'refererInfo.domain') || document.domain;
306
+ const location = utils.deepAccess(bidderRequest, 'refererInfo.location');
307
+ const page = utils.deepAccess(bidderRequest, 'refererInfo.page');
308
+ const referer = utils.deepAccess(bidderRequest, 'refererInfo.ref');
304
309
 
305
310
  const timeout = bidderRequest.timeout || 2000;
306
311
 
@@ -323,14 +328,13 @@ function getParam(validBidRequests, bidderRequest) {
323
328
  },
324
329
  ext: {},
325
330
  user: {
326
- buyeruid: getUserID(),
327
- id: pubcid,
331
+ id: sharedid || pubcid || getUserID(),
328
332
  },
329
333
  site: {
330
334
  name: domain,
331
335
  domain: domain,
332
- page: location,
333
- ref: location,
336
+ page: page || location,
337
+ ref: referer,
334
338
  mobile: isMobile,
335
339
  cat: [], // todo
336
340
  publisher: {
@@ -454,9 +458,9 @@ export const spec = {
454
458
  * Register bidder specific code, which will execute when the adserver targeting has been set for a bid from this bidder
455
459
  * @param {Bid} The bid of which the targeting has been set
456
460
  */
457
- // onSetTargeting: function (bid) {
458
- // // console.log('onSetTargeting', bid);
459
- // // Bidder specific code
460
- // },
461
+ // onSetTargeting: function (bid) {
462
+ // // console.log('onSetTargeting', bid);
463
+ // // Bidder specific code
464
+ // },
461
465
  };
462
466
  registerBidder(spec);
@@ -164,7 +164,7 @@ export const spec = {
164
164
  // fires a pixel to confirm a winning bid
165
165
  let params = {'pbjs': '$prebid.version$'};
166
166
  let endpoint = document.location.search.match(/msq_test=true/) ? BIDDER_URL_TEST : BIDDER_URL_PROD;
167
- let paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond', 'requestId', 'auctionId']
167
+ let paramsToSearchFor = ['cpm', 'size', 'mediaType', 'currency', 'creativeId', 'adUnitCode', 'timeToRespond', 'requestId', 'auctionId', 'originalCpm', 'originalCurrency'];
168
168
  if (bid.hasOwnProperty('mediasquare')) {
169
169
  if (bid['mediasquare'].hasOwnProperty('bidder')) { params['bidder'] = bid['mediasquare']['bidder']; }
170
170
  if (bid['mediasquare'].hasOwnProperty('code')) { params['code'] = bid['mediasquare']['code']; }
@@ -124,9 +124,9 @@ function formatSource(src) {
124
124
  }
125
125
 
126
126
  function getBillingPayload(event) {
127
- // for now we are mapping all events to type "general", later we will expand support for specific types
128
127
  let billingEvent = deepClone(event);
129
- billingEvent.type = 'general';
128
+ // Pass along type if is string and not empty else general
129
+ billingEvent.type = (typeof event.type === 'string' && event.type) || 'general';
130
130
  billingEvent.accountId = accountId;
131
131
  // mark as sent
132
132
  deepSetValue(cache.billing, `${event.vendor}.${event.billingId}`, true);