prebid.js 8.1.0 → 8.2.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 (183) hide show
  1. package/.devcontainer/devcontainer.json +3 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.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/admanBidAdapter.js +1 -1
  8. package/dist/adqueryBidAdapter.js +1 -1
  9. package/dist/adrelevantisBidAdapter.js +1 -1
  10. package/dist/adtrgtmeBidAdapter.js +1 -1
  11. package/dist/adxcgBidAdapter.js +1 -1
  12. package/dist/adyoulikeBidAdapter.js +1 -1
  13. package/dist/ajaBidAdapter.js +1 -1
  14. package/dist/amxBidAdapter.js +1 -1
  15. package/dist/amxIdSystem.js +1 -1
  16. package/dist/appierAnalyticsAdapter.js +1 -1
  17. package/dist/appnexusBidAdapter.js +1 -1
  18. package/dist/asoBidAdapter.js +1 -1
  19. package/dist/axonixBidAdapter.js +1 -1
  20. package/dist/bidglassBidAdapter.js +1 -1
  21. package/dist/big-richmediaBidAdapter.js +1 -1
  22. package/dist/bridBidAdapter.js +1 -0
  23. package/dist/bridgewellBidAdapter.js +1 -1
  24. package/dist/brightMountainMediaBidAdapter.js +1 -1
  25. package/dist/carodaBidAdapter.js +1 -1
  26. package/dist/categoryTranslation.js +1 -1
  27. package/dist/chtnwBidAdapter.js +1 -1
  28. package/dist/cmp.js +1 -0
  29. package/dist/concertBidAdapter.js +1 -1
  30. package/dist/connectadBidAdapter.js +1 -1
  31. package/dist/consentManagement.js +1 -1
  32. package/dist/consentManagementGpp.js +1 -1
  33. package/dist/consentManagementUsp.js +1 -1
  34. package/dist/consumableBidAdapter.js +1 -1
  35. package/dist/conversantAnalyticsAdapter.js +1 -1
  36. package/dist/conversantBidAdapter.js +1 -1
  37. package/dist/craftBidAdapter.js +1 -1
  38. package/dist/criteoBidAdapter.js +1 -1
  39. package/dist/cwireBidAdapter.js +1 -1
  40. package/dist/dependencies.json +12 -0
  41. package/dist/dspxBidAdapter.js +1 -1
  42. package/dist/eplanningBidAdapter.js +1 -1
  43. package/dist/euidIdSystem.js +1 -1
  44. package/dist/feedadBidAdapter.js +1 -1
  45. package/dist/finativeBidAdapter.js +1 -1
  46. package/dist/freewheel-sspBidAdapter.js +1 -1
  47. package/dist/gmosspBidAdapter.js +1 -1
  48. package/dist/goldbachBidAdapter.js +1 -1
  49. package/dist/gppControl_usnat.js +1 -0
  50. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  51. package/dist/greenbidsRtdProvider.js +1 -1
  52. package/dist/gridBidAdapter.js +1 -1
  53. package/dist/gumgumBidAdapter.js +1 -1
  54. package/dist/h12mediaBidAdapter.js +1 -1
  55. package/dist/hypelabBidAdapter.js +1 -1
  56. package/dist/id5IdSystem.js +1 -1
  57. package/dist/imdsBidAdapter.js +1 -1
  58. package/dist/improvedigitalBidAdapter.js +1 -1
  59. package/dist/insticatorBidAdapter.js +1 -1
  60. package/dist/intentIqIdSystem.js +1 -1
  61. package/dist/ixBidAdapter.js +1 -1
  62. package/dist/justpremiumBidAdapter.js +1 -1
  63. package/dist/kargoBidAdapter.js +1 -1
  64. package/dist/konduitAnalyticsAdapter.js +1 -1
  65. package/dist/kueezBidAdapter.js +1 -1
  66. package/dist/kueezRtbBidAdapter.js +1 -1
  67. package/dist/kulturemediaBidAdapter.js +1 -1
  68. package/dist/lassoBidAdapter.js +1 -1
  69. package/dist/lifestreetBidAdapter.js +1 -1
  70. package/dist/liveIntentIdSystem.js +1 -1
  71. package/dist/logicadBidAdapter.js +1 -1
  72. package/dist/loglyliftBidAdapter.js +1 -1
  73. package/dist/magniteAnalyticsAdapter.js +1 -1
  74. package/dist/malltvAnalyticsAdapter.js +1 -1
  75. package/dist/marsmediaBidAdapter.js +1 -1
  76. package/dist/mediafuseBidAdapter.js +1 -1
  77. package/dist/mediasquareBidAdapter.js +1 -1
  78. package/dist/mgidBidAdapter.js +1 -1
  79. package/dist/minutemediaBidAdapter.js +1 -1
  80. package/dist/minutemediaplusBidAdapter.js +1 -1
  81. package/dist/mspa.js +1 -0
  82. package/dist/nexx360BidAdapter.js +1 -1
  83. package/dist/not-for-prod/prebid.js +136 -132
  84. package/dist/oguryBidAdapter.js +1 -1
  85. package/dist/onetagBidAdapter.js +1 -1
  86. package/dist/ooloAnalyticsAdapter.js +1 -1
  87. package/dist/optidigitalBidAdapter.js +1 -1
  88. package/dist/outbrainBidAdapter.js +1 -1
  89. package/dist/oxxionRtdProvider.js +1 -1
  90. package/dist/parrableIdSystem.js +1 -1
  91. package/dist/pixfutureBidAdapter.js +1 -1
  92. package/dist/prebid-core.js +1 -1
  93. package/dist/publinkIdSystem.js +1 -1
  94. package/dist/pubmaticBidAdapter.js +1 -1
  95. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  96. package/dist/pxyzBidAdapter.js +1 -1
  97. package/dist/quantcastBidAdapter.js +1 -1
  98. package/dist/readpeakBidAdapter.js +1 -1
  99. package/dist/relaidoBidAdapter.js +1 -1
  100. package/dist/retailspotBidAdapter.js +1 -1
  101. package/dist/rhythmoneBidAdapter.js +1 -1
  102. package/dist/riseBidAdapter.js +1 -1
  103. package/dist/rubiconBidAdapter.js +1 -1
  104. package/dist/seedingAllianceBidAdapter.js +1 -1
  105. package/dist/seedtagBidAdapter.js +1 -1
  106. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  107. package/dist/sharethroughBidAdapter.js +1 -1
  108. package/dist/shinezBidAdapter.js +1 -1
  109. package/dist/smaatoBidAdapter.js +1 -1
  110. package/dist/smartadserverBidAdapter.js +1 -1
  111. package/dist/smartxBidAdapter.js +1 -1
  112. package/dist/smilewantedBidAdapter.js +1 -1
  113. package/dist/sonobiBidAdapter.js +1 -1
  114. package/dist/sovrnAnalyticsAdapter.js +1 -1
  115. package/dist/sovrnBidAdapter.js +1 -1
  116. package/dist/sspBCBidAdapter.js +1 -1
  117. package/dist/stvBidAdapter.js +1 -1
  118. package/dist/sublimeBidAdapter.js +1 -1
  119. package/dist/targetVideoBidAdapter.js +1 -1
  120. package/dist/teadsBidAdapter.js +1 -1
  121. package/dist/trionBidAdapter.js +1 -1
  122. package/dist/tripleliftBidAdapter.js +1 -1
  123. package/dist/ttdBidAdapter.js +1 -1
  124. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  125. package/dist/uid2IdSystem.js +1 -1
  126. package/dist/underdogmediaBidAdapter.js +1 -1
  127. package/dist/undertoneBidAdapter.js +1 -1
  128. package/dist/userId.js +1 -1
  129. package/dist/vidazooBidAdapter.js +1 -1
  130. package/dist/videobyteBidAdapter.js +1 -1
  131. package/dist/visxBidAdapter.js +1 -1
  132. package/dist/vuukleBidAdapter.js +1 -1
  133. package/dist/widespaceBidAdapter.js +1 -1
  134. package/dist/winrBidAdapter.js +1 -1
  135. package/dist/yahoosspBidAdapter.js +1 -1
  136. package/dist/yieldmoBidAdapter.js +1 -1
  137. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  138. package/libraries/cmp/cmpClient.js +139 -0
  139. package/libraries/mspa/activityControls.js +91 -0
  140. package/modules/admanBidAdapter.js +5 -0
  141. package/modules/bridBidAdapter.js +223 -0
  142. package/modules/categoryTranslation.js +3 -2
  143. package/modules/consentManagement.js +12 -86
  144. package/modules/consentManagementGpp.js +47 -126
  145. package/modules/consentManagementUsp.js +19 -97
  146. package/modules/gppControl_usnat.js +11 -0
  147. package/modules/intentIqIdSystem.js +6 -5
  148. package/modules/liveIntentIdSystem.js +8 -3
  149. package/modules/mediasquareBidAdapter.js +19 -23
  150. package/modules/oxxionRtdProvider.js +124 -11
  151. package/modules/oxxionRtdProvider.md +19 -4
  152. package/modules/tripleliftBidAdapter.js +21 -1
  153. package/modules/userId/eids.js +29 -0
  154. package/modules/userId/eids.md +19 -2
  155. package/modules/userId/index.js +78 -29
  156. package/modules/userId/userId.md +3 -0
  157. package/package.json +1 -1
  158. package/src/activities/params.js +4 -1
  159. package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
  160. package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
  161. package/test/spec/modules/admanBidAdapter_spec.js +8 -2
  162. package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
  163. package/test/spec/modules/bridBidAdapter_spec.js +129 -0
  164. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
  165. package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
  166. package/test/spec/modules/consentManagementGpp_spec.js +84 -7
  167. package/test/spec/modules/consentManagement_spec.js +8 -18
  168. package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
  169. package/test/spec/modules/eids_spec.js +87 -0
  170. package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
  171. package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
  172. package/test/spec/modules/ixBidAdapter_spec.js +40 -12
  173. package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
  174. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
  175. package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
  176. package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
  177. package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
  178. package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
  179. package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
  180. package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
  181. package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
  182. package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
  183. package/test/spec/modules/userId_spec.js +393 -6
