prebid.js 8.0.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 (232) 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/bedigitechBidAdapter.js +1 -1
  21. package/dist/beopBidAdapter.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/bidwatchAnalyticsAdapter.js +1 -1
  24. package/dist/big-richmediaBidAdapter.js +1 -1
  25. package/dist/bridBidAdapter.js +1 -0
  26. package/dist/bridgewellBidAdapter.js +1 -1
  27. package/dist/brightMountainMediaBidAdapter.js +1 -1
  28. package/dist/carodaBidAdapter.js +1 -1
  29. package/dist/categoryTranslation.js +1 -1
  30. package/dist/chtnwBidAdapter.js +1 -1
  31. package/dist/cmp.js +1 -0
  32. package/dist/colossussspBidAdapter.js +1 -1
  33. package/dist/conceptxBidAdapter.js +1 -1
  34. package/dist/concertBidAdapter.js +1 -1
  35. package/dist/connectadBidAdapter.js +1 -1
  36. package/dist/consentManagement.js +1 -1
  37. package/dist/consentManagementGpp.js +1 -1
  38. package/dist/consentManagementUsp.js +1 -1
  39. package/dist/consumableBidAdapter.js +1 -1
  40. package/dist/conversantAnalyticsAdapter.js +1 -1
  41. package/dist/conversantBidAdapter.js +1 -1
  42. package/dist/craftBidAdapter.js +1 -1
  43. package/dist/criteoBidAdapter.js +1 -1
  44. package/dist/cwireBidAdapter.js +1 -1
  45. package/dist/dependencies.json +15 -0
  46. package/dist/dspxBidAdapter.js +1 -1
  47. package/dist/eplanningBidAdapter.js +1 -1
  48. package/dist/euidIdSystem.js +1 -1
  49. package/dist/feedadBidAdapter.js +1 -1
  50. package/dist/finativeBidAdapter.js +1 -1
  51. package/dist/freepassBidAdapter.js +1 -0
  52. package/dist/freewheel-sspBidAdapter.js +1 -1
  53. package/dist/gmosspBidAdapter.js +1 -1
  54. package/dist/goldbachBidAdapter.js +1 -1
  55. package/dist/gppControl_usnat.js +1 -0
  56. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  57. package/dist/greenbidsRtdProvider.js +1 -1
  58. package/dist/gridBidAdapter.js +1 -1
  59. package/dist/gumgumBidAdapter.js +1 -1
  60. package/dist/h12mediaBidAdapter.js +1 -1
  61. package/dist/hypelabBidAdapter.js +1 -1
  62. package/dist/id5IdSystem.js +1 -1
  63. package/dist/imdsBidAdapter.js +1 -1
  64. package/dist/improvedigitalBidAdapter.js +1 -1
  65. package/dist/insticatorBidAdapter.js +1 -1
  66. package/dist/intentIqIdSystem.js +1 -1
  67. package/dist/ixBidAdapter.js +1 -1
  68. package/dist/justpremiumBidAdapter.js +1 -1
  69. package/dist/kargoBidAdapter.js +1 -1
  70. package/dist/kiviadsBidAdapter.js +1 -0
  71. package/dist/konduitAnalyticsAdapter.js +1 -1
  72. package/dist/kueezBidAdapter.js +1 -1
  73. package/dist/kueezRtbBidAdapter.js +1 -1
  74. package/dist/kulturemediaBidAdapter.js +1 -1
  75. package/dist/lassoBidAdapter.js +1 -1
  76. package/dist/lifestreetBidAdapter.js +1 -1
  77. package/dist/liveIntentIdSystem.js +1 -1
  78. package/dist/logicadBidAdapter.js +1 -1
  79. package/dist/loglyliftBidAdapter.js +1 -1
  80. package/dist/magniteAnalyticsAdapter.js +1 -1
  81. package/dist/malltvAnalyticsAdapter.js +1 -1
  82. package/dist/marsmediaBidAdapter.js +1 -1
  83. package/dist/mediafuseBidAdapter.js +1 -1
  84. package/dist/mediasquareBidAdapter.js +1 -1
  85. package/dist/mgidBidAdapter.js +1 -1
  86. package/dist/mgidXBidAdapter.js +1 -0
  87. package/dist/minutemediaBidAdapter.js +1 -1
  88. package/dist/minutemediaplusBidAdapter.js +1 -1
  89. package/dist/mspa.js +1 -0
  90. package/dist/nexx360BidAdapter.js +1 -1
  91. package/dist/not-for-prod/prebid.js +146 -139
  92. package/dist/oguryBidAdapter.js +1 -1
  93. package/dist/onetagBidAdapter.js +1 -1
  94. package/dist/ooloAnalyticsAdapter.js +1 -1
  95. package/dist/optidigitalBidAdapter.js +1 -1
  96. package/dist/outbrainBidAdapter.js +1 -1
  97. package/dist/oxxionAnalyticsAdapter.js +1 -1
  98. package/dist/oxxionRtdProvider.js +1 -1
  99. package/dist/parrableIdSystem.js +1 -1
  100. package/dist/pixfutureBidAdapter.js +1 -1
  101. package/dist/prebid-core.js +1 -1
  102. package/dist/publinkIdSystem.js +1 -1
  103. package/dist/pubmaticBidAdapter.js +1 -1
  104. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  105. package/dist/pxyzBidAdapter.js +1 -1
  106. package/dist/quantcastBidAdapter.js +1 -1
  107. package/dist/readpeakBidAdapter.js +1 -1
  108. package/dist/relaidoBidAdapter.js +1 -1
  109. package/dist/retailspotBidAdapter.js +1 -1
  110. package/dist/rhythmoneBidAdapter.js +1 -1
  111. package/dist/riseBidAdapter.js +1 -1
  112. package/dist/rtbhouseBidAdapter.js +1 -1
  113. package/dist/rubiconBidAdapter.js +1 -1
  114. package/dist/seedingAllianceBidAdapter.js +1 -1
  115. package/dist/seedtagBidAdapter.js +1 -1
  116. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  117. package/dist/sharethroughBidAdapter.js +1 -1
  118. package/dist/shinezBidAdapter.js +1 -1
  119. package/dist/smaatoBidAdapter.js +1 -1
  120. package/dist/smartadserverBidAdapter.js +1 -1
  121. package/dist/smartxBidAdapter.js +1 -1
  122. package/dist/smilewantedBidAdapter.js +1 -1
  123. package/dist/sonobiBidAdapter.js +1 -1
  124. package/dist/sovrnAnalyticsAdapter.js +1 -1
  125. package/dist/sovrnBidAdapter.js +1 -1
  126. package/dist/sspBCBidAdapter.js +1 -1
  127. package/dist/stvBidAdapter.js +1 -1
  128. package/dist/sublimeBidAdapter.js +1 -1
  129. package/dist/targetVideoBidAdapter.js +1 -1
  130. package/dist/teadsBidAdapter.js +1 -1
  131. package/dist/trionBidAdapter.js +1 -1
  132. package/dist/tripleliftBidAdapter.js +1 -1
  133. package/dist/ttdBidAdapter.js +1 -1
  134. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  135. package/dist/uid2IdSystem.js +1 -1
  136. package/dist/underdogmediaBidAdapter.js +1 -1
  137. package/dist/undertoneBidAdapter.js +1 -1
  138. package/dist/userId.js +1 -1
  139. package/dist/vidazooBidAdapter.js +1 -1
  140. package/dist/videobyteBidAdapter.js +1 -1
  141. package/dist/visxBidAdapter.js +1 -1
  142. package/dist/vuukleBidAdapter.js +1 -1
  143. package/dist/widespaceBidAdapter.js +1 -1
  144. package/dist/winrBidAdapter.js +1 -1
  145. package/dist/yahoosspBidAdapter.js +1 -1
  146. package/dist/yieldmoBidAdapter.js +1 -1
  147. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  148. package/libraries/cmp/cmpClient.js +139 -0
  149. package/libraries/mspa/activityControls.js +91 -0
  150. package/modules/admanBidAdapter.js +5 -0
  151. package/modules/amxBidAdapter.js +11 -12
  152. package/modules/bedigitechBidAdapter.js +15 -12
  153. package/modules/bedigitechBidAdapter.md +2 -2
  154. package/modules/beopBidAdapter.js +0 -4
  155. package/modules/bidwatchAnalyticsAdapter.js +33 -5
  156. package/modules/bridBidAdapter.js +223 -0
  157. package/modules/categoryTranslation.js +3 -2
  158. package/modules/colossussspBidAdapter.js +9 -0
  159. package/modules/conceptxBidAdapter.js +6 -3
  160. package/modules/consentManagement.js +12 -86
  161. package/modules/consentManagementGpp.js +47 -126
  162. package/modules/consentManagementUsp.js +19 -97
  163. package/modules/freepassBidAdapter.js +98 -0
  164. package/modules/freepassBidAdapter.md +31 -0
  165. package/modules/freepassIdSystem.md +1 -1
  166. package/modules/gppControl_usnat.js +11 -0
  167. package/modules/greenbidsAnalyticsAdapter.js +7 -13
  168. package/modules/gridBidAdapter.js +3 -4
  169. package/modules/intentIqIdSystem.js +11 -9
  170. package/modules/ixBidAdapter.js +284 -55
  171. package/modules/kiviadsBidAdapter.js +212 -0
  172. package/modules/kiviadsBidAdapter.md +79 -0
  173. package/modules/liveIntentIdSystem.js +8 -3
  174. package/modules/mediasquareBidAdapter.js +19 -23
  175. package/modules/mgidXBidAdapter.js +263 -0
  176. package/modules/mgidXBidAdapter.md +79 -0
  177. package/modules/oxxionAnalyticsAdapter.js +33 -5
  178. package/modules/oxxionRtdProvider.js +124 -11
  179. package/modules/oxxionRtdProvider.md +19 -4
  180. package/modules/pubmaticBidAdapter.js +18 -2
  181. package/modules/rtbhouseBidAdapter.js +9 -2
  182. package/modules/rtbhouseBidAdapter.md +27 -8
  183. package/modules/rubiconBidAdapter.js +13 -1
  184. package/modules/sharethroughBidAdapter.js +14 -0
  185. package/modules/sonobiBidAdapter.js +4 -7
  186. package/modules/tripleliftBidAdapter.js +21 -1
  187. package/modules/userId/eids.js +29 -0
  188. package/modules/userId/eids.md +19 -2
  189. package/modules/userId/index.js +78 -29
  190. package/modules/userId/userId.md +3 -0
  191. package/package.json +1 -1
  192. package/src/activities/params.js +4 -1
  193. package/test/spec/libraries/cmp/cmpClient_spec.js +233 -0
  194. package/test/spec/libraries/mspa/activityControls_spec.js +315 -0
  195. package/test/spec/modules/admanBidAdapter_spec.js +8 -2
  196. package/test/spec/modules/adqueryBidAdapter_spec.js +5 -1
  197. package/test/spec/modules/amxBidAdapter_spec.js +6 -3
  198. package/test/spec/modules/bedigitechBidAdapter_spec.js +25 -36
  199. package/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +21 -1
  200. package/test/spec/modules/bridBidAdapter_spec.js +129 -0
  201. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +9 -7
  202. package/test/spec/modules/chtnwBidAdapter_spec.js +4 -1
  203. package/test/spec/modules/colossussspBidAdapter_spec.js +29 -0
  204. package/test/spec/modules/consentManagementGpp_spec.js +84 -7
  205. package/test/spec/modules/consentManagement_spec.js +8 -18
  206. package/test/spec/modules/datablocksBidAdapter_spec.js +7 -3
  207. package/test/spec/modules/eids_spec.js +87 -0
  208. package/test/spec/modules/freepassBidAdapter_spec.js +161 -0
  209. package/test/spec/modules/greenbidsAnalyticsAdapter_spec.js +0 -15
  210. package/test/spec/modules/gridBidAdapter_spec.js +29 -28
  211. package/test/spec/modules/insticatorBidAdapter_spec.js +6 -2
  212. package/test/spec/modules/intentIqIdSystem_spec.js +36 -2
  213. package/test/spec/modules/ixBidAdapter_spec.js +785 -15
  214. package/test/spec/modules/kiviadsBidAdapter_spec.js +404 -0
  215. package/test/spec/modules/lassoBidAdapter_spec.js +6 -4
  216. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +17 -2
  217. package/test/spec/modules/liveIntentIdSystem_spec.js +11 -6
  218. package/test/spec/modules/mediasquareBidAdapter_spec.js +3 -0
  219. package/test/spec/modules/mgidXBidAdapter_spec.js +426 -0
  220. package/test/spec/modules/onetagBidAdapter_spec.js +81 -75
  221. package/test/spec/modules/orbidderBidAdapter_spec.js +6 -3
  222. package/test/spec/modules/oxxionAnalyticsAdapter_spec.js +21 -2
  223. package/test/spec/modules/oxxionRtdProvider_spec.js +113 -1
  224. package/test/spec/modules/pubmaticBidAdapter_spec.js +25 -0
  225. package/test/spec/modules/relaidoBidAdapter_spec.js +4 -3
  226. package/test/spec/modules/rtbhouseBidAdapter_spec.js +35 -0
  227. package/test/spec/modules/rubiconBidAdapter_spec.js +41 -0
  228. package/test/spec/modules/sharethroughBidAdapter_spec.js +75 -0
  229. package/test/spec/modules/sonobiBidAdapter_spec.js +15 -15
  230. package/test/spec/modules/tripleliftBidAdapter_spec.js +20 -1
  231. package/test/spec/modules/ucfunnelBidAdapter_spec.js +37 -16
  232. package/test/spec/modules/userId_spec.js +393 -6
