prebid.js 8.7.0 → 8.8.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 (187) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/a1MediaRtdProvider.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/admaticBidAdapter.js +1 -1
  8. package/dist/adqueryBidAdapter.js +1 -1
  9. package/dist/adqueryIdSystem.js +1 -1
  10. package/dist/adrelevantisBidAdapter.js +1 -1
  11. package/dist/adtrgtmeBidAdapter.js +1 -1
  12. package/dist/adxcgBidAdapter.js +1 -1
  13. package/dist/adyoulikeBidAdapter.js +1 -1
  14. package/dist/ajaBidAdapter.js +1 -1
  15. package/dist/amxBidAdapter.js +1 -1
  16. package/dist/amxIdSystem.js +1 -1
  17. package/dist/appierAnalyticsAdapter.js +1 -1
  18. package/dist/appnexusBidAdapter.js +1 -1
  19. package/dist/asoBidAdapter.js +1 -1
  20. package/dist/axonixBidAdapter.js +1 -1
  21. package/dist/bidViewability.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/big-richmediaBidAdapter.js +1 -1
  24. package/dist/brandmetricsRtdProvider.js +1 -1
  25. package/dist/bridBidAdapter.js +1 -1
  26. package/dist/bridgewellBidAdapter.js +1 -1
  27. package/dist/brightMountainMediaBidAdapter.js +1 -1
  28. package/dist/carodaBidAdapter.js +1 -1
  29. package/dist/chtnwBidAdapter.js +1 -1
  30. package/dist/concertBidAdapter.js +1 -1
  31. package/dist/connectadBidAdapter.js +1 -1
  32. package/dist/consumableBidAdapter.js +1 -1
  33. package/dist/conversantAnalyticsAdapter.js +1 -1
  34. package/dist/conversantBidAdapter.js +1 -1
  35. package/dist/craftBidAdapter.js +1 -1
  36. package/dist/criteoBidAdapter.js +1 -1
  37. package/dist/cwireBidAdapter.js +1 -1
  38. package/dist/dependencies.json +4 -1
  39. package/dist/dspxBidAdapter.js +1 -1
  40. package/dist/eplanningBidAdapter.js +1 -1
  41. package/dist/euidIdSystem.js +1 -1
  42. package/dist/feedadBidAdapter.js +1 -1
  43. package/dist/finativeBidAdapter.js +1 -1
  44. package/dist/freewheel-sspBidAdapter.js +1 -1
  45. package/dist/geoedgeRtdProvider.js +1 -1
  46. package/dist/gmosspBidAdapter.js +1 -1
  47. package/dist/goldbachBidAdapter.js +1 -1
  48. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  49. package/dist/greenbidsRtdProvider.js +1 -1
  50. package/dist/gridBidAdapter.js +1 -1
  51. package/dist/gumgumBidAdapter.js +1 -1
  52. package/dist/h12mediaBidAdapter.js +1 -1
  53. package/dist/hypelabBidAdapter.js +1 -1
  54. package/dist/id5IdSystem.js +1 -1
  55. package/dist/imdsBidAdapter.js +1 -1
  56. package/dist/improvedigitalBidAdapter.js +1 -1
  57. package/dist/insticatorBidAdapter.js +1 -1
  58. package/dist/ixBidAdapter.js +1 -1
  59. package/dist/justpremiumBidAdapter.js +1 -1
  60. package/dist/kargoBidAdapter.js +1 -1
  61. package/dist/konduitAnalyticsAdapter.js +1 -1
  62. package/dist/kueezBidAdapter.js +1 -1
  63. package/dist/kueezRtbBidAdapter.js +1 -1
  64. package/dist/kulturemediaBidAdapter.js +1 -1
  65. package/dist/lassoBidAdapter.js +1 -1
  66. package/dist/lifestreetBidAdapter.js +1 -1
  67. package/dist/liveIntentIdSystem.js +1 -1
  68. package/dist/logicadBidAdapter.js +1 -1
  69. package/dist/loglyliftBidAdapter.js +1 -1
  70. package/dist/magniteAnalyticsAdapter.js +1 -1
  71. package/dist/malltvAnalyticsAdapter.js +1 -1
  72. package/dist/marsmediaBidAdapter.js +1 -1
  73. package/dist/mediafuseBidAdapter.js +1 -1
  74. package/dist/mediasquareBidAdapter.js +1 -1
  75. package/dist/mgidBidAdapter.js +1 -1
  76. package/dist/minutemediaBidAdapter.js +1 -1
  77. package/dist/minutemediaplusBidAdapter.js +1 -1
  78. package/dist/nativoBidAdapter.js +1 -1
  79. package/dist/nexx360BidAdapter.js +1 -1
  80. package/dist/not-for-prod/prebid.js +138 -137
  81. package/dist/oguryBidAdapter.js +1 -1
  82. package/dist/onetagBidAdapter.js +1 -1
  83. package/dist/ooloAnalyticsAdapter.js +1 -1
  84. package/dist/operaadsBidAdapter.js +1 -1
  85. package/dist/operaadsIdSystem.js +1 -0
  86. package/dist/optidigitalBidAdapter.js +1 -1
  87. package/dist/outbrainBidAdapter.js +1 -1
  88. package/dist/oxxionAnalyticsAdapter.js +1 -1
  89. package/dist/parrableIdSystem.js +1 -1
  90. package/dist/pixfutureBidAdapter.js +1 -1
  91. package/dist/prebid-core.js +1 -1
  92. package/dist/publinkIdSystem.js +1 -1
  93. package/dist/pubmaticBidAdapter.js +1 -1
  94. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  95. package/dist/pxyzBidAdapter.js +1 -1
  96. package/dist/quantcastBidAdapter.js +1 -1
  97. package/dist/readpeakBidAdapter.js +1 -1
  98. package/dist/relaidoBidAdapter.js +1 -1
  99. package/dist/retailspotBidAdapter.js +1 -1
  100. package/dist/rhythmoneBidAdapter.js +1 -1
  101. package/dist/riseBidAdapter.js +1 -1
  102. package/dist/rubiconBidAdapter.js +1 -1
  103. package/dist/seedingAllianceBidAdapter.js +1 -1
  104. package/dist/seedtagBidAdapter.js +1 -1
  105. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  106. package/dist/sharethroughBidAdapter.js +1 -1
  107. package/dist/shinezBidAdapter.js +1 -1
  108. package/dist/smaatoBidAdapter.js +1 -1
  109. package/dist/smartadserverBidAdapter.js +1 -1
  110. package/dist/smartxBidAdapter.js +1 -1
  111. package/dist/smartyadsBidAdapter.js +1 -1
  112. package/dist/smilewantedBidAdapter.js +1 -1
  113. package/dist/snigelBidAdapter.js +1 -1
  114. package/dist/sonobiBidAdapter.js +1 -1
  115. package/dist/sovrnAnalyticsAdapter.js +1 -1
  116. package/dist/sovrnBidAdapter.js +1 -1
  117. package/dist/sspBCBidAdapter.js +1 -1
  118. package/dist/stvBidAdapter.js +1 -1
  119. package/dist/sublimeBidAdapter.js +1 -1
  120. package/dist/targetVideoBidAdapter.js +1 -1
  121. package/dist/teadsBidAdapter.js +1 -1
  122. package/dist/topicsFpdModule.js +1 -1
  123. package/dist/trionBidAdapter.js +1 -1
  124. package/dist/tripleliftBidAdapter.js +1 -1
  125. package/dist/ttdBidAdapter.js +1 -1
  126. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  127. package/dist/uid2IdSystem.js +1 -1
  128. package/dist/underdogmediaBidAdapter.js +1 -1
  129. package/dist/undertoneBidAdapter.js +1 -1
  130. package/dist/vidazooBidAdapter.js +1 -1
  131. package/dist/videobyteBidAdapter.js +1 -1
  132. package/dist/visxBidAdapter.js +1 -1
  133. package/dist/vuukleBidAdapter.js +1 -1
  134. package/dist/widespaceBidAdapter.js +1 -1
  135. package/dist/winrBidAdapter.js +1 -1
  136. package/dist/yahoosspBidAdapter.js +1 -1
  137. package/dist/yieldmoBidAdapter.js +1 -1
  138. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  139. package/integrationExamples/topics/topics-server.js +72 -0
  140. package/modules/.submodules.json +2 -1
  141. package/modules/a1MediaRtdProvider.js +1 -1
  142. package/modules/admaticBidAdapter.js +5 -0
  143. package/modules/adqueryBidAdapter.js +23 -21
  144. package/modules/adqueryIdSystem.js +45 -30
  145. package/modules/adrelevantisBidAdapter.js +2 -0
  146. package/modules/bidViewability.js +7 -0
  147. package/modules/bidViewability.md +9 -8
  148. package/modules/brandmetricsRtdProvider.js +30 -27
  149. package/modules/criteoBidAdapter.js +66 -43
  150. package/modules/geoedgeRtdProvider.js +43 -13
  151. package/modules/geoedgeRtdProvider.md +2 -1
  152. package/modules/liveIntentIdSystem.js +16 -1
  153. package/modules/nativoBidAdapter.js +21 -3
  154. package/modules/onetagBidAdapter.js +3 -0
  155. package/modules/operaadsBidAdapter.js +5 -0
  156. package/modules/operaadsBidAdapter.md +5 -5
  157. package/modules/operaadsIdSystem.js +106 -0
  158. package/modules/operaadsIdSystem.md +52 -0
  159. package/modules/oxxionAnalyticsAdapter.js +22 -5
  160. package/modules/rubiconBidAdapter.js +2 -2
  161. package/modules/smartyadsBidAdapter.js +18 -1
  162. package/modules/snigelBidAdapter.js +69 -16
  163. package/modules/snigelBidAdapter.md +9 -3
  164. package/modules/topicsFpdModule.js +35 -9
  165. package/modules/visxBidAdapter.js +51 -1
  166. package/package.json +2 -2
  167. package/src/adloader.js +1 -0
  168. package/src/native.js +2 -2
  169. package/test/spec/modules/admaticBidAdapter_spec.js +5 -0
  170. package/test/spec/modules/adqueryIdSystem_spec.js +13 -24
  171. package/test/spec/modules/bidViewability_spec.js +32 -1
  172. package/test/spec/modules/brandmetricsRtdProvider_spec.js +6 -0
  173. package/test/spec/modules/criteoBidAdapter_spec.js +228 -0
  174. package/test/spec/modules/eids_spec.js +48 -0
  175. package/test/spec/modules/geoedgeRtdProvider_spec.js +44 -24
  176. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
  177. package/test/spec/modules/liveIntentIdSystem_spec.js +5 -0
  178. package/test/spec/modules/nativoBidAdapter_spec.js +6 -1
  179. package/test/spec/modules/onetagBidAdapter_spec.js +69 -0
  180. package/test/spec/modules/operaadsIdSystem_spec.js +53 -0
  181. package/test/spec/modules/oxxionAnalyticsAdapter_spec.js +6 -1
  182. package/test/spec/modules/rubiconBidAdapter_spec.js +24 -0
  183. package/test/spec/modules/smartyadsBidAdapter_spec.js +49 -0
  184. package/test/spec/modules/snigelBidAdapter_spec.js +57 -6
  185. package/test/spec/modules/topicsFpdModule_spec.js +102 -1
  186. package/test/spec/modules/visxBidAdapter_spec.js +151 -1
  187. package/test/spec/native_spec.js +5 -3
