prebid.js 7.4.0 → 7.7.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 (239) hide show
  1. package/.circleci/config.yml +11 -6
  2. package/dist/1plusXRtdProvider.js +1 -0
  3. package/dist/33acrossBidAdapter.js +1 -1
  4. package/dist/adagioBidAdapter.js +1 -1
  5. package/dist/adbookpspBidAdapter.js +1 -1
  6. package/dist/adgenerationBidAdapter.js +1 -1
  7. package/dist/adnuntiusBidAdapter.js +1 -1
  8. package/dist/adoceanBidAdapter.js +1 -1
  9. package/dist/adotBidAdapter.js +1 -1
  10. package/dist/adrelevantisBidAdapter.js +1 -1
  11. package/dist/adrinoBidAdapter.js +1 -1
  12. package/dist/adtelligentBidAdapter.js +1 -1
  13. package/dist/adxcgBidAdapter.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/atsAnalyticsAdapter.js +1 -1
  21. package/dist/axonixBidAdapter.js +1 -1
  22. package/dist/bidglassBidAdapter.js +1 -1
  23. package/dist/big-richmediaBidAdapter.js +1 -1
  24. package/dist/bliinkBidAdapter.js +1 -1
  25. package/dist/bridgewellBidAdapter.js +1 -1
  26. package/dist/brightMountainMediaBidAdapter.js +1 -1
  27. package/dist/byDataAnalyticsAdapter.js +1 -1
  28. package/dist/concertBidAdapter.js +1 -1
  29. package/dist/connectadBidAdapter.js +1 -1
  30. package/dist/consumableBidAdapter.js +1 -1
  31. package/dist/conversantBidAdapter.js +1 -1
  32. package/dist/craftBidAdapter.js +1 -1
  33. package/dist/criteoBidAdapter.js +1 -1
  34. package/dist/currency.js +1 -1
  35. package/dist/dspxBidAdapter.js +1 -1
  36. package/dist/eplanningBidAdapter.js +1 -1
  37. package/dist/finativeBidAdapter.js +1 -1
  38. package/dist/gdprEnforcement.js +1 -1
  39. package/dist/glimpseBidAdapter.js +1 -1
  40. package/dist/gmosspBidAdapter.js +1 -1
  41. package/dist/goldbachBidAdapter.js +1 -1
  42. package/dist/gridBidAdapter.js +1 -1
  43. package/dist/gridNMBidAdapter.js +1 -1
  44. package/dist/gumgumBidAdapter.js +1 -1
  45. package/dist/h12mediaBidAdapter.js +1 -1
  46. package/dist/hadronIdSystem.js +1 -1
  47. package/dist/hadronRtdProvider.js +1 -1
  48. package/dist/id5IdSystem.js +1 -1
  49. package/dist/imRtdProvider.js +1 -1
  50. package/dist/impactifyBidAdapter.js +1 -1
  51. package/dist/improvedigitalBidAdapter.js +1 -1
  52. package/dist/inmarBidAdapter.js +1 -1
  53. package/dist/insticatorBidAdapter.js +1 -1
  54. package/dist/ixBidAdapter.js +1 -1
  55. package/dist/jixieBidAdapter.js +1 -1
  56. package/dist/justpremiumBidAdapter.js +1 -1
  57. package/dist/kargoAnalyticsAdapter.js +1 -1
  58. package/dist/konduitAnalyticsAdapter.js +1 -1
  59. package/dist/kueezBidAdapter.js +1 -1
  60. package/dist/lassoBidAdapter.js +1 -1
  61. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  62. package/dist/logicadBidAdapter.js +1 -1
  63. package/dist/loglyliftBidAdapter.js +1 -1
  64. package/dist/malltvAnalyticsAdapter.js +1 -1
  65. package/dist/marsmediaBidAdapter.js +1 -1
  66. package/dist/mediafuseBidAdapter.js +1 -1
  67. package/dist/mediasquareBidAdapter.js +1 -1
  68. package/dist/mgidBidAdapter.js +1 -1
  69. package/dist/minutemediaBidAdapter.js +1 -1
  70. package/dist/naveggIdSystem.js +1 -1
  71. package/dist/newspassidBidAdapter.js +1 -0
  72. package/dist/nextMillenniumBidAdapter.js +1 -1
  73. package/dist/not-for-prod/prebid.js +131 -128
  74. package/dist/oguryBidAdapter.js +1 -1
  75. package/dist/onetagBidAdapter.js +1 -1
  76. package/dist/ooloAnalyticsAdapter.js +1 -1
  77. package/dist/outbrainBidAdapter.js +1 -1
  78. package/dist/parrableIdSystem.js +1 -1
  79. package/dist/pixfutureBidAdapter.js +1 -1
  80. package/dist/prebid-core.js +1 -1
  81. package/dist/prebidServerBidAdapter.js +1 -1
  82. package/dist/priceFloors.js +1 -1
  83. package/dist/pubCommonId.js +1 -1
  84. package/dist/publinkIdSystem.js +1 -1
  85. package/dist/pubmaticBidAdapter.js +1 -1
  86. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  87. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  88. package/dist/pxyzBidAdapter.js +1 -1
  89. package/dist/quantcastBidAdapter.js +1 -1
  90. package/dist/rasBidAdapter.js +1 -0
  91. package/dist/readpeakBidAdapter.js +1 -1
  92. package/dist/relaidoBidAdapter.js +1 -1
  93. package/dist/rhythmoneBidAdapter.js +1 -1
  94. package/dist/riseBidAdapter.js +1 -1
  95. package/dist/rubiconAnalyticsAdapter.js +1 -1
  96. package/dist/rubiconBidAdapter.js +1 -1
  97. package/dist/seedingAllianceBidAdapter.js +1 -1
  98. package/dist/seedtagBidAdapter.js +1 -1
  99. package/dist/sharedIdSystem.js +1 -1
  100. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  101. package/dist/sharethroughBidAdapter.js +1 -1
  102. package/dist/shinezBidAdapter.js +1 -1
  103. package/dist/smaatoBidAdapter.js +1 -1
  104. package/dist/smartadserverBidAdapter.js +1 -1
  105. package/dist/smartxBidAdapter.js +1 -1
  106. package/dist/smilewantedBidAdapter.js +1 -1
  107. package/dist/sonobiBidAdapter.js +1 -1
  108. package/dist/sovrnAnalyticsAdapter.js +1 -1
  109. package/dist/sovrnBidAdapter.js +1 -1
  110. package/dist/sspBCBidAdapter.js +1 -1
  111. package/dist/sublimeBidAdapter.js +1 -1
  112. package/dist/synacormediaBidAdapter.js +1 -1
  113. package/dist/taboolaBidAdapter.js +1 -1
  114. package/dist/targetVideoBidAdapter.js +1 -1
  115. package/dist/teadsBidAdapter.js +1 -1
  116. package/dist/trionBidAdapter.js +1 -1
  117. package/dist/tripleliftBidAdapter.js +1 -1
  118. package/dist/ttdBidAdapter.js +1 -1
  119. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  120. package/dist/underdogmediaBidAdapter.js +1 -1
  121. package/dist/undertoneBidAdapter.js +1 -1
  122. package/dist/userId.js +1 -1
  123. package/dist/vidazooBidAdapter.js +1 -1
  124. package/dist/videobyteBidAdapter.js +1 -1
  125. package/dist/visxBidAdapter.js +1 -1
  126. package/dist/vuukleBidAdapter.js +1 -1
  127. package/dist/widespaceBidAdapter.js +1 -1
  128. package/dist/winrBidAdapter.js +1 -1
  129. package/dist/yahoosspBidAdapter.js +1 -1
  130. package/dist/yieldmoBidAdapter.js +1 -1
  131. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  132. package/integrationExamples/gpt/1plusXRtdProviderExample.html +112 -0
  133. package/karma.conf.maker.js +3 -1
  134. package/modules/.submodules.json +2 -1
  135. package/modules/1plusXRtdProvider.js +251 -0
  136. package/modules/1plusXRtdProvider.md +65 -0
  137. package/modules/adgenerationBidAdapter.js +24 -1
  138. package/modules/adnuntiusBidAdapter.js +26 -8
  139. package/modules/adoceanBidAdapter.js +10 -3
  140. package/modules/adotBidAdapter.js +13 -4
  141. package/modules/adrinoBidAdapter.js +10 -2
  142. package/modules/adrinoBidAdapter.md +6 -0
  143. package/modules/adtelligentBidAdapter.js +2 -1
  144. package/modules/appnexusBidAdapter.js +3 -3
  145. package/modules/atsAnalyticsAdapter.js +4 -5
  146. package/modules/big-richmediaBidAdapter.js +3 -3
  147. package/modules/bliinkBidAdapter.js +120 -193
  148. package/modules/bliinkBidAdapter.md +2 -5
  149. package/modules/byDataAnalyticsAdapter.js +172 -74
  150. package/modules/byDataAnalyticsAdapter.md +5 -6
  151. package/modules/consumableBidAdapter.js +21 -1
  152. package/modules/criteoBidAdapter.js +7 -1
  153. package/modules/currency.js +2 -2
  154. package/modules/cwireBidAdapter.md +1 -1
  155. package/modules/eplanningBidAdapter.js +82 -97
  156. package/modules/gdprEnforcement.js +8 -14
  157. package/modules/gridNMBidAdapter.js +45 -4
  158. package/modules/hadronAnalyticsAdapter.md +5 -5
  159. package/modules/hadronIdSystem.js +18 -5
  160. package/modules/hadronIdSystem.md +15 -11
  161. package/modules/hadronRtdProvider.js +14 -1
  162. package/modules/hadronRtdProvider.md +17 -13
  163. package/modules/imRtdProvider.js +0 -8
  164. package/modules/impactifyBidAdapter.js +6 -2
  165. package/modules/ixBidAdapter.js +133 -23
  166. package/modules/ixBidAdapter.md +2 -5
  167. package/modules/jixieBidAdapter.js +10 -10
  168. package/modules/kargoAnalyticsAdapter.js +88 -6
  169. package/modules/kargoAnalyticsAdapter.md +33 -0
  170. package/modules/minutemediaBidAdapter.js +1 -0
  171. package/modules/naveggIdSystem.js +1 -12
  172. package/modules/newspassidBidAdapter.js +649 -0
  173. package/modules/nextMillenniumBidAdapter.js +17 -1
  174. package/modules/nextMillenniumBidAdapter.md +1 -1
  175. package/modules/oguryBidAdapter.js +2 -0
  176. package/modules/onetagBidAdapter.js +44 -7
  177. package/modules/prebidServerBidAdapter/index.js +7 -0
  178. package/modules/priceFloors.js +1 -1
  179. package/modules/pubCommonId.js +1 -2
  180. package/modules/pubxaiAnalyticsAdapter.js +6 -1
  181. package/modules/rasBidAdapter.js +149 -0
  182. package/modules/rasBidAdapter.md +50 -0
  183. package/modules/rubiconBidAdapter.js +5 -0
  184. package/modules/seedingAllianceBidAdapter.js +3 -0
  185. package/modules/seedtagBidAdapter.js +37 -1
  186. package/modules/sharedIdSystem.js +11 -5
  187. package/modules/sharethroughBidAdapter.js +9 -24
  188. package/modules/taboolaBidAdapter.js +1 -1
  189. package/modules/taboolaBidAdapter.md +3 -3
  190. package/modules/targetVideoBidAdapter.js +18 -0
  191. package/modules/userId/index.js +39 -21
  192. package/package.json +1 -1
  193. package/src/auction.js +6 -5
  194. package/src/consentHandler.js +11 -11
  195. package/src/debugging.js +5 -3
  196. package/src/hook.js +2 -2
  197. package/src/storageManager.js +4 -5
  198. package/src/utils/promise.js +96 -21
  199. package/src/utils.js +3 -2
  200. package/test/helpers/consentData.js +2 -1
  201. package/test/spec/auctionmanager_spec.js +1 -6
  202. package/test/spec/debugging_spec.js +2 -2
  203. package/test/spec/modules/1plusXRtdProvider_spec.js +430 -0
  204. package/test/spec/modules/adgenerationBidAdapter_spec.js +52 -4
  205. package/test/spec/modules/adnuntiusBidAdapter_spec.js +126 -14
  206. package/test/spec/modules/adoceanBidAdapter_spec.js +4 -1
  207. package/test/spec/modules/adotBidAdapter_spec.js +12 -9
  208. package/test/spec/modules/adrinoBidAdapter_spec.js +22 -0
  209. package/test/spec/modules/appnexusBidAdapter_spec.js +165 -156
  210. package/test/spec/modules/bliinkBidAdapter_spec.js +323 -136
  211. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +74 -24
  212. package/test/spec/modules/consumableBidAdapter_spec.js +122 -1
  213. package/test/spec/modules/criteoBidAdapter_spec.js +15 -5
  214. package/test/spec/modules/eplanningBidAdapter_spec.js +58 -18
  215. package/test/spec/modules/gdprEnforcement_spec.js +53 -100
  216. package/test/spec/modules/gridNMBidAdapter_spec.js +32 -0
  217. package/test/spec/modules/hadronIdSystem_spec.js +2 -2
  218. package/test/spec/modules/idxIdSystem_spec.js +1 -1
  219. package/test/spec/modules/imRtdProvider_spec.js +0 -1
  220. package/test/spec/modules/ixBidAdapter_spec.js +212 -5
  221. package/test/spec/modules/jixieBidAdapter_spec.js +8 -8
  222. package/test/spec/modules/kargoAnalyticsAdapter_spec.js +42 -0
  223. package/test/spec/modules/minutemediaBidAdapter_spec.js +3 -0
  224. package/test/spec/modules/newspassidBidAdapter_spec.js +1793 -0
  225. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +20 -0
  226. package/test/spec/modules/onetagBidAdapter_spec.js +53 -4
  227. package/test/spec/modules/parrableIdSystem_spec.js +2 -1
  228. package/test/spec/modules/prebidServerBidAdapter_spec.js +20 -0
  229. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +5 -0
  230. package/test/spec/modules/rasBidAdapter_spec.js +190 -0
  231. package/test/spec/modules/rubiconBidAdapter_spec.js +27 -0
  232. package/test/spec/modules/seedtagBidAdapter_spec.js +29 -0
  233. package/test/spec/modules/sharethroughBidAdapter_spec.js +4 -4
  234. package/test/spec/modules/taboolaBidAdapter_spec.js +1 -1
  235. package/test/spec/modules/targetVideoBidAdapter_spec.js +43 -0
  236. package/test/spec/modules/userId_spec.js +15 -2
  237. package/test/spec/unit/pbjs_api_spec.js +1 -5
  238. package/test/spec/unit/utils/promise_spec.js +283 -38
  239. package/test/helpers/syncPromise.js +0 -71