@@ -1,10 +1,13 @@
1
1
  import { submodule } from '../src/hook.js'
2
- import { deepAccess, logInfo } from '../src/utils.js'
2
+ import { deepAccess, logInfo, logError } from '../src/utils.js'
3
+ import { ajax } from '../src/ajax.js';
4
+ import adapterManager from '../src/adapterManager.js';
3
5
 
4
6
  const oxxionRtdSearchFor = [ 'adUnitCode', 'auctionId', 'bidder', 'bidderCode', 'bidId', 'cpm', 'creativeId', 'currency', 'width', 'height', 'mediaType', 'netRevenue', 'originalCpm', 'originalCurrency', 'requestId', 'size', 'source', 'status', 'timeToRespond', 'transactionId', 'ttl', 'sizes', 'mediaTypes', 'src', 'userId', 'labelAny', 'adId' ];
5
7
  const LOG_PREFIX = 'oxxionRtdProvider submodule: ';
6
8
 
7
9
  const allAdUnits = [];
10
+ const bidderAliasRegistry = adapterManager.aliasRegistry || {};
8
11
 
9
12
  /** @type {RtdSubmodule} */
10
13
  export const oxxionSubmodule = {
@@ -12,23 +15,56 @@ export const oxxionSubmodule = {
12
15
  init: init,
13
16
  getBidRequestData: getAdUnits,
14
17
  onBidResponseEvent: insertVideoTracking,
18
+ getRequestsList: getRequestsList,
19
+ getFilteredAdUnitsOnBidRates: getFilteredAdUnitsOnBidRates,
15
20
  };
16
21
 
17
22
  function init(config, userConsent) {
18
- if (!config.params || !config.params.domain || !config.params.contexts || !Array.isArray(config.params.contexts) || config.params.contexts.length == 0) {
19
- return false
20
- }
21
- return true;
23
+ if (!config.params || !config.params.domain) { return false }
24
+ if (config.params.contexts && Array.isArray(config.params.contexts) && config.params.contexts.length > 0) { return true; }
25
+ if (typeof config.params.threshold != 'undefined' && typeof config.params.samplingRate == 'number') { return true }
26
+ return false;
22
27
  }
23
28
 
24
29
  function getAdUnits(reqBidsConfigObj, callback, config, userConsent) {
25
- const reqAdUnits = reqBidsConfigObj.adUnits;
26
- if (Array.isArray(reqAdUnits)) {
27
- reqAdUnits.forEach(adunit => {
28
- if (config.params.contexts.includes(deepAccess(adunit, 'mediaTypes.video.context'))) {
29
- allAdUnits.push(adunit);
30
+ logInfo(LOG_PREFIX + 'started with ', config);
31
+ if (typeof config.params.threshold != 'undefined' && typeof config.params.samplingRate == 'number') {
32
+ let filteredBids;
33
+ const requests = getRequestsList(reqBidsConfigObj);
34
+ const gdpr = userConsent && userConsent.gdpr ? userConsent.gdpr.consentString : null;
35
+ const payload = {
36
+ gdpr,
37
+ requests
38
+ };
39
+ const endpoint = 'https://' + config.params.domain + '.oxxion.io/analytics/bid_rate_interests';
40
+ getPromisifiedAjax(endpoint, JSON.stringify(payload), {
41
+ method: 'POST',
42
+ withCredentials: true
43
+ }).then(bidsRateInterests => {
44
+ if (bidsRateInterests.length) {
45
+ [reqBidsConfigObj.adUnits, filteredBids] = getFilteredAdUnitsOnBidRates(bidsRateInterests, reqBidsConfigObj.adUnits, config.params, true);
30
46
  }
31
- });
47
+ if (filteredBids.length > 0) {
48
+ getPromisifiedAjax('https://' + config.params.domain + '.oxxion.io/analytics/request_rejecteds', JSON.stringify({'bids': filteredBids, 'gdpr': gdpr}), {
49
+ method: 'POST',
50
+ withCredentials: true
51
+ });
52
+ }
53
+ if (typeof callback == 'function') { callback(); }
54
+ }).catch(error => logError(LOG_PREFIX, 'bidInterestError', error));
55
+ }
56
+ if (config.params.contexts && Array.isArray(config.params.contexts) && config.params.contexts.length > 0) {
57
+ const reqAdUnits = reqBidsConfigObj.adUnits;
58
+ if (Array.isArray(reqAdUnits)) {
59
+ reqAdUnits.forEach(adunit => {
60
+ if (config.params.contexts.includes(deepAccess(adunit, 'mediaTypes.video.context'))) {
61
+ allAdUnits.push(adunit);
62
+ }
63
+ });
64
+ }
65
+ if (!(typeof config.params.threshold != 'undefined' && typeof config.params.samplingRate == 'number') && typeof callback == 'function') {
66
+ callback();
67
+ }
32
68
  }
33
69
  }
34
70
 
@@ -94,4 +130,81 @@ function getImpUrl(config, data, maxCpm) {
94
130
  return trackingImpUrl + 'cpmIncrement=' + cpmIncrement + '&context=' + context;
95
131
  }
96
132
 
133
+ function getPromisifiedAjax (url, data = {}, options = {}) {
134
+ return new Promise((resolve, reject) => {
135
+ const callbacks = {
136
+ success(responseText, { response }) {
137
+ resolve(JSON.parse(response));
138
+ },
139
+ error(error) {
140
+ reject(error);
141
+ }
142
+ };
143
+ ajax(url, callbacks, data, options);
144
+ })
145
+ }
146
+
147
+ function getFilteredAdUnitsOnBidRates (bidsRateInterests, adUnits, params, useSampling) {
148
+ const { threshold, samplingRate } = params;
149
+ const filteredBids = [];
150
+ // Separate bidsRateInterests in two groups against threshold & samplingRate
151
+ const { interestingBidsRates, uninterestingBidsRates } = bidsRateInterests.reduce((acc, interestingBid) => {
152
+ const isBidRateUpper = typeof threshold == 'number' ? interestingBid.rate === true || interestingBid.rate > threshold : interestingBid.suggestion;
153
+ const isBidInteresting = isBidRateUpper || (getRandomNumber(100) < samplingRate && useSampling);
154
+ const key = isBidInteresting ? 'interestingBidsRates' : 'uninterestingBidsRates';
155
+ acc[key].push(interestingBid);
156
+ return acc;
157
+ }, {
158
+ interestingBidsRates: [],
159
+ uninterestingBidsRates: [] // Do something with later
160
+ });
161
+ logInfo(LOG_PREFIX, 'getFilteredAdUnitsOnBidRates()', interestingBidsRates, uninterestingBidsRates);
162
+ // Filter bids and adUnits against interesting bids rates
163
+ const newAdUnits = adUnits.filter(({ bids = [] }, adUnitIndex) => {
164
+ adUnits[adUnitIndex].bids = bids.filter(bid => {
165
+ if (!params.bidders || params.bidders.includes(bid.bidder)) {
166
+ const index = interestingBidsRates.findIndex(({ id }) => id === bid._id);
167
+ if (index == -1) {
168
+ let tmpBid = bid;
169
+ tmpBid['code'] = adUnits[adUnitIndex].code;
170
+ tmpBid['mediaTypes'] = adUnits[adUnitIndex].mediaTypes;
171
+ tmpBid['originalBidder'] = bidderAliasRegistry[bid.bidder] || bid.bidder;
172
+ if (tmpBid.floorData) {
173
+ delete tmpBid.floorData;
174
+ }
175
+ filteredBids.push(tmpBid);
176
+ }
177
+ delete bid._id;
178
+ return index !== -1;
179
+ } else {
180
+ return true;
181
+ }
182
+ });
183
+ return !!adUnits[adUnitIndex].bids.length;
184
+ });
185
+ return [newAdUnits, filteredBids];
186
+ }
187
+
188
+ function getRandomNumber (max = 10) {
189
+ return Math.round(Math.random() * max);
190
+ }
191
+
192
+ function getRequestsList(reqBidsConfigObj) {
193
+ let count = 0;
194
+ return reqBidsConfigObj.adUnits.flatMap(({
195
+ bids = [],
196
+ mediaTypes = {},
197
+ code = ''
198
+ }) => bids.reduce((acc, { bidder = '', params = {} }, index) => {
199
+ const id = count++;
200
+ bids[index]._id = id;
201
+ return acc.concat({
202
+ id,
203
+ adUnit: code,
204
+ bidder,
205
+ mediaTypes,
206
+ });
207
+ }, []));
208
+ }
209
+
97
210
  submodule('realTimeData', oxxionSubmodule);
@@ -7,12 +7,12 @@ Maintainer: tech@oxxion.io
7
7
  # Oxxion Real-Time-Data submodule
8
8
 
9
9
  Oxxion helps you to understand how your prebid stack performs.
10
- This Rtd module is to use in order to improve video events tracking.
10
+ This Rtd module is to use in order to improve video events tracking and/or to filter bidder requested.
11
11
 
12
12
  # Integration
13
13
 
14
14
  Make sure to have the following modules listed while building prebid : `rtdModule,oxxionRtdProvider`
15
- `rtbModule` is required to activate real-time-data submodules.
15
+ `rtdModule` is required to activate real-time-data submodules.
16
16
  For example :
17
17
  ```
18
18
  gulp build --modules=schain,priceFloors,currency,consentManagement,appnexusBidAdapter,rubiconBidAdapter,rtdModule,oxxionRtdProvider
@@ -23,7 +23,7 @@ Then add the oxxion Rtd module to your prebid configuration :
23
23
  pbjs.setConfig(
24
24
  ...
25
25
  realTimeData: {
26
- auctionDelay: 200,
26
+ auctionDelay: 300,
27
27
  dataProviders: [
28
28
  {
29
29
  name: "oxxionRtd",
@@ -31,6 +31,8 @@ pbjs.setConfig(
31
31
  params: {
32
32
  domain: "test.endpoint",
33
33
  contexts: ["instream"],
34
+ threshold: false,
35
+ samplingRate: 10,
34
36
  }
35
37
  }
36
38
  ]
@@ -39,10 +41,23 @@ pbjs.setConfig(
39
41
  )
40
42
  ```
41
43
 
42
- # setConfig Parameters
44
+ # setConfig Parameters General
43
45
 
44
46
  | Name | Type | Description |
45
47
  |:---------------------------------|:---------|:------------------------------------------------------------------------------------------------------------|
46
48
  | domain | String | This string identifies yourself in Oxxion's systems and is provided to you by your Oxxion representative. |
49
+
50
+ # setConfig Parameters for Video Tracking
51
+
52
+ | Name | Type | Description |
53
+ |:---------------------------------|:---------|:------------------------------------------------------------------------------------------------------------|
47
54
  | contexts | Array | Array defining which video contexts to add tracking events into. Values can be instream and/or outstream. |
48
55
 
56
+ # setConfig Parameters for bidder filtering
57
+
58
+ | Name | Type | Description |
59
+ |:---------------------------------|:-----------|:------------------------------------------------------------------------------------------------------------|
60
+ | threshold | Float/Bool | False or minimum expected bid rate to call a bidder (ex: 1.0 for 1% bid rate). |
61
+ | samplingRate | Integer | Percentage of request not meeting the criterias to run anyway in order to check for any change. |
62
+ | bidders | Array | Optional: If set, filtering will only be applied to bidders listed.
63
+
@@ -56,6 +56,10 @@ export const tripleliftAdapterSpec = {
56
56
  tlCall = tryAppendQueryString(tlCall, 'us_privacy', bidderRequest.uspConsent);
57
57
  }
58
58
 
59
+ if (bidderRequest && bidderRequest.fledgeEnabled) {
60
+ tlCall = tryAppendQueryString(tlCall, 'fledge', bidderRequest.fledgeEnabled);
61
+ }
62
+
59
63
  if (config.getConfig('coppa') === true) {
60
64
  tlCall = tryAppendQueryString(tlCall, 'coppa', true);
61
65
  }
@@ -80,7 +84,7 @@ export const tripleliftAdapterSpec = {
80
84
  });
81
85
  },
82
86
 
83
- getUserSyncs: function(syncOptions, responses, gdprConsent, usPrivacy) {
87
+ getUserSyncs: function(syncOptions, responses, gdprConsent, usPrivacy, gppConsent) {
84
88
  let syncType = _getSyncType(syncOptions);
85
89
  if (!syncType) return;
86
90
 
@@ -100,6 +104,15 @@ export const tripleliftAdapterSpec = {
100
104
  syncEndpoint = tryAppendQueryString(syncEndpoint, 'us_privacy', usPrivacy);
101
105
  }
102
106
 
107
+ if (gppConsent) {
108
+ if (gppConsent.gppString) {
109
+ syncEndpoint = tryAppendQueryString(syncEndpoint, 'gpp', gppConsent.gppString);
110
+ }
111
+ if (gppConsent.applicableSections && gppConsent.applicableSections.length !== 0) {
112
+ syncEndpoint = tryAppendQueryString(syncEndpoint, 'gpp_sid', _filterSid(gppConsent.applicableSections));
113
+ }
114
+ }
115
+
103
116
  return [{
104
117
  type: syncType,
105
118
  url: syncEndpoint
@@ -113,6 +126,13 @@ function _getSyncType(syncOptions) {
113
126
  if (syncOptions.pixelEnabled) return 'image';
114
127
  }
115
128
 
129
+ function _filterSid(sid) {
130
+ return sid.filter(element => {
131
+ return Number.isInteger(element);
132
+ })
133
+ .join(',');
134
+ }
135
+
116
136
  function _buildPostBody(bidRequests, bidderRequest) {
117
137
  let data = {};
118
138
  let { schain } = bidRequests[0];
@@ -158,6 +158,11 @@ export const USER_IDS_CONFIG = {
158
158
  atype: 3,
159
159
  getValue: function(data) {
160
160
  return data.id;
161
+ },
162
+ getUidExt: function(data) {
163
+ if (data.ext) {
164
+ return data.ext;
165
+ }
161
166
  }
162
167
  },
163
168
 
@@ -167,6 +172,25 @@ export const USER_IDS_CONFIG = {
167
172
  atype: 3,
168
173
  getValue: function(data) {
169
174
  return data.id;
175
+ },
176
+ getUidExt: function(data) {
177
+ if (data.ext) {
178
+ return data.ext;
179
+ }
180
+ }
181
+ },
182
+
183
+ // magnite
184
+ 'magnite': {
185
+ source: 'rubiconproject.com',
186
+ atype: 3,
187
+ getValue: function(data) {
188
+ return data.id;
189
+ },
190
+ getUidExt: function(data) {
191
+ if (data.ext) {
192
+ return data.ext;
193
+ }
170
194
  }
171
195
  },
172
196
 
@@ -288,6 +312,11 @@ export const USER_IDS_CONFIG = {
288
312
  atype: 3,
289
313
  getValue: function(data) {
290
314
  return data.id;
315
+ },
316
+ getUidExt: function(data) {
317
+ if (data.ext) {
318
+ return data.ext;
319
+ }
291
320
  }
292
321
  },
293
322
 
@@ -110,7 +110,10 @@ userIdAsEids = [
110
110
  source: 'bidswitch.net',
111
111
  uids: [{
112
112
  id: 'some-random-id-value',
113
- atype: 3
113
+ atype: 3,
114
+ ext: {
115
+ provider: 'liveintent.com'
116
+ }
114
117
  }]
115
118
  },
116
119
 
@@ -118,7 +121,21 @@ userIdAsEids = [
118
121
  source: 'media.net',
119
122
  uids: [{
120
123
  id: 'some-random-id-value',
121
- atype: 3
124
+ atype: 3,
125
+ ext: {
126
+ provider: 'liveintent.com'
127
+ }
128
+ }]
129
+ },
130
+
131
+ {
132
+ source: 'rubiconproject.com',
133
+ uids: [{
134
+ id: 'some-random-id-value',
135
+ atype: 3,
136
+ ext: {
137
+ provider: 'liveintent.com'
138
+ }
122
139
  }]
123
140
  },
124
141
 
@@ -130,7 +130,7 @@ import {find, includes} from '../../src/polyfill.js';
130
130
  import {config} from '../../src/config.js';
131
131
  import * as events from '../../src/events.js';
132
132
  import {getGlobal} from '../../src/prebidGlobal.js';
133
- import adapterManager, {gdprDataHandler} from '../../src/adapterManager.js';
133
+ import adapterManager, {gdprDataHandler, gppDataHandler} from '../../src/adapterManager.js';
134
134
  import CONSTANTS from '../../src/constants.json';
135
135
  import {module, ready as hooksReady} from '../../src/hook.js';
136
136
  import {buildEidPermissions, createEidsArray, USER_IDS_CONFIG} from './eids.js';
@@ -195,6 +195,9 @@ let initializedSubmodules;
195
195
  /** @type {SubmoduleConfig[]} */
196
196
  let configRegistry = [];
197
197
 
198
+ /** @type {Object} */
199
+ let idPriority = {};
200
+
198
201
  /** @type {Submodule[]} */
199
202
  let submoduleRegistry = [];
200
203
 
@@ -406,7 +409,7 @@ function storedConsentDataMatchesConsentData(storedConsentData, consentData) {
406
409
  * @param {SubmoduleContainer[]} submodules
407
410
  * @param {function} cb - callback for after processing is done.
408
411
  */
409
- function processSubmoduleCallbacks(submodules, cb) {
412
+ function processSubmoduleCallbacks(submodules, cb, allModules) {
410
413
  cb = uidMetrics().fork().startTiming('userId.callbacks.total').stopBefore(cb);
411
414
  const done = delayExecution(() => {
412
415
  clearTimeout(timeoutID);
@@ -422,7 +425,7 @@ function processSubmoduleCallbacks(submodules, cb) {
422
425
  }
423
426
  // cache decoded value (this is copied to every adUnit bid)
424
427
  submodule.idObj = submodule.submodule.decode(idObj, submodule.config);
425
- updatePPID(submodule.idObj);
428
+ updatePPID(getCombinedSubmoduleIds(allModules));
426
429
  } else {
427
430
  logInfo(`${MODULE_NAME}: ${submodule.submodule.name} - request id responded with an empty value`);
428
431
  }
@@ -447,14 +450,7 @@ function getCombinedSubmoduleIds(submodules) {
447
450
  if (!Array.isArray(submodules) || !submodules.length) {
448
451
  return {};
449
452
  }
450
- const combinedSubmoduleIds = submodules.filter(i => isPlainObject(i.idObj) && Object.keys(i.idObj).length).reduce((carry, i) => {
451
- Object.keys(i.idObj).forEach(key => {
452
- carry[key] = i.idObj[key];
453
- });
454
- return carry;
455
- }, {});
456
-
457
- return combinedSubmoduleIds;
453
+ return getPrioritizedCombinedSubmoduleIds(submodules)
458
454
  }
459
455
 
460
456
  /**
@@ -466,9 +462,14 @@ function getSubmoduleId(submodules, sourceName) {
466
462
  if (!Array.isArray(submodules) || !submodules.length) {
467
463
  return {};
468
464
  }
469
- const submodule = submodules.filter(sub => isPlainObject(sub.idObj) &&
470
- Object.keys(sub.idObj).length && USER_IDS_CONFIG[Object.keys(sub.idObj)[0]]?.source === sourceName);
471
- return !isEmpty(submodule) ? submodule[0].idObj : [];
465
+
466
+ const prioritisedIds = getPrioritizedCombinedSubmoduleIds(submodules);
467
+ const eligibleIdName = Object.keys(prioritisedIds).find(idName => {
468
+ const config = USER_IDS_CONFIG[idName];
469
+ return config?.source === sourceName || (isFn(config?.getSource) && config.getSource() === sourceName);
470
+ });
471
+
472
+ return eligibleIdName ? {[eligibleIdName]: prioritisedIds[eligibleIdName]} : [];
472
473
  }
473
474
 
474
475
  /**
@@ -480,15 +481,38 @@ function getCombinedSubmoduleIdsForBidder(submodules, bidder) {
480
481
  if (!Array.isArray(submodules) || !submodules.length || !bidder) {
481
482
  return {};
482
483
  }
483
- return submodules
484
+ const eligibleSubmodules = submodules
484
485
  .filter(i => !i.config.bidders || !isArray(i.config.bidders) || includes(i.config.bidders, bidder))
486
+
487
+ return getPrioritizedCombinedSubmoduleIds(eligibleSubmodules);
488
+ }
489
+
490
+ /**
491
+ * @param {SubmoduleContainer[]} submodules
492
+ */
493
+ function getPrioritizedCombinedSubmoduleIds(submodules) {
494
+ const combinedIdStates = submodules
485
495
  .filter(i => isPlainObject(i.idObj) && Object.keys(i.idObj).length)
486
496
  .reduce((carry, i) => {
487
497
  Object.keys(i.idObj).forEach(key => {
488
- carry[key] = i.idObj[key];
498
+ const maybeCurrentIdPriority = idPriority[key]?.indexOf(i.submodule.name);
499
+ const currentIdPriority = isNumber(maybeCurrentIdPriority) ? maybeCurrentIdPriority : -1;
500
+ const currentIdState = {priority: currentIdPriority, value: i.idObj[key]};
501
+ if (carry[key]) {
502
+ const winnerIdState = currentIdState.priority > carry[key].priority ? currentIdState : carry[key];
503
+ carry[key] = winnerIdState;
504
+ } else {
505
+ carry[key] = currentIdState;
506
+ }
489
507
  });
490
508
  return carry;
491
509
  }, {});
510
+
511
+ const result = {};
512
+ Object.keys(combinedIdStates).forEach(key => {
513
+ result[key] = combinedIdStates[key].value
514
+ });
515
+ return result;
492
516
  }
493
517
 
494
518
  /**
@@ -550,10 +574,13 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) {
550
574
  function timeGdpr() {
551
575
  return gdprDataHandler.promise.finally(initMetrics.startTiming('userId.init.gdpr'));
552
576
  }
577
+ function timeGpp() {
578
+ return gppDataHandler.promise.finally(initMetrics.startTiming('userId.init.gpp'))
579
+ }
553
580
 
554
581
  let done = cancelAndTry(
555
582
  GreedyPromise.all([hooksReady, startInit.promise])
556
- .then(timeGdpr)
583
+ .then(() => GreedyPromise.all([timeGdpr(), timeGpp()]).then(([gdpr]) => gdpr))
557
584
  .then(checkRefs((consentData) => {
558
585
  initSubmodules(initModules, allModules, consentData);
559
586
  }))
@@ -561,7 +588,7 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) {
561
588
  .then(checkRefs(() => {
562
589
  const modWithCb = initModules.filter(item => isFn(item.callback));
563
590
  if (modWithCb.length) {
564
- return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve));
591
+ return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve, initModules));
565
592
  }
566
593
  }))
567
594
  );
@@ -600,7 +627,7 @@ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) {
600
627
  return sm.callback != null;
601
628
  });
602
629
  if (cbModules.length) {
603
- return new GreedyPromise((resolve) => processSubmoduleCallbacks(cbModules, resolve));
630
+ return new GreedyPromise((resolve) => processSubmoduleCallbacks(cbModules, resolve, initModules));
604
631
  }
605
632
  }))
606
633
  );
@@ -783,7 +810,7 @@ function getUserIdsAsync() {
783
810
  );
784
811
  }
785
812
 
786
- function populateSubmoduleId(submodule, consentData, storedConsentData, forceRefresh) {
813
+ function populateSubmoduleId(submodule, consentData, storedConsentData, forceRefresh, allSubmodules) {
787
814
  // There are two submodule configuration types to handle: storage or value
788
815
  // 1. storage: retrieve user id data from cookie/html storage or with the submodule's getId method
789
816
  // 2. value: pass directly to bids
@@ -832,7 +859,7 @@ function populateSubmoduleId(submodule, consentData, storedConsentData, forceRef
832
859
  if (response.id) { submodule.idObj = submodule.submodule.decode(response.id, submodule.config); }
833
860
  }
834
861
  }
835
- updatePPID(submodule.idObj);
862
+ updatePPID(getCombinedSubmoduleIds(allSubmodules));
836
863
  }
837
864
 
838
865
  function updatePPID(userIds = getUserIds()) {
@@ -879,7 +906,7 @@ function initSubmodules(dest, submodules, consentData, forceRefresh = false) {
879
906
  const initialized = submodules.reduce((carry, submodule) => {
880
907
  return submoduleMetrics(submodule.submodule.name).measureTime('init', () => {
881
908
  try {
882
- populateSubmoduleId(submodule, consentData, storedConsentData, forceRefresh);
909
+ populateSubmoduleId(submodule, consentData, storedConsentData, forceRefresh, submodules);
883
910
  carry.push(submodule);
884
911
  } catch (e) {
885
912
  logError(`Error in userID module '${submodule.submodule.name}':`, e);
@@ -1010,6 +1037,25 @@ function updateSubmodules() {
1010
1037
  }
1011
1038
  }
1012
1039
 
1040
+ /**
1041
+ * This function will update the idPriority according to the provided configuration
1042
+ * @param {Object} idPriorityConfig
1043
+ * @param {SubmoduleContainer[]} submodules
1044
+ */
1045
+ function updateIdPriority(idPriorityConfig, submodules) {
1046
+ if (idPriorityConfig) {
1047
+ const result = {};
1048
+ const aliasToName = new Map(submodules.map(s => s.submodule.aliasName ? [s.submodule.aliasName, s.submodule.name] : []));
1049
+ Object.keys(idPriorityConfig).forEach(key => {
1050
+ const priority = isArray(idPriorityConfig[key]) ? [...idPriorityConfig[key]].reverse() : []
1051
+ result[key] = priority.map(s => aliasToName.has(s) ? aliasToName.get(s) : s);
1052
+ });
1053
+ idPriority = result;
1054
+ } else {
1055
+ idPriority = {};
1056
+ }
1057
+ }
1058
+
1013
1059
  export function requestDataDeletion(next, ...args) {
1014
1060
  logInfo('UserID: received data deletion request; deleting all stored IDs...')
1015
1061
  submodules.forEach(submodule => {
@@ -1069,13 +1115,16 @@ export function init(config, {delay = GreedyPromise.timeout} = {}) {
1069
1115
  configListener = config.getConfig('userSync', conf => {
1070
1116
  // Note: support for 'usersync' was dropped as part of Prebid.js 4.0
1071
1117
  const userSync = conf.userSync;
1072
- ppidSource = userSync.ppid;
1073
- if (userSync && userSync.userIds) {
1074
- configRegistry = userSync.userIds;
1075
- syncDelay = isNumber(userSync.syncDelay) ? userSync.syncDelay : DEFAULT_SYNC_DELAY;
1076
- auctionDelay = isNumber(userSync.auctionDelay) ? userSync.auctionDelay : NO_AUCTION_DELAY;
1077
- updateSubmodules();
1078
- initIdSystem({ready: true});
1118
+ if (userSync) {
1119
+ ppidSource = userSync.ppid;
1120
+ if (userSync.userIds) {
1121
+ configRegistry = userSync.userIds;
1122
+ syncDelay = isNumber(userSync.syncDelay) ? userSync.syncDelay : DEFAULT_SYNC_DELAY;
1123
+ auctionDelay = isNumber(userSync.auctionDelay) ? userSync.auctionDelay : NO_AUCTION_DELAY;
1124
+ updateSubmodules();
1125
+ updateIdPriority(userSync.idPriority, submodules);
1126
+ initIdSystem({ready: true});
1127
+ }
1079
1128
  }
1080
1129
  });
1081
1130
 
@@ -5,6 +5,9 @@ Example showing `cookie` storage for user id data for each of the submodules
5
5
  ```
6
6
  pbjs.setConfig({
7
7
  userSync: {
8
+ idPriority: {
9
+ uid2: ['uid2', 'liveIntentId']
10
+ }
8
11
  userIds: [{
9
12
  name: "33acrossId",
10
13
  storage: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "8.1.0",
3
+ "version": "8.2.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
@@ -1,4 +1,5 @@
1
1
  import {MODULE_TYPE_BIDDER} from './modules.js';
2
+ import {hook} from '../hook.js';
2
3
 
3
4
  /**
4
5
  * Component ID - who is trying to perform the activity?
@@ -54,6 +55,8 @@ export function activityParamsBuilder(resolveAlias) {
54
55
  if (moduleType === MODULE_TYPE_BIDDER) {
55
56
  defaults[ACTIVITY_PARAM_ADAPTER_CODE] = resolveAlias(moduleName);
56
57
  }
57
- return Object.assign(defaults, params);
58
+ return buildActivityParams(Object.assign(defaults, params));
58
59
  }
59
60
  }
61
+
62
+ export const buildActivityParams = hook('sync', params => params);