@@ -20,6 +20,8 @@ import { ajax } from '../src/ajax.js';
20
20
  import { generateUUID, insertElement, isEmpty, logError } from '../src/utils.js';
21
21
  import * as events from '../src/events.js';
22
22
  import CONSTANTS from '../src/constants.json';
23
+ import { loadExternalScript } from '../src/adloader.js';
24
+ import { auctionManager } from '../src/auctionManager.js';
23
25
 
24
26
  /** @type {string} */
25
27
  const SUBMODULE_NAME = 'geoedge';
@@ -33,9 +35,13 @@ const PV_ID = generateUUID();
33
35
  /** @type {string} */
34
36
  const HOST_NAME = 'https://rumcdn.geoedge.be';
35
37
  /** @type {string} */
36
- const FILE_NAME = 'grumi.js';
38
+ const FILE_NAME_CLIENT = 'grumi.js';
39
+ /** @type {string} */
40
+ const FILE_NAME_INPAGE = 'grumi-ip.js';
41
+ /** @type {function} */
42
+ export let getClientUrl = (key) => `${HOST_NAME}/${key}/${FILE_NAME_CLIENT}`;
37
43
  /** @type {function} */
38
- export let getClientUrl = (key) => `${HOST_NAME}/${key}/${FILE_NAME}`;
44
+ export let getInPageUrl = (key) => `${HOST_NAME}/${key}/${FILE_NAME_INPAGE}`;
39
45
  /** @type {string} */