@@ -152,7 +152,7 @@ import {
152
152
  isEmpty
153
153
  } from '../../src/utils.js';
154
154
  import {getPPID as coreGetPPID} from '../../src/adserver.js';
155
- import {promiseControls} from '../../src/utils/promise.js';
155
+ import {defer, GreedyPromise} from '../../src/utils/promise.js';
156
156
  import {hasPurpose1Consent} from '../../src/utils/gpdr.js';
157
157
 
158
158
  const MODULE_NAME = 'User ID';
@@ -504,15 +504,11 @@ function addIdDataToAdUnitBids(adUnits, submodules) {
504
504
  });
505
505
  }
506
506
 
507
- function delayFor(ms) {
508
- return new Promise((resolve) => setTimeout(resolve, ms));
509
- }
510
-
511
507
  const INIT_CANCELED = {};
512
508
 
513
- function idSystemInitializer({delay = delayFor} = {}) {
514
- const startInit = promiseControls();
515
- const startCallbacks = promiseControls();
509
+ function idSystemInitializer({delay = GreedyPromise.timeout} = {}) {
510
+ const startInit = defer();
511
+ const startCallbacks = defer();
516
512
  let cancel;
517
513
  let initialized = false;
518
514
 
@@ -520,8 +516,8 @@ function idSystemInitializer({delay = delayFor} = {}) {
520
516
  if (cancel != null) {
521
517
  cancel.reject(INIT_CANCELED);
522
518
  }
523
- cancel = promiseControls();
524
- return Promise.race([promise, cancel.promise]);
519
+ cancel = defer();
520
+ return GreedyPromise.race([promise, cancel.promise]);
525
521
  }
526
522
 
527
523
  // grab a reference to global vars so that the promise chains remain isolated;
@@ -540,7 +536,7 @@ function idSystemInitializer({delay = delayFor} = {}) {
540
536
  }
541
537
 
542
538
  let done = cancelAndTry(
543
- Promise.all([hooksReady, startInit.promise])
539
+ GreedyPromise.all([hooksReady, startInit.promise])
544
540
  .then(() => gdprDataHandler.promise)
545
541
  .then(checkRefs((consentData) => {
546
542
  initSubmodules(initModules, allModules, consentData);
@@ -549,7 +545,7 @@ function idSystemInitializer({delay = delayFor} = {}) {
549
545
  .then(checkRefs(() => {
550
546
  const modWithCb = initModules.filter(item => isFn(item.callback));
551
547
  if (modWithCb.length) {
552
- return new Promise((resolve) => processSubmoduleCallbacks(modWithCb, resolve));
548
+ return new GreedyPromise((resolve) => processSubmoduleCallbacks(modWithCb, resolve));
553
549
  }
554
550
  }))
555
551
  );
@@ -573,7 +569,7 @@ function idSystemInitializer({delay = delayFor} = {}) {
573
569
  });
574
570
  }
575
571
  }
576
- if (refresh) {
572
+ if (refresh && initialized) {
577
573
  done = cancelAndTry(
578
574
  done
579
575
  .catch(() => null)
@@ -588,7 +584,7 @@ function idSystemInitializer({delay = delayFor} = {}) {
588
584
  return sm.callback != null;
589
585
  });
590
586
  if (cbModules.length) {
591
- return new Promise((resolve) => processSubmoduleCallbacks(cbModules, resolve));
587
+ return new GreedyPromise((resolve) => processSubmoduleCallbacks(cbModules, resolve));
592
588
  }
593
589
  }))
594
590
  );
@@ -621,8 +617,8 @@ function getPPID() {
621
617
  * @param {Object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
622
618
  * @param {function} fn required; The next function in the chain, used by hook.js
623
619
  */
624
- export function requestBidsHook(fn, reqBidsConfigObj, {delay = delayFor} = {}) {
625
- Promise.race([
620
+ export function requestBidsHook(fn, reqBidsConfigObj, {delay = GreedyPromise.timeout} = {}) {
621
+ GreedyPromise.race([
626
622
  getUserIdsAsync(),
627
623
  delay(auctionDelay)
628
624
  ]).then(() => {
@@ -767,7 +763,16 @@ function refreshUserIds({submoduleNames} = {}, callback) {
767
763
  */
768
764
 
769
765
  function getUserIdsAsync() {
770
- return initIdSystem().then(() => getUserIds(), (e) => e === INIT_CANCELED ? getUserIdsAsync() : Promise.reject(e));
766
+ return initIdSystem().then(
767
+ () => getUserIds(),
768
+ (e) =>
769
+ e === INIT_CANCELED
770
+ // there's a pending refresh - because GreedyPromise runs this synchronously, we are now in the middle
771
+ // of canceling the previous init, before the refresh logic has had a chance to run.
772
+ // Use a "normal" Promise to clear the stack and let it complete (or this will just recurse infinitely)
773
+ ? Promise.resolve().then(getUserIdsAsync)
774
+ : GreedyPromise.reject(e)
775
+ );
771
776
  }
772
777
 
773
778
  /**
@@ -914,6 +919,8 @@ function updateSubmodules() {
914
919
  return;
915
920
  }
916
921
  // do this to avoid reprocessing submodules
922
+ // TODO: the logic does not match the comment - addedSubmodules is always a copy of submoduleRegistry
923
+ // (if it did it would not be correct - it's not enough to find new modules, as others may have been removed or changed)
917
924
  const addedSubmodules = submoduleRegistry.filter(i => !find(submodules, j => j.name === i.name));
918
925
 
919
926
  submodules.splice(0, submodules.length);
@@ -949,6 +956,17 @@ export function attachIdSystem(submodule) {
949
956
  if (!find(submoduleRegistry, i => i.name === submodule.name)) {
950
957
  submoduleRegistry.push(submodule);
951
958
  updateSubmodules();
959
+ // TODO: a test case wants this to work even if called after init (the setConfig({userId}))
960
+ // so we trigger a refresh. But is that even possible outside of tests?
961
+ initIdSystem({refresh: true, submoduleNames: [submodule.name]});
962
+ }
963
+ }
964
+
965
+ function normalizePromise(fn) {
966
+ // for public methods that return promises, make sure we return a "normal" one - to avoid
967
+ // exposing confusing stack traces
968
+ return function() {
969
+ return Promise.resolve(fn.apply(this, arguments));
952
970
  }
953
971
  }
954
972
 
@@ -957,7 +975,7 @@ export function attachIdSystem(submodule) {
957
975
  * so a callback is added to fire after the consentManagement module.
958
976
  * @param {{getConfig:function}} config
959
977
  */
960
- export function init(config, {delay = delayFor} = {}) {
978
+ export function init(config, {delay = GreedyPromise.timeout} = {}) {
961
979
  ppidSource = undefined;
962
980
  submodules = [];
963
981
  configRegistry = [];
@@ -1002,10 +1020,10 @@ export function init(config, {delay = delayFor} = {}) {
1002
1020
  // exposing getUserIds function in global-name-space so that userIds stored in Prebid can be used by external codes.
1003
1021
  (getGlobal()).getUserIds = getUserIds;
1004
1022
  (getGlobal()).getUserIdsAsEids = getUserIdsAsEids;
1005
- (getGlobal()).getEncryptedEidsForSource = getEncryptedEidsForSource;
1023
+ (getGlobal()).getEncryptedEidsForSource = normalizePromise(getEncryptedEidsForSource);
1006
1024
  (getGlobal()).registerSignalSources = registerSignalSources;
1007
- (getGlobal()).refreshUserIds = refreshUserIds;
1008
- (getGlobal()).getUserIdsAsync = getUserIdsAsync;
1025
+ (getGlobal()).refreshUserIds = normalizePromise(refreshUserIds);
1026
+ (getGlobal()).getUserIdsAsync = normalizePromise(getUserIdsAsync);
1009
1027
  (getGlobal()).getUserIdsAsEidBySource = getUserIdsAsEidBySource;
1010
1028
  }
1011
1029
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "7.4.0",
3
+ "version": "7.7.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
package/src/auction.js CHANGED
@@ -76,6 +76,7 @@ import {bidderSettings} from './bidderSettings.js';
76
76
  import * as events from './events.js'
77
77
  import adapterManager from './adapterManager.js';
78
78
  import CONSTANTS from './constants.json';
79
+ import {GreedyPromise} from './utils/promise.js';
79
80
 
80
81
  const { syncUsers } = userSync;
81
82
 
@@ -384,9 +385,9 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM
384
385
 
385
386
  function waitFor(requestId, result) {
386
387
  if (ready[requestId] == null) {
387
- ready[requestId] = Promise.resolve();
388
+ ready[requestId] = GreedyPromise.resolve();
388
389
  }
389
- ready[requestId] = ready[requestId].then(() => Promise.resolve(result).catch(() => {}))
390
+ ready[requestId] = ready[requestId].then(() => GreedyPromise.resolve(result).catch(() => {}))
390
391
  }
391
392
 
392
393
  function guard(bidderRequest, fn) {
@@ -398,9 +399,9 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM
398
399
  const wait = ready[bidderRequest.bidderRequestId];
399
400
  const orphanWait = ready['']; // also wait for "orphan" responses that are not associated with any request
400
401
  if ((wait != null || orphanWait != null) && timeRemaining > 0) {
401
- Promise.race([
402
- new Promise((resolve) => setTimeout(resolve, timeRemaining)),
403
- Promise.resolve(orphanWait).then(() => wait)
402
+ GreedyPromise.race([
403
+ GreedyPromise.timeout(timeRemaining),
404
+ GreedyPromise.resolve(orphanWait).then(() => wait)
404
405
  ]).then(fn);
405
406
  } else {
406
407
  fn();
@@ -1,10 +1,10 @@
1
1
  import {isStr, timestamp} from './utils.js';
2
+ import {defer, GreedyPromise} from './utils/promise.js';
2
3
 
3
4
  export class ConsentHandler {
4
5
  #enabled;
5
6
  #data;
6
- #promise;
7
- #resolve;
7
+ #defer;
8
8
  #ready;
9
9
  generatedTime;
10
10
 
@@ -12,17 +12,17 @@ export class ConsentHandler {
12
12
  this.reset();
13
13
  }
14
14
 
15
+ #resolve(data) {
16
+ this.#ready = true;
17
+ this.#data = data;
18
+ this.#defer.resolve(data);
19
+ }
20
+
15
21
  /**
16
22
  * reset this handler (mainly for tests)
17
23
  */
18
24
  reset() {
19
- this.#promise = new Promise((resolve) => {
20
- this.#resolve = (data) => {
21
- this.#ready = true;
22
- this.#data = data;
23
- resolve(data);
24
- };
25
- });
25
+ this.#defer = defer();
26
26
  this.#enabled = false;
27
27
  this.#data = null;
28
28
  this.#ready = false;
@@ -56,12 +56,12 @@ export class ConsentHandler {
56
56
  */
57
57
  get promise() {
58
58
  if (this.#ready) {
59
- return Promise.resolve(this.#data);
59
+ return GreedyPromise.resolve(this.#data);
60
60
  }
61
61
  if (!this.#enabled) {
62
62
  this.#resolve(null);
63
63
  }
64
- return this.#promise;
64
+ return this.#defer.promise;
65
65
  }
66
66
 
67
67
  setConsentData(data, time = timestamp()) {
package/src/debugging.js CHANGED
@@ -4,6 +4,7 @@ import {getGlobal} from './prebidGlobal.js';
4
4
  import {logMessage, prefixLog} from './utils.js';
5
5
  import {createBid} from './bidfactory.js';
6
6
  import {loadExternalScript} from './adloader.js';
7
+ import {GreedyPromise} from './utils/promise.js';
7
8
 
8
9
  export const DEBUG_KEY = '__$$PREBID_GLOBAL$$_debugging__';
9
10
 
@@ -12,7 +13,7 @@ function isDebuggingInstalled() {
12
13
  }
13
14
 
14
15
  function loadScript(url) {
15
- return new Promise((resolve) => {
16
+ return new GreedyPromise((resolve) => {
16
17
  loadExternalScript(url, 'debugging', resolve);
17
18
  });
18
19
  }
@@ -21,7 +22,8 @@ export function debuggingModuleLoader({alreadyInstalled = isDebuggingInstalled,
21
22
  let loading = null;
22
23
  return function () {
23
24
  if (loading == null) {
24
- loading = new Promise((resolve, reject) => {
25
+ loading = new GreedyPromise((resolve, reject) => {
26
+ // run this in a 0-delay timeout to give installedModules time to be populated
25
27
  setTimeout(() => {
26
28
  if (alreadyInstalled()) {
27
29
  resolve();
@@ -44,7 +46,7 @@ export function debuggingControls({load = debuggingModuleLoader(), hook = getHoo
44
46
  let promise = null;
45
47
  let enabled = false;
46
48
  function waitForDebugging(next, ...args) {
47
- return (promise || Promise.resolve()).then(() => next.apply(this, args))
49
+ return (promise || GreedyPromise.resolve()).then(() => next.apply(this, args))
48
50
  }
49
51
  function enable() {
50
52
  if (!enabled) {
package/src/hook.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import funHooks from 'fun-hooks/no-eval/index.js';
2
- import {promiseControls} from './utils/promise.js';
2
+ import {defer} from './utils/promise.js';
3
3
 
4
4
  export let hook = funHooks({
5
5
  ready: funHooks.SYNC | funHooks.ASYNC | funHooks.QUEUE
6
6
  });
7
7
 
8
- const readyCtl = promiseControls();
8
+ const readyCtl = defer();
9
9
  hook.ready = (() => {
10
10
  const ready = hook.ready;
11
11
  return function () {
@@ -48,7 +48,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} =
48
48
  let hookDetails = {
49
49
  hasEnforcementHook: false
50
50
  }
51
- validateStorageEnforcement(gvlid, bidderCode || moduleName, moduleType, hookDetails, function(result) {
51
+ validateStorageEnforcement(gvlid, bidderCode || moduleName, hookDetails, function(result) {
52
52
  if (result && result.hasEnforcementHook) {
53
53
  value = cb(result);
54
54
  } else {
@@ -303,7 +303,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} =
303
303
  /**
304
304
  * This hook validates the storage enforcement if gdprEnforcement module is included
305
305
  */
306
- export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, moduleType, hookDetails, callback) {
306
+ export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, hookDetails, callback) {
307
307
  callback(hookDetails);
308
308
  }, 'validateStorageEnforcement');
309
309
 
@@ -322,13 +322,12 @@ export function getCoreStorageManager(moduleName) {
322
322
  * @param {Number=} gvlid? Vendor id - required for proper GDPR integration
323
323
  * @param {string=} bidderCode? - required for bid adapters
324
324
  * @param {string=} moduleName? module name
325
- * @param {string=} moduleType? module type
326
325
  */
327
- export function getStorageManager({gvlid, moduleName, bidderCode, moduleType} = {}) {
326
+ export function getStorageManager({gvlid, moduleName, bidderCode} = {}) {
328
327
  if (arguments.length > 1 || (arguments.length > 0 && !isPlainObject(arguments[0]))) {
329
328
  throw new Error('Invalid invocation for getStorageManager')
330
329
  }
331
- return newStorageManager({gvlid, moduleName, bidderCode, moduleType});
330
+ return newStorageManager({gvlid, moduleName, bidderCode});
332
331
  }
333
332
 
334
333
  export function resetData() {
@@ -1,36 +1,111 @@
1
1
  const SUCCESS = 0;
2
2
  const FAIL = 1;
3
- const RESULT = 2;
4
3
 
5
4
  /**
6
- * @returns a {promise, resolve, reject} trio where `promise` is resolved by calling `resolve` or `reject`.
5
+ * A version of Promise that runs callbacks synchronously when it can (i.e. after it's been fulfilled or rejected).
7
6
  */
8
- export function promiseControls({promiseFactory = (resolver) => new Promise(resolver)} = {}) {
9
- const status = {};
7
+ export class GreedyPromise extends Promise {
8
+ #result;
9
+ #callbacks;
10
+ #parent = null;
11
+
12
+ /**
13
+ * Convenience wrapper for setTimeout; takes care of returning an already fulfilled GreedyPromise when the delay is zero.
14
+ *
15
+ * @param {Number} delayMs delay in milliseconds
16
+ * @returns {GreedyPromise} a promise that resolves (to undefined) in `delayMs` milliseconds
17
+ */
18
+ static timeout(delayMs = 0) {
19
+ return new GreedyPromise((resolve) => {
20
+ delayMs === 0 ? resolve() : setTimeout(resolve, delayMs);
21
+ });
22
+ }
10
23
 
11
- function finisher(slot) {
12
- return function (val) {
13
- if (typeof status[slot] === 'function') {
14
- status[slot](val);
15
- } else if (!status[slot]) {
16
- status[slot] = true;
17
- status[RESULT] = val;
24
+ constructor(resolver) {
25
+ const result = [];
26
+ const callbacks = [];
27
+ function handler(type, resolveFn) {
28
+ return function (value) {
29
+ if (!result.length) {
30
+ result.push(type, value);
31
+ while (callbacks.length) callbacks.shift()();
32
+ resolveFn(value);
33
+ }
34
+ }
35
+ }
36
+ super(
37
+ typeof resolver !== 'function'
38
+ ? resolver // let super throw an error
39
+ : (resolve, reject) => {
40
+ const rejectHandler = handler(FAIL, reject);
41
+ const resolveHandler = (() => {
42
+ const done = handler(SUCCESS, resolve);
43
+ return value =>
44
+ typeof value?.then === 'function' ? value.then(done, rejectHandler) : done(value);
45
+ })();
46
+ try {
47
+ resolver(resolveHandler, rejectHandler);
48
+ } catch (e) {
49
+ rejectHandler(e);
50
+ }
51
+ }
52
+ );
53
+ this.#result = result;
54
+ this.#callbacks = callbacks;
55
+ }
56
+ then(onSuccess, onError) {
57
+ if (typeof onError === 'function') {
58
+ // if an error handler is provided, attach a dummy error handler to super,
59
+ // and do the same for all promises without an error handler that precede this one in a chain.
60
+ // This is to avoid unhandled rejection events / warnings for errors that were, in fact, handled;
61
+ // since we are not using super's callback mechanisms we need to make it aware of this separately.
62
+ let node = this;
63
+ while (node) {
64
+ super.then.call(node, null, () => null);
65
+ const next = node.#parent;
66
+ node.#parent = null; // since we attached a handler already, we are no longer interested in what will happen later in the chain
67
+ node = next;
18
68
  }
19
69
  }
70
+ const result = this.#result;
71
+ const res = new GreedyPromise((resolve, reject) => {
72
+ const continuation = () => {
73
+ let value = result[1];
74
+ let [handler, resolveFn] = result[0] === SUCCESS ? [onSuccess, resolve] : [onError, reject];
75
+ if (typeof handler === 'function') {
76
+ try {
77
+ value = handler(value);
78
+ } catch (e) {
79
+ reject(e);
80
+ return;
81
+ }
82
+ resolveFn = resolve;
83
+ }
84
+ resolveFn(value);
85
+ }
86
+ result.length ? continuation() : this.#callbacks.push(continuation);
87
+ });
88
+ res.#parent = this;
89
+ return res;
20
90
  }
91
+ }
92
+
93
+ /**
94
+ * @returns a {promise, resolve, reject} trio where `promise` is resolved by calling `resolve` or `reject`.
95
+ */
96
+ export function defer({promiseFactory = (resolver) => new GreedyPromise(resolver)} = {}) {
97
+ function invoker(delegate) {
98
+ return (val) => delegate(val);
99
+ }
100
+
101
+ let resolveFn, rejectFn;
21
102
 
22
103
  return {
23
104
  promise: promiseFactory((resolve, reject) => {
24
- if (status[SUCCESS] != null) {
25
- resolve(status[RESULT]);
26
- } else if (status[FAIL] != null) {
27
- reject(status[RESULT]);
28
- } else {
29
- status[SUCCESS] = resolve;
30
- status[FAIL] = reject;
31
- }
105
+ resolveFn = resolve;
106
+ rejectFn = reject;
32
107
  }),
33
- resolve: finisher(SUCCESS),
34
- reject: finisher(FAIL)
108
+ resolve: invoker(resolveFn),
109
+ reject: invoker(rejectFn)
35
110
  }
36
111
  }
package/src/utils.js CHANGED
@@ -2,6 +2,7 @@ import { config } from './config.js';
2
2
  import clone from 'just-clone';
3
3
  import {find, includes} from './polyfill.js';
4
4
  import CONSTANTS from './constants.json';
5
+ import {GreedyPromise} from './utils/promise.js';
5
6
  export { default as deepAccess } from 'dlv/index.js';
6
7
  export { default as deepSetValue } from 'dset';
7
8
 
@@ -487,7 +488,7 @@ export function hasOwn(objectToCheck, propertyToCheckFor) {
487
488
  * @param {HTMLElement} [doc]
488
489
  * @param {HTMLElement} [target]
489
490
  * @param {Boolean} [asLastChildChild]
490
- * @return {HTMLElement}
491
+ * @return {HTML Element}
491
492
  */
492
493
  export function insertElement(elm, doc, target, asLastChildChild) {
493
494
  doc = doc || document;
@@ -517,7 +518,7 @@ export function insertElement(elm, doc, target, asLastChildChild) {
517
518
  */
518
519
  export function waitForElementToLoad(element, timeout) {
519
520
  let timer = null;
520
- return new Promise((resolve) => {
521
+ return new GreedyPromise((resolve) => {
521
522
  const onLoad = function() {
522
523
  element.removeEventListener('load', onLoad);
523
524
  element.removeEventListener('error', onLoad);
@@ -1,6 +1,7 @@
1
1
  import {gdprDataHandler} from 'src/adapterManager.js';
2
+ import {GreedyPromise} from '../../src/utils/promise.js';
2
3
 
3
4
  export function mockGdprConsent(sandbox, getConsentData = () => null) {
4
- sandbox.stub(gdprDataHandler, 'promise').get(() => Promise.resolve(getConsentData()));
5
+ sandbox.stub(gdprDataHandler, 'promise').get(() => GreedyPromise.resolve(getConsentData()));
5
6
  sandbox.stub(gdprDataHandler, 'getConsentData').callsFake(getConsentData)
6
7
  }
@@ -21,7 +21,6 @@ import {auctionManager} from '../../src/auctionManager.js';
21
21
  import 'modules/debugging/index.js' // some tests look for debugging side effects
22
22
  import {AuctionIndex} from '../../src/auctionIndex.js';
23
23
  import {expect} from 'chai';
24
- import {synchronizePromise} from '../helpers/syncPromise.js';
25
24
 
26
25
  var assert = require('assert');
27
26
 
@@ -134,7 +133,7 @@ function mockAjaxBuilder() {
134
133
  }
135
134
 
136
135
  describe('auctionmanager.js', function () {
137
- let indexAuctions, indexStub, promiseSandbox;
136
+ let indexAuctions, indexStub
138
137
 
139
138
  before(() => {
140
139
  // hooks are global and their side effects depend on what has been loaded
@@ -150,13 +149,10 @@ describe('auctionmanager.js', function () {
150
149
  indexAuctions = [];
151
150
  indexStub = sinon.stub(auctionManager, 'index');
152
151
  indexStub.get(() => new AuctionIndex(() => indexAuctions));
153
- promiseSandbox = sinon.createSandbox();
154
- synchronizePromise(promiseSandbox);
155
152
  });
156
153
 
157
154
  afterEach(() => {
158
155
  indexStub.restore();
159
- promiseSandbox.restore();
160
156
  });
161
157
 
162
158
  describe('getKeyValueTargetingPairs', function () {
@@ -1458,7 +1454,6 @@ describe('auctionmanager.js', function () {
1458
1454
  }
1459
1455
 
1460
1456
  beforeEach(() => {
1461
- promiseSandbox.restore();
1462
1457
  bids = [
1463
1458
  mockBid({bidderCode: BIDDER_CODE1}),
1464
1459
  mockBid({bidderCode: BIDDER_CODE})
@@ -1,6 +1,6 @@
1
1
  import {ready, loadSession, getConfig, reset, debuggingModuleLoader, debuggingControls} from '../../src/debugging.js';
2
2
  import {getGlobal} from '../../src/prebidGlobal.js';
3
- import {promiseControls} from '../../src/utils/promise.js';
3
+ import {defer} from '../../src/utils/promise.js';
4
4
  import funHooks from 'fun-hooks/no-eval/index.js';
5
5
 
6
6
  describe('Debugging', () => {
@@ -67,7 +67,7 @@ describe('Debugging', () => {
67
67
  let debugging, loader, hook, hookRan;
68
68
 
69
69
  beforeEach(() => {
70
- loader = promiseControls();
70
+ loader = defer();
71
71
  hookRan = false;
72
72
  hook = funHooks()('sync', () => { hookRan = true });
73
73
  debugging = debuggingControls({load: sinon.stub().returns(loader.promise), hook});