@@ -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.0.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);
@@ -0,0 +1,233 @@
1
+ import {cmpClient} from '../../../../libraries/cmp/cmpClient.js';
2
+
3
+ describe('cmpClient', () => {
4
+ function mockWindow(props = {}) {
5
+ let listeners = [];
6
+ const win = {
7
+ addEventListener: sinon.stub().callsFake((evt, listener) => {
8
+ evt === 'message' && listeners.push(listener)
9
+ }),
10
+ postMessage: sinon.stub().callsFake((msg) => {
11
+ listeners.forEach(ln => ln({data: msg}))
12
+ }),
13
+ ...props,
14
+ };
15
+ win.top = win.parent?.top || win;
16
+ return win;
17
+ }
18
+
19
+ it('should return undefined when there is no CMP', () => {
20
+ expect(cmpClient({apiName: 'missing'}, mockWindow())).to.not.exist;
21
+ });
22
+
23
+ it('should return undefined when parent is inaccessible', () => {
24
+ const win = mockWindow();
25
+ win.top = mockWindow();
26
+ expect(cmpClient({apiName: 'missing'}, win)).to.not.exist;
27
+ })
28
+
29
+ describe('direct access', () => {
30
+ let mockApiFn;
31
+ beforeEach(() => {
32
+ mockApiFn = sinon.stub();
33
+ })
34
+ Object.entries({
35
+ 'on same frame': () => mockWindow({mockApiFn}),
36
+ 'on parent frame': () => mockWindow({parent: mockWindow({parent: mockWindow({parent: mockWindow(), mockApiFn})})}),
37
+ }).forEach(([t, mkWindow]) => {
38
+ describe(t, () => {
39
+ let win, mkClient;
40
+ beforeEach(() => {
41
+ win = mkWindow();
42
+ mkClient = (opts) => cmpClient(Object.assign({apiName: 'mockApiFn'}, opts), win)
43
+ });
44
+
45
+ it('should mark client function as direct', () => {
46
+ expect(mkClient().isDirect).to.equal(true);
47
+ });
48
+
49
+ it('should find and call the CMP api function', () => {
50
+ mkClient()({command: 'mockCmd'});
51
+ sinon.assert.calledWith(mockApiFn, 'mockCmd');
52
+ });
53
+
54
+ describe('should return a promise that', () => {
55
+ let cbResult;
56
+ beforeEach(() => {
57
+ cbResult = [];
58
+ mockApiFn.callsFake((cmd, callback) => {
59
+ if (typeof callback === 'function') {
60
+ callback.apply(this, cbResult);
61
+ }
62
+ return 'val'
63
+ })
64
+ })
65
+ Object.entries({
66
+ callback: [sinon.stub(), 'undefined', undefined],
67
+ 'no callback': [undefined, 'api return value', 'val']
68
+ }).forEach(([t, [callback, tResult, expectedResult]]) => {
69
+ describe(`when ${t} is provided`, () => {
70
+ Object.entries({
71
+ 'no success flag': undefined,
72
+ 'success is set': true
73
+ }).forEach(([t, success]) => {
74
+ it(`resolves to ${tResult} (${t})`, (done) => {
75
+ cbResult = ['cbVal', success];
76
+ mkClient()({callback}).then((val) => {
77
+ expect(val).to.equal(expectedResult);
78
+ done();
79
+ })
80
+ })
81
+ });
82
+ })
83
+ });
84
+
85
+ it('rejects to undefined when callback is provided and success = false', () => {
86
+ cbResult = ['cbVal', false];
87
+ mkClient()({callback: sinon.stub()}).catch(val => {
88
+ expect(val).to.equal('cbVal');
89
+ done();
90
+ })
91
+ });
92
+
93
+ it('rejects when CMP api throws', (done) => {
94
+ mockApiFn.reset();
95
+ const e = new Error();
96
+ mockApiFn.throws(e);
97
+ mkClient()({}).catch(val => {
98
+ expect(val).to.equal(e);
99
+ done();
100
+ });
101
+ })
102
+ })
103
+
104
+ it('should use apiArgs to choose and order the arguments to pass to the API fn', () => {
105
+ mkClient({apiArgs: ['parameter', 'command']})({
106
+ command: 'mockCmd',
107
+ parameter: 'mockParam',
108
+ callback() {}
109
+ });
110
+ sinon.assert.calledWith(mockApiFn, 'mockParam', 'mockCmd');
111
+ });
112
+ })
113
+ })
114
+ })
115
+
116
+ describe('postMessage access', () => {
117
+ let messenger, win, response;
118
+ beforeEach(() => {
119
+ response = {};
120
+ messenger = sinon.stub().callsFake((msg) => {
121
+ if (msg.mockApiCall) {
122
+ win.postMessage({mockApiReturn: {callId: msg.mockApiCall.callId, ...response}});
123
+ }
124
+ });
125
+ });
126
+
127
+ function mkClient(options) {
128
+ return cmpClient(Object.assign({apiName: 'mockApi'}, options), win);
129
+ }
130
+
131
+ Object.entries({
132
+ 'on same frame': () => {
133
+ win = mockWindow({frames: {mockApiLocator: true}});
134
+ win.addEventListener('message', (evt) => messenger(evt.data));
135
+ },
136
+ 'on parent frame': () => {
137
+ win = mockWindow({parent: mockWindow({frames: {mockApiLocator: true}})})
138
+ win.parent.addEventListener('message', evt => messenger(evt.data))
139
+ }
140
+ }).forEach(([t, setup]) => {
141
+ describe(t, () => {
142
+ beforeEach(setup);
143
+
144
+ it('should mark client as not direct', () => {
145
+ expect(mkClient().isDirect).to.equal(false);
146
+ });
147
+
148
+ it('should find and message the CMP frame', () => {
149
+ mkClient()({command: 'mockCmd', parameter: 'param'});
150
+ sinon.assert.calledWithMatch(messenger, {
151
+ mockApiCall: {
152
+ command: 'mockCmd',
153
+ parameter: 'param'
154
+ }
155
+ })
156
+ });
157
+
158
+ it('should use apiArgs to choose what to include in the message payload', () => {
159
+ mkClient({apiArgs: ['command']})({
160
+ command: 'cmd',
161
+ parameter: 'param'
162
+ });
163
+ sinon.assert.calledWithMatch(messenger, sinon.match((arg) => {
164
+ return arg.mockApiCall.command === 'cmd' &&
165
+ !arg.mockApiCall.hasOwnProperty('parameter');
166
+ }))
167
+ });
168
+
169
+ it('should not include callback in the payload, but still run it on response', () => {
170
+ const cb = sinon.stub();
171
+ mkClient({apiArgs: ['command', 'callback']})({
172
+ command: 'cmd',
173
+ callback: cb
174
+ });
175
+ sinon.assert.calledWithMatch(messenger, sinon.match(arg => !arg.mockApiCall.hasOwnProperty('callback')));
176
+ sinon.assert.called(cb);
177
+ });
178
+
179
+ it('should use callbackArgs to decide what to pass to callback', () => {
180
+ const cb = sinon.stub();
181
+ response = {a: 'one', b: 'two'};
182
+ mkClient({callbackArgs: ['a', 'b']})({callback: cb});
183
+ sinon.assert.calledWith(cb, 'one', 'two');
184
+ })
185
+
186
+ describe('should return a promise that', () => {
187
+ beforeEach(() => {
188
+ response = {returnValue: 'val'}
189
+ })
190
+ Object.entries({
191
+ 'callback': [sinon.stub(), 'undefined', undefined],
192
+ 'no callback': [undefined, 'response returnValue', 'val'],
193
+ }).forEach(([t, [callback, tResult, expectedResult]]) => {
194
+ describe(`when ${t} is provided`, () => {
195
+ Object.entries({
196
+ 'no success flag': {},
197
+ 'with success flag': {success: true}
198
+ }).forEach(([t, resp]) => {
199
+ it(`resolves to ${tResult} (${t})`, () => {
200
+ Object.assign(response, resp);
201
+ mkClient()({callback}).then((val) => {
202
+ expect(val).to.equal(expectedResult);
203
+ })
204
+ })
205
+ });
206
+
207
+ it(`rejects to ${tResult} when success = false`, (done) => {
208
+ response.success = false;
209
+ mkClient()({callback}).catch((err) => {
210
+ expect(err).to.equal(expectedResult);
211
+ done();
212
+ });
213
+ });
214
+ })
215
+ });
216
+ });
217
+
218
+ it('should re-use callback for messages with same callId', () => {
219
+ messenger.reset();
220
+ let callId;
221
+ messenger.callsFake((msg) => { if (msg.mockApiCall) callId = msg.mockApiCall.callId });
222
+ const callback = sinon.stub();
223
+ mkClient()({callback});
224
+ expect(callId).to.exist;
225
+ win.postMessage({mockApiReturn: {callId, returnValue: 'a'}});
226
+ win.postMessage({mockApiReturn: {callId, returnValue: 'b'}});
227
+ sinon.assert.calledWith(callback, 'a');
228
+ sinon.assert.calledWith(callback, 'b');
229
+ })
230
+ });
231
+ });
232
+ });
233
+ });