40
46
  export let wrapper
41
47
  /** @type {boolean} */;
@@ -177,7 +183,8 @@ function isSupportedBidder(bidder, paramsBidders) {
177
183
  function shouldWrap(bid, params) {
178
184
  let supportedBidder = isSupportedBidder(bid.bidderCode, params.bidders);
179
185
  let donePreload = params.wap ? preloaded : true;
180
- return wrapperReady && supportedBidder && donePreload;
186
+ let isGPT = params.gpt;
187
+ return wrapperReady && supportedBidder && donePreload && !isGPT;
181
188
  }
182
189
 
183
190
  function conditionallyWrap(bidResponse, config, userConsent) {
@@ -187,31 +194,55 @@ function conditionallyWrap(bidResponse, config, userConsent) {
187
194
  }
188
195
  }
189
196
 
197
+ function isBillingMessage(data, params) {
198
+ return data.key === params.key && data.impression;
199
+ }
200
+
190
201
  /**
191
- * Fire billable events for applicable bids
202
+ * Fire billable events when our client sends a message
203
+ * Messages will be sent only when:
204
+ * a. applicable bids are wrapped
205
+ * b. our code laoded and executed sucesfully
192
206
  */
193
207
  function fireBillableEventsForApplicableBids(params) {
194
- events.on(CONSTANTS.EVENTS.BID_WON, function (winningBid) {
195
- if (shouldWrap(winningBid, params)) {
208
+ window.addEventListener('message', function (message) {
209
+ let data = message.data;
210
+ if (isBillingMessage(data, params)) {
211
+ let winningBid = auctionManager.findBidByAdId(data.adId);
196
212
  events.emit(CONSTANTS.EVENTS.BILLABLE_EVENT, {
197
213
  vendor: SUBMODULE_NAME,
198
- billingId: generateUUID(),
199
- type: 'impression',
200
- transactionId: winningBid.transactionId,
201
- auctionId: winningBid.auctionId,
202
- bidId: winningBid.requestId
214
+ billingId: data.impressionId,
215
+ type: winningBid ? 'impression' : data.type,
216
+ transactionId: winningBid?.transactionId || data.transactionId,
217
+ auctionId: winningBid?.auctionId || data.auctionId,
218
+ bidId: winningBid?.requestId || data.requestId
203
219
  });
204
220
  }
205
221
  });
206
222
  }
207
223
 
224
+ /**
225
+ * Loads Geoedge in page script that monitors all ad slots created by GPT
226
+ * @param {Object} params
227
+ */
228
+ function setupInPage(params) {
229
+ window.grumi = params;
230
+ window.grumi.fromPrebid = true;
231
+ loadExternalScript(getInPageUrl(params.key), SUBMODULE_NAME);
232
+ }
233
+
208
234
  function init(config, userConsent) {
209
235
  let params = config.params;
210
236
  if (!params || !params.key) {
211
237
  logError('missing key for geoedge RTD module provider');
212
238
  return false;
213
239
  }
214
- preloadClient(params.key);
240
+ if (params.gpt) {
241
+ setupInPage(params);
242
+ } else {
243
+ fetchWrapper(setWrapper);
244
+ preloadClient(params.key);
245
+ }
215
246
  fireBillableEventsForApplicableBids(params);
216
247
  return true;
217
248
  }
@@ -228,7 +259,6 @@ export const geoedgeSubmodule = {
228
259
  };
229
260
 
230
261
  export function beforeInit() {
231
- fetchWrapper(setWrapper);
232
262
  submodule('realTimeData', geoedgeSubmodule);
233
263
  }
234
264
 
@@ -5,7 +5,7 @@ Module Type: Rtd Provider
5
5
  Maintainer: guy.books@geoedge.com
6
6
 
7
7
  The Geoedge Realtime module lets publishers block bad ads such as automatic redirects, malware, offensive creatives and landing pages.
8
- To use this module, you'll need to work with [Geoedge](https://www.geoedge.com/publishers-real-time-protection/) to get an account and cutomer key.
8
+ To use this module, you'll need to work with [Geoedge](https://www.geoedge.com/publishers-real-time-protection/) to get an account and customer key.
9
9
 
10
10
  ## Integration
11
11
 
@@ -49,6 +49,7 @@ Parameters details:
49
49
  |params.key | String | Customer key |Required, contact Geoedge to get your key |
50
50
  |params.bidders | Object | Bidders to monitor |Optional, list of bidder to include / exclude from monitoring. Omitting this will monitor bids from all bidders. |
51
51
  |params.wap |Boolean |Wrap after preload |Optional, defaults to `false`. Set to `true` if you want to monitor only after the module has preloaded the monitoring client. |
52
+ |params.gpt |Boolean |Wrap all GPT ad slots |Optional, defaults to `false`. Set to `true` if you want to monitor all Google Publisher Tag ad slots, regaedless if the winning bid comes from Prebid or Google Ad Manager (Direct, Adx, Adesnse, Open Bidding, etc). |
52
53
 
53
54
  ## Example
54
55
 
@@ -205,6 +205,10 @@ export const liveIntentIdSubmodule = {
205
205
  result.magnite = { 'id': value.magnite, ext: { provider: LI_PROVIDER_DOMAIN } }
206
206
  }
207
207
 
208
+ if (value.index) {
209
+ result.index = { 'id': value.index, ext: { provider: LI_PROVIDER_DOMAIN } }
210
+ }
211
+
208
212
  return result
209
213
  }
210
214
 
@@ -294,7 +298,18 @@ export const liveIntentIdSubmodule = {
294
298
  }
295
299
  }
296
300
  },
297
-
301
+ 'index': {
302
+ source: 'liveintent.indexexchange.com',
303
+ atype: 3,
304
+ getValue: function(data) {
305
+ return data.id;
306
+ },
307
+ getUidExt: function(data) {
308
+ if (data.ext) {
309
+ return data.ext;
310
+ }
311
+ }
312
+ }
298
313
  }
299
314
  };
300
315
 
@@ -2,7 +2,20 @@ import { deepAccess, isEmpty } from '../src/utils.js'
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js'
3
3
  import { BANNER } from '../src/mediaTypes.js'
4
4
  import { getGlobal } from '../src/prebidGlobal.js'
5
- // import { config } from 'src/config'
5
+ import { ortbConverter } from '../libraries/ortbConverter/converter.js'
6
+
7
+ const converter = ortbConverter({
8
+ context: {
9
+ // `netRevenue` and `ttl` are required properties of bid responses - provide a default for them
10
+ netRevenue: true, // or false if your adapter should set bidResponse.netRevenue = false
11
+ ttl: 30 // default bidResponse.ttl (when not specified in ORTB response.seatbid[].bid[].exp)
12
+ },
13
+ imp(buildImp, bidRequest, context) {
14
+ const imp = buildImp(bidRequest, context);
15
+ imp.tagid = bidRequest.adUnitCode
16
+ return imp;
17
+ }
18
+ });
6
19
 
7
20
  const BIDDER_CODE = 'nativo'
8
21
  const BIDDER_ENDPOINT = 'https://exchange.postrelease.com/prebid'
@@ -136,6 +149,10 @@ export const spec = {
136
149
  * @return ServerRequest Info describing the request to the server.
137
150
  */
138
151
  buildRequests: function (validBidRequests, bidderRequest) {
152
+ // Get OpenRTB Data
153
+ const openRTBData = converter.toORTB({bidRequests: validBidRequests, bidderRequest})
154
+ const openRTBDataString = JSON.stringify(openRTBData)
155
+
139
156
  const requestData = new RequestData()
140
157
  requestData.addBidRequestDataSource(new UserEIDs())
141
158
 
@@ -271,8 +288,9 @@ export const spec = {
271
288
  const requestUrl = buildRequestUrl(BIDDER_ENDPOINT, qsParamStrings)
272
289
 
273
290
  let serverRequest = {
274
- method: 'GET',
275
- url: requestUrl
291
+ method: 'POST',
292
+ url: requestUrl,
293
+ data: openRTBDataString,
276
294
  }
277
295
 
278
296
  return serverRequest
@@ -70,6 +70,9 @@ function buildRequests(validBidRequests, bidderRequest) {
70
70
  if (bidderRequest && bidderRequest.uspConsent) {
71
71
  payload.usPrivacy = bidderRequest.uspConsent;
72
72
  }
73
+ if (bidderRequest && bidderRequest.ortb2) {
74
+ payload.ortb2 = bidderRequest.ortb2;
75
+ }
73
76
  if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].userIdAsEids) {
74
77
  payload.userId = validBidRequests[0].userIdAsEids;
75
78
  }
@@ -680,6 +680,11 @@ function mapNativeImage(image, type) {
680
680
  * @returns {String} userId
681
681
  */
682
682
  function getUserId(bidRequest) {
683
+ let operaId = deepAccess(bidRequest, 'userId.operaId');
684
+ if (operaId) {
685
+ return operaId;
686
+ }
687
+
683
688
  let sharedId = deepAccess(bidRequest, 'userId.sharedid.id');
684
689
  if (sharedId) {
685
690
  return sharedId;
@@ -135,18 +135,18 @@ var adUnits = [{
135
135
 
136
136
  ### User Ids
137
137
 
138
- Opera Ads Bid Adapter uses `sharedId`, `pubcid` or `tdid`, please config at least one.
138
+ Opera Ads Bid Adapter uses `operaId`, please refer to [`Opera ID System`](./operaadsIdSystem.md).
139
139
 
140
140
  ```javascript
141
141
  pbjs.setConfig({
142
142
  ...,
143
143
  userSync: {
144
144
  userIds: [{
145
- name: 'sharedId',
145
+ name: 'operaId',
146
146
  storage: {
147
- name: '_sharedID', // name of the 1st party cookie
148
- type: 'cookie',
149
- expires: 30
147
+ name: 'operaId',
148
+ type: 'html5',
149
+ expires: 14
150
150
  }
151
151
  }]
152
152
  }
@@ -0,0 +1,106 @@
1
+ /**
2
+ * This module adds operaId to the User ID module
3
+ * The {@link module:modules/userId} module is required
4
+ * @module modules/operaadsIdSystem
5
+ * @requires module:modules/userId
6
+ */
7
+ import * as ajax from '../src/ajax.js';
8
+ import { submodule } from '../src/hook.js';
9
+ import { logMessage, logError } from '../src/utils.js';
10
+
11
+ const MODULE_NAME = 'operaId';
12
+ const ID_KEY = MODULE_NAME;
13
+ const version = '1.0';
14
+ const SYNC_URL = 'https://t.adx.opera.com/identity/';
15
+ const AJAX_TIMEOUT = 300;
16
+ const AJAX_OPTIONS = {method: 'GET', withCredentials: true, contentType: 'application/json'};
17
+
18
+ function constructUrl(pairs) {
19
+ const queries = [];
20
+ for (let key in pairs) {
21
+ queries.push(`${key}=${encodeURIComponent(pairs[key])}`);
22
+ }
23
+ return `${SYNC_URL}?${queries.join('&')}`;
24
+ }
25
+
26
+ function asyncRequest(url, cb) {
27
+ ajax.ajaxBuilder(AJAX_TIMEOUT)(
28
+ url,
29
+ {
30
+ success: response => {
31
+ try {
32
+ const jsonResponse = JSON.parse(response);
33
+ const { uid: operaId } = jsonResponse;
34
+ cb(operaId);
35
+ return;
36
+ } catch (e) {
37
+ logError(`${MODULE_NAME}: invalid response`, response);
38
+ }
39
+ cb();
40
+ },
41
+ error: (err) => {
42
+ logError(`${MODULE_NAME}: ID error response`, err);
43
+ cb();
44
+ }
45
+ },
46
+ null,
47
+ AJAX_OPTIONS
48
+ );
49
+ }
50
+
51
+ export const operaIdSubmodule = {
52
+ /**
53
+ * used to link submodule with config
54
+ * @type {string}
55
+ */
56
+ name: MODULE_NAME,
57
+
58
+ /**
59
+ * @type {string}
60
+ */
61
+ version,
62
+
63
+ /**
64
+ * decode the stored id value for passing to bid requests
65
+ * @function
66
+ * @param {string} id
67
+ * @returns {{'operaId': string}}
68
+ */
69
+ decode: (id) =>
70
+ id != null && id.length > 0
71
+ ? { [ID_KEY]: id }
72
+ : undefined,
73
+
74
+ /**
75
+ * performs action to obtain id and return a value in the callback's response argument
76
+ * @function
77
+ * @param {SubmoduleConfig} [config]
78
+ * @returns {IdResponse|undefined}
79
+ */
80
+ getId(config, consentData) {
81
+ logMessage(`${MODULE_NAME}: start synchronizing opera uid`);
82
+ const params = (config && config.params) || {};
83
+ if (typeof params.pid !== 'string' || params.pid.length == 0) {
84
+ logError(`${MODULE_NAME}: submodule requires a publisher ID to be defined`);
85
+ return;
86
+ }
87
+
88
+ const { pid, syncUrl = SYNC_URL } = params;
89
+ const url = constructUrl(syncUrl, { publisherId: pid });
90
+
91
+ return {
92
+ callback: (cb) => {
93
+ asyncRequest(url, cb);
94
+ }
95
+ }
96
+ },
97
+
98
+ eids: {
99
+ 'operaId': {
100
+ source: 't.adx.opera.com',
101
+ atype: 1
102
+ },
103
+ }
104
+ };
105
+
106
+ submodule('userId', operaIdSubmodule);
@@ -0,0 +1,52 @@
1
+ # Opera ID System
2
+
3
+ For help adding this module, please contact [adtech-prebid-group@opera.com](adtech-prebid-group@opera.com).
4
+
5
+ ### Prebid Configuration
6
+
7
+ You should configure this module under your `userSync.userIds[]` configuration:
8
+
9
+ ```javascript
10
+ pbjs.setConfig({
11
+ userSync: {
12
+ userIds: [
13
+ {
14
+ name: "operaId",
15
+ storage: {
16
+ name: "operaId",
17
+ type: "html5",
18
+ expires: 14
19
+ },
20
+ params: {
21
+ pid: "your-pulisher-ID-here"
22
+ }
23
+ }
24
+ ]
25
+ }
26
+ })
27
+ ```
28
+ <br>
29
+
30
+ | Param under `userSync.userIds[]` | Scope | Type | Description | Example |
31
+ | -------------------------------- | -------- | ------ | ----------------------------- | ----------------------------------------- |
32
+ | name | Required | string | ID for the operaId module | `"operaId"` |
33
+ | storage | Optional | Object | Settings for operaId storage | See [storage settings](#storage-settings) |
34
+ | params | Required | Object | Parameters for opreaId module | See [params](#params) |
35
+ <br>
36
+
37
+ ### Params
38
+
39
+ | Param under `params` | Scope | Type | Description | Example |
40
+ | -------------------- | -------- | ------ | ------------------------------ | --------------- |
41
+ | pid | Required | string | Publisher ID assigned by Opera | `"pub12345678"` |
42
+ <br>
43
+
44
+ ### Storage Settings
45
+
46
+ The following settings are suggested for the `storage` property in the `userSync.userIds[]` object:
47
+
48
+ | Param under `storage` | Type | Description | Example |
49
+ | --------------------- | ------------- | -------------------------------------------------------------------------------- | ----------- |
50
+ | name | String | Where the ID will be stored | `"operaId"` |
51
+ | type | String | For best performance, this should be `"html5"` | `"html5"` |
52
+ | expires | Number <= 30 | number of days until the stored ID expires. **Must be less than or equal to 30** | `14` |
@@ -21,6 +21,7 @@ let saveEvents = {}
21
21
  let allEvents = {}
22
22
  let auctionEnd = {}
23
23
  let initOptions = {}
24
+ let mode = {};
24
25
  let endpoint = 'https://default'
25
26
  let requestsAttributes = ['adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'params', 'userId', 'labelAny', 'bids', 'adId'];
26
27
 
@@ -41,16 +42,27 @@ function filterAttributes(arg, removead) {
41
42
  }
42
43
  if (typeof arg['gdprConsent'] != 'undefined') {
43
44
  response['gdprConsent'] = {};
44
- if (typeof arg['gdprConsent']['consentString'] != 'undefined') { response['gdprConsent']['consentString'] = arg['gdprConsent']['consentString']; }
45
+ if (typeof arg['gdprConsent']['consentString'] != 'undefined') {
46
+ response['gdprConsent']['consentString'] = arg['gdprConsent']['consentString'];
47
+ }
45
48
  }
46
- if (typeof arg['meta'] == 'object' && typeof arg['meta']['advertiserDomains'] != 'undefined') {
47
- response['meta'] = {'advertiserDomains': arg['meta']['advertiserDomains']};
49
+ if (typeof arg['meta'] == 'object') {
50
+ response['meta'] = {};
51
+ if (typeof arg['meta']['advertiserDomains'] != 'undefined') {
52
+ response['meta']['advertiserDomains'] = arg['meta']['advertiserDomains'];
53
+ }
54
+ if (typeof arg['meta']['demandSource'] == 'string') {
55
+ response['meta']['demandSource'] = arg['meta']['demandSource'];
56
+ }
48
57
  }
49
58
  requestsAttributes.forEach((attr) => {
50
59
  if (typeof arg[attr] != 'undefined') { response[attr] = arg[attr]; }
51
60
  });
52
- if (typeof response['creativeId'] == 'number') { response['creativeId'] = response['creativeId'].toString(); }
61
+ if (typeof response['creativeId'] == 'number') {
62
+ response['creativeId'] = response['creativeId'].toString();
63
+ }
53
64
  }
65
+ response['oxxionMode'] = mode;
54
66
  return response;
55
67
  }
56
68
 
@@ -229,7 +241,12 @@ oxxionAnalytics.originEnableAnalytics = oxxionAnalytics.enableAnalytics;
229
241
  oxxionAnalytics.enableAnalytics = function (config) {
230
242
  oxxionAnalytics.originEnableAnalytics(config); // call the base class function
231
243
  initOptions = config.options;
232
- if (initOptions.domain) { endpoint = 'https://' + initOptions.domain; }
244
+ if (initOptions.domain) {
245
+ endpoint = 'https://' + initOptions.domain;
246
+ }
247
+ if (window.OXXION_MODE) {
248
+ mode = window.OXXION_MODE;
249
+ }
233
250
  };
234
251
 
235
252
  adapterManager.registerAnalyticsAdapter({
@@ -27,7 +27,7 @@ const DEFAULT_PBS_INTEGRATION = 'pbjs';
27
27
  const DEFAULT_RENDERER_URL = 'https://video-outstream.rubiconproject.com/apex-2.2.1.js';
28
28
  // renderer code at https://github.com/rubicon-project/apex2
29
29
 
30
- let rubiConf = {};
30
+ let rubiConf = config.getConfig('rubicon') || {};
31
31
  // we are saving these as global to this module so that if a pub accidentally overwrites the entire
32
32
  // rubicon object, then we do not lose other data
33
33
  config.getConfig('rubicon', config => {
@@ -322,7 +322,7 @@ export const spec = {
322
322
  )
323
323
  );
324
324
  });
325
- if (config.getConfig('rubicon.singleRequest') !== true) {
325
+ if (rubiConf.singleRequest !== true) {
326
326
  // bids are not grouped if single request mode is not enabled
327
327
  requests = filteredHttpRequest.concat(bannerBidRequests.map(bidRequest => {
328
328
  const bidParams = spec.createSlotParams(bidRequest, bidderRequest);
@@ -3,6 +3,7 @@ import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
4
4
  import { config } from '../src/config.js';
5
5
  import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
6
+ import { ajax } from '../src/ajax.js';
6
7
 
7
8
  const BIDDER_CODE = 'smartyads';
8
9
  const AD_URL = 'https://n1.smartyads.com/?c=o&m=prebid&secret_key=prebid_js';
@@ -122,7 +123,23 @@ export const spec = {
122
123
  }
123
124
 
124
125
  return syncs
125
- }
126
+ },
127
+
128
+ onBidWon: function(bid) {
129
+ if (bid.winUrl) {
130
+ ajax(bid.winUrl, () => {}, JSON.stringify(bid));
131
+ } else {
132
+ ajax('https://et-nd43.itdsmr.com/?c=o&m=prebid&secret_key=prebid_js&winTest=1', () => {}, JSON.stringify(bid));
133
+ }
134
+ },
135
+
136
+ onTimeout: function(bid) {
137
+ ajax('https://et-nd43.itdsmr.com/?c=o&m=prebid&secret_key=prebid_js&bidTimeout=1', () => {}, JSON.stringify(bid));
138
+ },
139
+
140
+ onBidderError: function(bid) {
141
+ ajax('https://et-nd43.itdsmr.com/?c=o&m=prebid&secret_key=prebid_js&bidderError=1', () => {}, JSON.stringify(bid));
142
+ },
126
143
 
127
144
  };
128
145
 
@@ -1,7 +1,7 @@
1
1
  import {config} from '../src/config.js';
2
2
  import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import {BANNER} from '../src/mediaTypes.js';
4
- import {deepAccess, isArray, isFn, isPlainObject} from '../src/utils.js';
4
+ import {deepAccess, isArray, isFn, isPlainObject, inIframe, getDNT} from '../src/utils.js';
5
5
  import {hasPurpose1Consent} from '../src/utils/gpdr.js';
6
6
  import {getGlobal} from '../src/prebidGlobal.js';
7
7
 
@@ -13,6 +13,7 @@ const DEFAULT_CURRENCIES = ['USD'];
13
13
  const FLOOR_MATCH_ALL_SIZES = '*';
14
14
 
15
15
  const getConfig = config.getConfig;
16
+ const refreshes = {};
16
17
 
17
18
  export const spec = {
18
19
  code: BIDDER_CODE,
@@ -29,12 +30,15 @@ export const spec = {
29
30
  method: 'POST',
30
31
  url: getEndpoint(),
31
32
  data: JSON.stringify({
32
- id: bidderRequest.bidderRequestId,
33
+ id: bidderRequest.auctionId,
34
+ accountId: deepAccess(bidRequests, '0.params.accountId'),
35
+ site: deepAccess(bidRequests, '0.params.site'),
33
36
  cur: getCurrencies(),
34
37
  test: getTestFlag(),
35
- devw: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
36
- devh: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
37
38
  version: getGlobal().version,
39
+ gpp: deepAccess(bidderRequest, 'gppConsent.gppString') || deepAccess(bidderRequest, 'ortb2.regs.gpp'),
40
+ gpp_sid:
41
+ deepAccess(bidderRequest, 'gppConsent.applicableSections') || deepAccess(bidderRequest, 'ortb2.regs.gpp_sid'),
38
42
  gdprApplies: gdprApplies,
39
43
  gdprConsentString: gdprApplies === true ? deepAccess(bidderRequest, 'gdprConsent.consentString') : undefined,
40
44
  gdprConsentProv: gdprApplies === true ? deepAccess(bidderRequest, 'gdprConsent.addtlConsent') : undefined,
@@ -43,12 +47,24 @@ export const spec = {
43
47
  eids: deepAccess(bidRequests, '0.userIdAsEids'),
44
48
  schain: deepAccess(bidRequests, '0.schain'),
45
49
  page: getPage(bidderRequest),
50
+ topframe: inIframe() === true ? 0 : 1,
51
+ device: {
52
+ w: window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth,
53
+ h: window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight,
54
+ dnt: getDNT() ? 1 : 0,
55
+ language: getLanguage(),
56
+ },
46
57
  placements: bidRequests.map((r) => {
47
58
  return {
48
- uuid: r.bidId,
59
+ id: r.adUnitCode,
60
+ tid: r.transactionId,
61
+ gpid: deepAccess(r, 'ortb2Imp.ext.gpid'),
62
+ pbadslot: deepAccess(r, 'ortb2Imp.ext.data.pbadslot') || deepAccess(r, 'ortb2Imp.ext.gpid'),
49
63
  name: r.params.placement,
50
64
  sizes: r.sizes,
51
65
  floor: getPriceFloor(r, BANNER, FLOOR_MATCH_ALL_SIZES),
66
+ refresh: getRefreshInformation(r.adUnitCode),
67
+ params: r.params.additionalParams,
52
68
  };
53
69
  }),
54
70
  }),
@@ -56,14 +72,14 @@ export const spec = {
56
72
  };
57
73
  },
58
74
 
59
- interpretResponse: function (serverResponse) {
75
+ interpretResponse: function (serverResponse, bidRequest) {
60
76
  if (!serverResponse.body || !serverResponse.body.bids) {
61
77
  return [];
62
78
  }
63
79
 
64
80
  return serverResponse.body.bids.map((bid) => {
65
81
  return {
66
- requestId: bid.uuid,
82
+ requestId: mapIdToRequestId(bid.id, bidRequest),
67
83
  cpm: bid.price,
68
84
  creativeId: bid.crid,
69
85
  currency: serverResponse.body.cur,
@@ -77,9 +93,9 @@ export const spec = {
77
93
  });
78
94
  },
79
95
 
80
- getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent) {
96
+ getUserSyncs: function (syncOptions, responses, gdprConsent, uspConsent, gppConsent) {
81
97
  const syncUrl = getSyncUrl(responses || []);
82
- if (syncUrl && syncOptions.iframeEnabled && hasSyncConsent(gdprConsent, uspConsent)) {
98
+ if (syncUrl && syncOptions.iframeEnabled && hasSyncConsent(gdprConsent, uspConsent, gppConsent)) {
83
99
  return [{type: 'iframe', url: getSyncEndpoint(syncUrl, gdprConsent)}];
84
100
  }
85
101
  },
@@ -101,6 +117,14 @@ function getTestFlag() {
101
117
  return getConfig(`${BIDDER_CODE}.test`) === true;
102
118
  }
103
119
 
120
+ function getLanguage() {
121
+ return navigator && navigator.language
122
+ ? navigator.language.indexOf('-') != -1
123
+ ? navigator.language.split('-')[0]
124
+ : navigator.language
125
+ : undefined;
126
+ }
127
+
104
128
  function getCurrencies() {
105
129
  const currencyOverrides = getConfig(`${BIDDER_CODE}.cur`);
106
130
  if (currencyOverrides !== undefined && (!isArray(currencyOverrides) || currencyOverrides.length === 0)) {
@@ -130,14 +154,43 @@ function getPriceFloor(bidRequest, mediaType, size) {
130
154
  }
131
155
  }
132
156
 
133
- function hasSyncConsent(gdprConsent, uspConsent) {
134
- if (gdprConsent?.gdprApplies && !hasPurpose1Consent(gdprConsent)) {
135
- return false;
136
- } else if (uspConsent && uspConsent[1] === 'Y' && uspConsent[2] === 'Y') {
137
- return false;
138
- } else {
139
- return true;
157
+ function getRefreshInformation(adUnitCode) {
158
+ const refresh = refreshes[adUnitCode];
159
+ if (!refresh) {
160
+ refreshes[adUnitCode] = {
161
+ count: 0,
162
+ previousTime: new Date(),
163
+ };
164
+ return undefined;
140
165
  }
166
+
167
+ const currentTime = new Date();
168
+ const timeDifferenceSeconds = Math.floor((currentTime - refresh.previousTime) / 1000);
169
+ refresh.count += 1;
170
+ refresh.previousTime = currentTime;
171
+ return {
172
+ count: refresh.count,
173
+ time: timeDifferenceSeconds,
174
+ };
175
+ }
176
+
177
+ function mapIdToRequestId(id, bidRequest) {
178
+ return bidRequest.bidderRequest.bids.filter((bid) => bid.adUnitCode === id)[0].bidId;
179
+ }
180
+
181
+ function hasUspConsent(uspConsent) {
182
+ return typeof uspConsent !== 'string' || !(uspConsent[0] === '1' && uspConsent[2] === 'Y');
183
+ }
184
+
185
+ function hasGppConsent(gppConsent) {
186
+ return (
187
+ !(gppConsent && Array.isArray(gppConsent.applicableSections)) ||
188
+ gppConsent.applicableSections.every((section) => typeof section === 'number' && section <= 5)
189
+ );
190
+ }
191
+
192
+ function hasSyncConsent(gdprConsent, uspConsent, gppConsent) {
193
+ return hasPurpose1Consent(gdprConsent) && hasUspConsent(uspConsent) && hasGppConsent(gppConsent);
141
194
  }
142
195
 
143
196
  function getSyncUrl(responses) {