prebid.js 7.26.0 → 7.27.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 (305) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.js +1 -1
  3. package/dist/adWMGAnalyticsAdapter.js +1 -1
  4. package/dist/adagioAnalyticsAdapter.js +1 -1
  5. package/dist/adagioBidAdapter.js +1 -1
  6. package/dist/adbookpspBidAdapter.js +1 -1
  7. package/dist/adgenerationBidAdapter.js +1 -1
  8. package/dist/adkernelAdnAnalyticsAdapter.js +1 -1
  9. package/dist/adlooxAdServerVideo.js +1 -1
  10. package/dist/adlooxAnalyticsAdapter.js +1 -1
  11. package/dist/adlooxRtdProvider.js +1 -1
  12. package/dist/admaticBidAdapter.js +1 -1
  13. package/dist/admixerBidAdapter.js +1 -1
  14. package/dist/adomikAnalyticsAdapter.js +1 -1
  15. package/dist/adrelevantisBidAdapter.js +1 -1
  16. package/dist/adtrgtmeBidAdapter.js +1 -1
  17. package/dist/adxcgAnalyticsAdapter.js +1 -1
  18. package/dist/adxcgBidAdapter.js +1 -1
  19. package/dist/adxpremiumAnalyticsAdapter.js +1 -1
  20. package/dist/aidemBidAdapter.js +1 -0
  21. package/dist/ajaBidAdapter.js +1 -1
  22. package/dist/amxBidAdapter.js +1 -1
  23. package/dist/amxIdSystem.js +1 -1
  24. package/dist/analyticsAdapter.js +1 -1
  25. package/dist/appierAnalyticsAdapter.js +1 -1
  26. package/dist/appnexusBidAdapter.js +1 -1
  27. package/dist/asoBidAdapter.js +1 -1
  28. package/dist/atsAnalyticsAdapter.js +1 -1
  29. package/dist/axonixBidAdapter.js +1 -1
  30. package/dist/bidViewability.js +1 -1
  31. package/dist/bidglassBidAdapter.js +1 -1
  32. package/dist/bidwatchAnalyticsAdapter.js +1 -1
  33. package/dist/big-richmediaBidAdapter.js +1 -1
  34. package/dist/bridgewellBidAdapter.js +1 -1
  35. package/dist/brightMountainMediaBidAdapter.js +1 -1
  36. package/dist/browsiRtdProvider.js +1 -1
  37. package/dist/bucksenseBidAdapter.js +1 -1
  38. package/dist/byDataAnalyticsAdapter.js +1 -1
  39. package/dist/carodaBidAdapter.js +1 -1
  40. package/dist/chtnwBidAdapter.js +1 -1
  41. package/dist/concertAnalyticsAdapter.js +1 -1
  42. package/dist/concertBidAdapter.js +1 -1
  43. package/dist/connectadBidAdapter.js +1 -1
  44. package/dist/consentManagement.js +1 -1
  45. package/dist/consentManagementUsp.js +1 -1
  46. package/dist/consumableBidAdapter.js +1 -1
  47. package/dist/conversantAnalyticsAdapter.js +1 -1
  48. package/dist/conversantBidAdapter.js +1 -1
  49. package/dist/craftBidAdapter.js +1 -1
  50. package/dist/criteoBidAdapter.js +1 -1
  51. package/dist/datablocksAnalyticsAdapter.js +1 -1
  52. package/dist/dependencies.json +6 -0
  53. package/dist/dfpAdServerVideo.js +1 -1
  54. package/dist/dspxBidAdapter.js +1 -1
  55. package/dist/eplanningAnalyticsAdapter.js +1 -1
  56. package/dist/eplanningBidAdapter.js +1 -1
  57. package/dist/finativeBidAdapter.js +1 -1
  58. package/dist/fintezaAnalyticsAdapter.js +1 -1
  59. package/dist/fluctBidAdapter.js +1 -1
  60. package/dist/ftrackIdSystem.js +1 -1
  61. package/dist/gdprEnforcement.js +1 -1
  62. package/dist/genericAnalyticsAdapter.js +1 -0
  63. package/dist/geoedgeRtdProvider.js +1 -1
  64. package/dist/glimpseBidAdapter.js +1 -1
  65. package/dist/glomexBidAdapter.js +1 -1
  66. package/dist/gmosspBidAdapter.js +1 -1
  67. package/dist/goldbachBidAdapter.js +1 -1
  68. package/dist/googleAnalyticsAdapter.js +1 -1
  69. package/dist/gravitoIdSystem.js +1 -1
  70. package/dist/gridBidAdapter.js +1 -1
  71. package/dist/gridNMBidAdapter.js +1 -1
  72. package/dist/growthCodeAnalyticsAdapter.js +1 -0
  73. package/dist/gumgumBidAdapter.js +1 -1
  74. package/dist/h12mediaBidAdapter.js +1 -1
  75. package/dist/hadronAnalyticsAdapter.js +1 -1
  76. package/dist/id5AnalyticsAdapter.js +1 -1
  77. package/dist/id5IdSystem.js +1 -1
  78. package/dist/impactifyBidAdapter.js +1 -1
  79. package/dist/improvedigitalBidAdapter.js +1 -1
  80. package/dist/inmarBidAdapter.js +1 -1
  81. package/dist/insticatorBidAdapter.js +1 -1
  82. package/dist/invisiblyAnalyticsAdapter.js +1 -1
  83. package/dist/ixBidAdapter.js +1 -1
  84. package/dist/justpremiumBidAdapter.js +1 -1
  85. package/dist/jwplayerRtdProvider.js +1 -1
  86. package/dist/kargoAnalyticsAdapter.js +1 -1
  87. package/dist/kinessoIdSystem.js +1 -1
  88. package/dist/konduitAnalyticsAdapter.js +1 -1
  89. package/dist/kueezBidAdapter.js +1 -1
  90. package/dist/kueezRtbBidAdapter.js +1 -1
  91. package/dist/lassoBidAdapter.js +1 -1
  92. package/dist/lifestreetBidAdapter.js +1 -1
  93. package/dist/limelightDigitalBidAdapter.js +1 -1
  94. package/dist/liveIntentAnalyticsAdapter.js +1 -1
  95. package/dist/liveIntentIdSystem.js +1 -1
  96. package/dist/livewrappedAnalyticsAdapter.js +1 -1
  97. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  98. package/dist/logicadBidAdapter.js +1 -1
  99. package/dist/loglyliftBidAdapter.js +1 -1
  100. package/dist/lotamePanoramaIdSystem.js +1 -1
  101. package/dist/magniteAnalyticsAdapter.js +1 -1
  102. package/dist/malltvAnalyticsAdapter.js +1 -1
  103. package/dist/marsmediaAnalyticsAdapter.js +1 -1
  104. package/dist/marsmediaBidAdapter.js +1 -1
  105. package/dist/mediafuseBidAdapter.js +1 -1
  106. package/dist/medianetAnalyticsAdapter.js +1 -1
  107. package/dist/mediasquareBidAdapter.js +1 -1
  108. package/dist/mgidBidAdapter.js +1 -1
  109. package/dist/minutemediaBidAdapter.js +1 -1
  110. package/dist/nexx360BidAdapter.js +1 -1
  111. package/dist/not-for-prod/prebid.js +200 -196
  112. package/dist/oguryBidAdapter.js +1 -1
  113. package/dist/onetagBidAdapter.js +1 -1
  114. package/dist/ooloAnalyticsAdapter.js +1 -1
  115. package/dist/openxAnalyticsAdapter.js +1 -1
  116. package/dist/optimonAnalyticsAdapter.js +1 -1
  117. package/dist/outbrainBidAdapter.js +1 -1
  118. package/dist/parrableIdSystem.js +1 -1
  119. package/dist/pbsExtensions.js +1 -1
  120. package/dist/pianoDmpAnalyticsAdapter.js +1 -1
  121. package/dist/pixfutureBidAdapter.js +1 -1
  122. package/dist/prebid-core.js +1 -1
  123. package/dist/prebidServerBidAdapter.js +1 -1
  124. package/dist/prebidmanagerAnalyticsAdapter.js +1 -1
  125. package/dist/pubCommonId.js +1 -1
  126. package/dist/pubProvidedIdSystem.js +1 -1
  127. package/dist/publinkIdSystem.js +1 -1
  128. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  129. package/dist/pubmaticBidAdapter.js +1 -1
  130. package/dist/pubperfAnalyticsAdapter.js +1 -1
  131. package/dist/pubstackAnalyticsAdapter.js +1 -1
  132. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  133. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  134. package/dist/pulsepointAnalyticsAdapter.js +1 -1
  135. package/dist/pxyzBidAdapter.js +1 -1
  136. package/dist/quantcastBidAdapter.js +1 -1
  137. package/dist/quantcastIdSystem.js +1 -1
  138. package/dist/rasBidAdapter.js +1 -1
  139. package/dist/readpeakBidAdapter.js +1 -1
  140. package/dist/realvuAnalyticsAdapter.js +1 -1
  141. package/dist/redtramBidAdapter.js +1 -0
  142. package/dist/relaidoBidAdapter.js +1 -1
  143. package/dist/relevantAnalyticsAdapter.js +1 -1
  144. package/dist/rhythmoneBidAdapter.js +1 -1
  145. package/dist/riseBidAdapter.js +1 -1
  146. package/dist/rivrAnalyticsAdapter.js +1 -1
  147. package/dist/roxotAnalyticsAdapter.js +1 -1
  148. package/dist/rtbhouseBidAdapter.js +1 -1
  149. package/dist/rtdModule.js +1 -1
  150. package/dist/rubiconAnalyticsAdapter.js +1 -1
  151. package/dist/rubiconBidAdapter.js +1 -1
  152. package/dist/s2sTesting.js +1 -1
  153. package/dist/scaleableAnalyticsAdapter.js +1 -1
  154. package/dist/schain.js +1 -1
  155. package/dist/seedingAllianceBidAdapter.js +1 -1
  156. package/dist/seedtagBidAdapter.js +1 -1
  157. package/dist/sharedIdSystem.js +1 -1
  158. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  159. package/dist/sharethroughBidAdapter.js +1 -1
  160. package/dist/shinezBidAdapter.js +1 -1
  161. package/dist/sigmoidAnalyticsAdapter.js +1 -1
  162. package/dist/smaatoBidAdapter.js +1 -1
  163. package/dist/smartadserverBidAdapter.js +1 -1
  164. package/dist/smartxBidAdapter.js +1 -1
  165. package/dist/smilewantedBidAdapter.js +1 -1
  166. package/dist/sonobiAnalyticsAdapter.js +1 -1
  167. package/dist/sonobiBidAdapter.js +1 -1
  168. package/dist/sovrnAnalyticsAdapter.js +1 -1
  169. package/dist/sovrnBidAdapter.js +1 -1
  170. package/dist/sspBCBidAdapter.js +1 -1
  171. package/dist/staqAnalyticsAdapter.js +1 -1
  172. package/dist/sublimeBidAdapter.js +1 -1
  173. package/dist/synacormediaBidAdapter.js +1 -1
  174. package/dist/tapadIdSystem.js +1 -1
  175. package/dist/targetVideoBidAdapter.js +1 -1
  176. package/dist/teadsBidAdapter.js +1 -1
  177. package/dist/teadsIdSystem.js +1 -1
  178. package/dist/terceptAnalyticsAdapter.js +1 -1
  179. package/dist/trionBidAdapter.js +1 -1
  180. package/dist/tripleliftBidAdapter.js +1 -1
  181. package/dist/ttdBidAdapter.js +1 -1
  182. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  183. package/dist/underdogmediaBidAdapter.js +1 -1
  184. package/dist/undertoneBidAdapter.js +1 -1
  185. package/dist/userId.js +1 -1
  186. package/dist/vidazooBidAdapter.js +1 -1
  187. package/dist/videobyteBidAdapter.js +1 -1
  188. package/dist/visxBidAdapter.js +1 -1
  189. package/dist/vuukleBidAdapter.js +1 -1
  190. package/dist/weboramaRtdProvider.js +1 -1
  191. package/dist/widespaceBidAdapter.js +1 -1
  192. package/dist/winrBidAdapter.js +1 -1
  193. package/dist/yahoosspBidAdapter.js +1 -1
  194. package/dist/yandexBidAdapter.js +1 -1
  195. package/dist/yieldlabBidAdapter.js +1 -1
  196. package/dist/yieldliftBidAdapter.js +1 -1
  197. package/dist/yieldmoBidAdapter.js +1 -1
  198. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  199. package/dist/yuktamediaAnalyticsAdapter.js +1 -1
  200. package/dist/zeta_global_sspAnalyticsAdapter.js +1 -1
  201. package/integrationExamples/gpt/growthcode.html +134 -0
  202. package/libraries/analyticsAdapter/AnalyticsAdapter.js +95 -102
  203. package/modules/admaticBidAdapter.js +10 -1
  204. package/modules/admixerBidAdapter.js +1 -1
  205. package/modules/aidemBidAdapter.js +492 -0
  206. package/modules/aidemBidAdapter.md +187 -0
  207. package/modules/browsiRtdProvider.js +6 -4
  208. package/modules/bucksenseBidAdapter.js +1 -1
  209. package/modules/criteoBidAdapter.js +3 -3
  210. package/modules/eplanningBidAdapter.js +2 -6
  211. package/modules/fluctBidAdapter.js +5 -0
  212. package/modules/gdprEnforcement.js +26 -24
  213. package/modules/genericAnalyticsAdapter.js +157 -0
  214. package/modules/geoedgeRtdProvider.js +22 -0
  215. package/modules/glomexBidAdapter.js +2 -0
  216. package/modules/gravitoIdSystem.js +3 -4
  217. package/modules/gridBidAdapter.js +1 -1
  218. package/modules/gridNMBidAdapter.js +1 -1
  219. package/modules/growthCodeAnalyticsAdapter.js +176 -0
  220. package/modules/growthCodeAnalyticsAdapter.md +41 -0
  221. package/modules/impactifyBidAdapter.js +19 -1
  222. package/modules/jwplayerRtdProvider.js +1 -2
  223. package/modules/limelightDigitalBidAdapter.js +1 -1
  224. package/modules/minutemediaBidAdapter.md +3 -3
  225. package/modules/nexx360BidAdapter.js +264 -138
  226. package/modules/pubCommonId.js +2 -1
  227. package/modules/pubProvidedIdSystem.js +2 -0
  228. package/modules/rasBidAdapter.js +8 -3
  229. package/modules/rasBidAdapter.md +16 -15
  230. package/modules/redtramBidAdapter.js +155 -0
  231. package/modules/redtramBidAdapter.md +33 -0
  232. package/modules/riseBidAdapter.js +15 -0
  233. package/modules/riseBidAdapter.md +3 -3
  234. package/modules/rtbhouseBidAdapter.js +90 -29
  235. package/modules/rubiconBidAdapter.js +2 -1
  236. package/modules/seedtagBidAdapter.js +67 -56
  237. package/modules/seedtagBidAdapter.md +60 -0
  238. package/modules/sharedIdSystem.js +3 -1
  239. package/modules/smartxBidAdapter.js +1 -1
  240. package/modules/smnBidAdapter.md +52 -0
  241. package/modules/tripleliftBidAdapter.js +1 -1
  242. package/modules/ttdBidAdapter.js +4 -0
  243. package/modules/vidazooBidAdapter.js +11 -1
  244. package/modules/yandexBidAdapter.js +85 -19
  245. package/modules/yandexBidAdapter.md +7 -7
  246. package/modules/yieldlabBidAdapter.js +10 -4
  247. package/modules/yieldliftBidAdapter.js +3 -3
  248. package/package.json +1 -1
  249. package/src/auction.js +19 -3
  250. package/src/consentHandler.js +8 -0
  251. package/src/events.js +4 -0
  252. package/src/native.js +31 -20
  253. package/src/refererDetection.js +6 -1
  254. package/src/storageManager.js +6 -3
  255. package/test/helpers/analytics.js +34 -0
  256. package/test/mocks/analyticsStub.js +3 -1
  257. package/test/spec/AnalyticsAdapter_spec.js +119 -116
  258. package/test/spec/auctionmanager_spec.js +86 -0
  259. package/test/spec/modules/adWMGAnalyticsAdapter_spec.js +10 -8
  260. package/test/spec/modules/adagioAnalyticsAdapter_spec.js +18 -25
  261. package/test/spec/modules/aidemBidAdapter_spec.js +664 -0
  262. package/test/spec/modules/bidwatchAnalyticsAdapter_spec.js +0 -2
  263. package/test/spec/modules/browsiRtdProvider_spec.js +2 -1
  264. package/test/spec/modules/concertAnalyticsAdapter_spec.js +2 -4
  265. package/test/spec/modules/enrichmentFpdModule_spec.js +3 -2
  266. package/test/spec/modules/eplanningAnalyticsAdapter_spec.js +0 -3
  267. package/test/spec/modules/eplanningBidAdapter_spec.js +4 -4
  268. package/test/spec/modules/fluctBidAdapter_spec.js +37 -1
  269. package/test/spec/modules/fpdModule_spec.js +1 -1
  270. package/test/spec/modules/gdprEnforcement_spec.js +115 -68
  271. package/test/spec/modules/genericAnalyticsAdapter_spec.js +284 -0
  272. package/test/spec/modules/geoedgeRtdProvider_spec.js +15 -0
  273. package/test/spec/modules/glomexBidAdapter_spec.js +4 -0
  274. package/test/spec/modules/gravitoIdSystem_spec.js +1 -1
  275. package/test/spec/modules/growthCodeAnalyticsAdapter_spec.js +70 -0
  276. package/test/spec/modules/impactifyBidAdapter_spec.js +13 -0
  277. package/test/spec/modules/invisiblyAnalyticsAdapter_spec.js +17 -27
  278. package/test/spec/modules/jwplayerRtdProvider_spec.js +3 -3
  279. package/test/spec/modules/konduitAnalyticsAdapter_spec.js +0 -2
  280. package/test/spec/modules/liveIntentAnalyticsAdapter_spec.js +3 -6
  281. package/test/spec/modules/medianetAnalyticsAdapter_spec.js +7 -1
  282. package/test/spec/modules/nexx360BidAdapter_spec.js +441 -221
  283. package/test/spec/modules/optimonAnalyticsAdapter_spec.js +3 -11
  284. package/test/spec/modules/pianoDmpAnalyticsAdapter_spec.js +4 -11
  285. package/test/spec/modules/prebidmanagerAnalyticsAdapter_spec.js +3 -12
  286. package/test/spec/modules/pubperfAnalyticsAdapter_spec.js +6 -19
  287. package/test/spec/modules/pubstackAnalyticsAdapter_spec.js +3 -17
  288. package/test/spec/modules/pubwiseAnalyticsAdapter_spec.js +13 -19
  289. package/test/spec/modules/rasBidAdapter_spec.js +5 -1
  290. package/test/spec/modules/redtramBidAdapter_spec.js +256 -0
  291. package/test/spec/modules/riseBidAdapter_spec.js +24 -0
  292. package/test/spec/modules/rtbhouseBidAdapter_spec.js +79 -0
  293. package/test/spec/modules/seedtagBidAdapter_spec.js +65 -92
  294. package/test/spec/modules/sigmoidAnalyticsAdapter_spec.js +4 -8
  295. package/test/spec/modules/sovrnAnalyticsAdapter_spec.js +6 -18
  296. package/test/spec/modules/tripleliftBidAdapter_spec.js +3 -10
  297. package/test/spec/modules/ttdBidAdapter_spec.js +14 -0
  298. package/test/spec/modules/vidazooBidAdapter_spec.js +39 -24
  299. package/test/spec/modules/yandexBidAdapter_spec.js +22 -13
  300. package/test/spec/modules/yieldlabBidAdapter_spec.js +49 -20
  301. package/test/spec/modules/yieldliftBidAdapter_spec.js +1 -1
  302. package/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +5 -2
  303. package/test/spec/native_spec.js +68 -56
  304. package/test/spec/refererDetection_spec.js +45 -7
  305. package/test/spec/unit/core/storageManager_spec.js +2 -1
@@ -2,9 +2,9 @@ import {deepSetValue, logInfo, deepAccess} from '../src/utils.js';
2
2
  import {registerBidder} from '../src/adapters/bidderFactory.js';
3
3
  import {BANNER} from '../src/mediaTypes.js';
4
4
 
5
- const ENDPOINT_URL = 'https://x.yieldlift.com/auction';
5
+ const ENDPOINT_URL = 'https://x.yieldlift.com/pbjs';
6
6
 
7
- const DEFAULT_BID_TTL = 30;
7
+ const DEFAULT_BID_TTL = 300;
8
8
  const DEFAULT_CURRENCY = 'USD';
9
9
  const DEFAULT_NET_REVENUE = true;
10
10
 
@@ -98,7 +98,7 @@ export const spec = {
98
98
  width: bid.w,
99
99
  height: bid.h,
100
100
  ad: bid.adm,
101
- ttl: DEFAULT_BID_TTL,
101
+ ttl: typeof bid.exp === 'number' ? bid.exp : DEFAULT_BID_TTL,
102
102
  creativeId: bid.crid,
103
103
  netRevenue: DEFAULT_NET_REVENUE,
104
104
  currency: DEFAULT_CURRENCY,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "7.26.0",
3
+ "version": "7.27.0",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.js",
6
6
  "scripts": {
package/src/auction.js CHANGED
@@ -76,7 +76,7 @@ import {
76
76
  timestamp
77
77
  } from './utils.js';
78
78
  import {getPriceBucketString} from './cpmBucketManager.js';
79
- import {getNativeTargeting} from './native.js';
79
+ import {getNativeTargeting, toLegacyResponse} from './native.js';
80
80
  import {getCacheUrl, store} from './videoCache.js';
81
81
  import {Renderer} from './Renderer.js';
82
82
  import {config} from './config.js';
@@ -462,9 +462,14 @@ export function auctionCallbacks(auctionDone, auctionInstance, {index = auctionM
462
462
  handleBidResponse(adUnitCode, bid, (done) => {
463
463
  let bidResponse = getPreparedBidForAuction(bid);
464
464
 
465
- if (bidResponse.mediaType === 'video') {
465
+ if (bidResponse.mediaType === VIDEO) {
466
466
  tryAddVideoBid(auctionInstance, bidResponse, done);
467
467
  } else {
468
+ if (FEATURES.NATIVE && bidResponse.native != null && typeof bidResponse.native === 'object') {
469
+ // NOTE: augment bidResponse.native even if bidResponse.mediaType !== NATIVE; it's possible
470
+ // to treat banner responses as native
471
+ addLegacyFieldsIfNeeded(bidResponse);
472
+ }
468
473
  addBidToAuction(auctionInstance, bidResponse);
469
474
  done();
470
475
  }
@@ -593,6 +598,17 @@ function tryAddVideoBid(auctionInstance, bidResponse, afterBidAdded, {index = au
593
598
  }
594
599
  }
595
600
 
601
+ // Native bid response might be in ortb2 format - adds legacy field for backward compatibility
602
+ const addLegacyFieldsIfNeeded = (bidResponse) => {
603
+ const nativeOrtbRequest = auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest;
604
+ const nativeOrtbResponse = bidResponse.native?.ortb
605
+
606
+ if (nativeOrtbRequest && nativeOrtbResponse) {
607
+ const legacyResponse = toLegacyResponse(nativeOrtbResponse, nativeOrtbRequest);
608
+ Object.assign(bidResponse.native, legacyResponse);
609
+ }
610
+ }
611
+
596
612
  const storeInCache = (batch) => {
597
613
  store(batch.map(entry => entry.bidResponse), function (error, cacheIds) {
598
614
  cacheIds.forEach((cacheId, i) => {
@@ -672,7 +688,7 @@ function addCommonResponseProperties(bidResponse, adUnitCode, {index = auctionMa
672
688
  Object.assign(bidResponse, {
673
689
  responseTimestamp: bidResponse.responseTimestamp || timestamp(),
674
690
  requestTimestamp: bidResponse.requestTimestamp || start,
675
- cpm: bidResponse.cpm || parseFloat(bidResponse.cpm) || 0,
691
+ cpm: parseFloat(bidResponse.cpm) || 0,
676
692
  bidder: bidResponse.bidder || bidResponse.bidderCode,
677
693
  adUnitCode
678
694
  });
@@ -1,6 +1,14 @@
1
1
  import {isStr, timestamp} from './utils.js';
2
2
  import {defer, GreedyPromise} from './utils/promise.js';
3
3
 
4
+ /**
5
+ * Placeholder gvlid for when vendor consent is not required. When this value is used as gvlid, the gdpr
6
+ * enforcement module will take it to mean "vendor consent was given".
7
+ *
8
+ * see https://github.com/prebid/Prebid.js/issues/8161
9
+ */
10
+ export const VENDORLESS_GVLID = Object.freeze({});
11
+
4
12
  export class ConsentHandler {
5
13
  #enabled;
6
14
  #data;
package/src/events.js CHANGED
@@ -157,3 +157,7 @@ const _public = (function () {
157
157
  utils._setEventEmitter(_public.emit.bind(_public));
158
158
 
159
159
  export const {on, off, get, getEvents, emit, addEvents} = _public;
160
+
161
+ export function clearEvents() {
162
+ eventsFired.length = 0;
163
+ }
package/src/native.js CHANGED
@@ -23,7 +23,7 @@ export const NATIVE_TARGETING_KEYS = Object.keys(CONSTANTS.NATIVE_KEYS).map(
23
23
  key => CONSTANTS.NATIVE_KEYS[key]
24
24
  );
25
25
 
26
- const IMAGE = {
26
+ export const IMAGE = {
27
27
  ortb: {
28
28
  ver: '1.2',
29
29
  assets: [
@@ -385,26 +385,14 @@ export function getNativeTargeting(bid, {index = auctionManager.index} = {}) {
385
385
  return keyValues;
386
386
  }
387
387
 
388
- const getNativeRequest = (bidResponse) => auctionManager.index.getAdUnit(bidResponse)?.nativeOrtbRequest;
389
-
390
- function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} = {}) {
388
+ function assetsMessage(data, adObject, keys) {
391
389
  const message = {
392
390
  message: 'assetResponse',
393
391
  adId: data.adId,
394
392
  };
395
393
 
396
- // Pass to Prebid Universal Creative all assets, the legacy ones + the ortb ones (under ortb property)
397
- const ortbRequest = getNativeReq(adObject);
398
394
  let nativeResp = adObject.native;
399
- const ortbResponse = adObject.native?.ortb;
400
- let legacyResponse = {};
401
- if (ortbRequest && ortbResponse) {
402
- legacyResponse = toLegacyResponse(ortbResponse, ortbRequest);
403
- nativeResp = {
404
- ...adObject.native,
405
- ...legacyResponse
406
- };
407
- }
395
+
408
396
  if (adObject.native.ortb) {
409
397
  message.ortb = adObject.native.ortb;
410
398
  }
@@ -435,13 +423,13 @@ function assetsMessage(data, adObject, keys, {getNativeReq = getNativeRequest} =
435
423
  * Constructs a message object containing asset values for each of the
436
424
  * requested data keys.
437
425
  */
438
- export function getAssetMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) {
426
+ export function getAssetMessage(data, adObject) {
439
427
  const keys = data.assets.map((k) => getKeyByValue(CONSTANTS.NATIVE_KEYS, k));
440
- return assetsMessage(data, adObject, keys, {getNativeReq});
428
+ return assetsMessage(data, adObject, keys);
441
429
  }
442
430
 
443
- export function getAllAssetsMessage(data, adObject, {getNativeReq = getNativeRequest} = {}) {
444
- return assetsMessage(data, adObject, null, {getNativeReq});
431
+ export function getAllAssetsMessage(data, adObject) {
432
+ return assetsMessage(data, adObject, null);
445
433
  }
446
434
 
447
435
  /**
@@ -749,7 +737,7 @@ export function toOrtbNativeResponse(legacyResponse, ortbRequest) {
749
737
  * @param {*} ortbRequest the ortb request, useful to match ids.
750
738
  * @returns an object containing the response in legacy native format: { title: "this is a title", image: ... }
751
739
  */
752
- function toLegacyResponse(ortbResponse, ortbRequest) {
740
+ export function toLegacyResponse(ortbResponse, ortbRequest) {
753
741
  const legacyResponse = {};
754
742
  const requestAssets = ortbRequest?.assets || [];
755
743
  legacyResponse.clickUrl = ortbResponse.link.url;
@@ -764,6 +752,29 @@ function toLegacyResponse(ortbResponse, ortbRequest) {
764
752
  legacyResponse[PREBID_NATIVE_DATA_KEYS_TO_ORTB_INVERSE[NATIVE_ASSET_TYPES_INVERSE[requestAsset.data.type]]] = asset.data.value;
765
753
  }
766
754
  }
755
+
756
+ // Handle trackers
757
+ legacyResponse.impressionTrackers = [];
758
+ let jsTrackers = [];
759
+
760
+ if (ortbRequest?.imptrackers) {
761
+ legacyResponse.impressionTrackers.push(...ortbRequest.imptrackers);
762
+ }
763
+ for (const eventTracker of ortbResponse?.eventtrackers || []) {
764
+ if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.img) {
765
+ legacyResponse.impressionTrackers.push(eventTracker.url);
766
+ }
767
+ if (eventTracker.event === TRACKER_EVENTS.impression && eventTracker.method === TRACKER_METHODS.js) {
768
+ jsTrackers.push(eventTracker.url);
769
+ }
770
+ }
771
+
772
+ jsTrackers = jsTrackers.map(url => `<script async src="${url}"></script>`);
773
+ if (ortbResponse?.jstracker) { jsTrackers.push(ortbResponse.jstracker); }
774
+ if (jsTrackers.length) {
775
+ legacyResponse.javascriptTrackers = jsTrackers.join('\n');
776
+ }
777
+
767
778
  return legacyResponse;
768
779
  }
769
780
 
@@ -120,6 +120,7 @@ export function detectReferer(win) {
120
120
  const stack = [];
121
121
  const ancestors = getAncestorOrigins(win);
122
122
  const maxNestedIframes = config.getConfig('maxNestedIframes');
123
+
123
124
  let currentWindow;
124
125
  let bestLocation;
125
126
  let bestCanonicalUrl;
@@ -226,7 +227,11 @@ export function detectReferer(win) {
226
227
 
227
228
  const location = reachedTop || hasTopLocation ? bestLocation : null;
228
229
  const canonicalUrl = config.getConfig('pageUrl') || bestCanonicalUrl || null;
229
- const page = ensureProtocol(canonicalUrl, win) || location;
230
+ let page = config.getConfig('pageUrl') || location || ensureProtocol(canonicalUrl, win);
231
+
232
+ if (location && location.indexOf('?') > -1 && page.indexOf('?') === -1) {
233
+ page = `${page}${location.substring(location.indexOf('?'))}`;
234
+ }
230
235
 
231
236
  return {
232
237
  reachedTop,
@@ -1,6 +1,7 @@
1
1
  import {hook} from './hook.js';
2
2
  import {hasDeviceAccess, checkCookieSupport, logError, logInfo, isPlainObject} from './utils.js';
3
3
  import {bidderSettings as defaultBidderSettings} from './bidderSettings.js';
4
+ import {VENDORLESS_GVLID} from './consentHandler.js';
4
5
 
5
6
  const moduleTypeWhiteList = ['core', 'prebid-module'];
6
7
 
@@ -33,7 +34,9 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} =
33
34
  return storageAllowed == null ? false : storageAllowed;
34
35
  }
35
36
 
36
- const isVendorless = moduleTypeWhiteList.includes(moduleType);
37
+ if (moduleTypeWhiteList.includes(moduleType)) {
38
+ gvlid = gvlid || VENDORLESS_GVLID;
39
+ }
37
40
 
38
41
  function isValid(cb) {
39
42
  if (!isBidderAllowed()) {
@@ -45,7 +48,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} =
45
48
  let hookDetails = {
46
49
  hasEnforcementHook: false
47
50
  }
48
- validateStorageEnforcement(isVendorless, gvlid, bidderCode || moduleName, hookDetails, function(result) {
51
+ validateStorageEnforcement(gvlid, bidderCode || moduleName, hookDetails, function(result) {
49
52
  if (result && result.hasEnforcementHook) {
50
53
  value = cb(result);
51
54
  } else {
@@ -296,7 +299,7 @@ export function newStorageManager({gvlid, moduleName, bidderCode, moduleType} =
296
299
  /**
297
300
  * This hook validates the storage enforcement if gdprEnforcement module is included
298
301
  */
299
- export const validateStorageEnforcement = hook('async', function(isVendorless, gvlid, moduleName, hookDetails, callback) {
302
+ export const validateStorageEnforcement = hook('async', function(gvlid, moduleName, hookDetails, callback) {
300
303
  callback(hookDetails);
301
304
  }, 'validateStorageEnforcement');
302
305
 
@@ -0,0 +1,34 @@
1
+ import * as pbEvents from 'src/events.js';
2
+ import constants from '../../src/constants.json';
3
+
4
+ export function fireEvents(events = [
5
+ constants.EVENTS.AUCTION_INIT,
6
+ constants.EVENTS.AUCTION_END,
7
+ constants.EVENTS.BID_REQUESTED,
8
+ constants.EVENTS.BID_RESPONSE,
9
+ constants.EVENTS.BID_WON
10
+ ]) {
11
+ return events.map((ev, i) => {
12
+ ev = Array.isArray(ev) ? ev : [ev, {i: i}];
13
+ pbEvents.emit.apply(null, ev)
14
+ return ev;
15
+ });
16
+ }
17
+
18
+ export function expectEvents(events) {
19
+ events = fireEvents(events);
20
+ return {
21
+ to: {
22
+ beTrackedBy(trackFn) {
23
+ events.forEach(([eventType, args]) => {
24
+ sinon.assert.calledWithMatch(trackFn, sinon.match({eventType, args}));
25
+ });
26
+ },
27
+ beBundledTo(bundleFn) {
28
+ events.forEach(([eventType, args]) => {
29
+ sinon.assert.calledWithMatch(bundleFn, sinon.match.any, eventType, sinon.match(args))
30
+ });
31
+ },
32
+ },
33
+ };
34
+ }
@@ -1,8 +1,10 @@
1
- import {_internal} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js';
1
+ import {_internal, setDebounceDelay} from '../../libraries/analyticsAdapter/AnalyticsAdapter.js';
2
2
 
3
3
  before(() => {
4
4
  // stub out analytics networking to avoid random events polluting the global xhr mock
5
5
  disableAjaxForAnalytics();
6
+ // make analytics event handling synchronous
7
+ setDebounceDelay(0);
6
8
  })
7
9
 
8
10
  export function disableAjaxForAnalytics() {
@@ -1,18 +1,17 @@
1
- import { expect } from 'chai';
1
+ import {expect} from 'chai';
2
2
  import * as events from 'src/events.js';
3
3
  import CONSTANTS from 'src/constants.json';
4
- import { server } from 'test/mocks/xhr.js';
4
+ import {server} from 'test/mocks/xhr.js';
5
5
  import {disableAjaxForAnalytics, enableAjaxForAnalytics} from '../mocks/analyticsStub.js';
6
+ import {clearEvents} from 'src/events.js';
7
+ import {
8
+ DEFAULT_EXCLUDE_EVENTS,
9
+ DEFAULT_INCLUDE_EVENTS,
10
+ setDebounceDelay
11
+ } from '../../libraries/analyticsAdapter/AnalyticsAdapter.js';
6
12
 
7
- const REQUEST_BIDS = CONSTANTS.EVENTS.REQUEST_BIDS;
8
- const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED;
9
- const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE;
10
13
  const BID_WON = CONSTANTS.EVENTS.BID_WON;
11
- const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT;
12
- const AD_RENDER_FAILED = CONSTANTS.EVENTS.AD_RENDER_FAILED;
13
- const AD_RENDER_SUCCEEDED = CONSTANTS.EVENTS.AD_RENDER_SUCCEEDED;
14
- const AUCTION_DEBUG = CONSTANTS.EVENTS.AUCTION_DEBUG;
15
- const ADD_AD_UNITS = CONSTANTS.EVENTS.ADD_AD_UNITS;
14
+ const NO_BID = CONSTANTS.EVENTS.NO_BID;
16
15
 
17
16
  const AnalyticsAdapter = require('libraries/analyticsAdapter/AnalyticsAdapter.js').default;
18
17
  const config = {
@@ -35,6 +34,7 @@ FEATURE: Analytics Adapters API
35
34
 
36
35
  afterEach(function () {
37
36
  adapter.disableAnalytics();
37
+ clearEvents();
38
38
  });
39
39
 
40
40
  it('should track enable status in `enabled`', () => {
@@ -43,21 +43,21 @@ FEATURE: Analytics Adapters API
43
43
  expect(adapter.enabled).to.equal(true);
44
44
  adapter.disableAnalytics();
45
45
  expect(adapter.enabled).to.equal(false);
46
- })
46
+ });
47
47
 
48
48
  it(`SHOULD call the endpoint WHEN an event occurs that is to be tracked`, function () {
49
- const eventType = BID_REQUESTED;
50
- const args = { some: 'data' };
49
+ const eventType = BID_WON;
50
+ const args = {some: 'data'};
51
51
 
52
- adapter.track({ eventType, args });
52
+ adapter.track({eventType, args});
53
53
 
54
54
  let result = JSON.parse(server.requests[0].requestBody);
55
- expect(result).to.deep.equal({args: {some: 'data'}, eventType: 'bidRequested'});
55
+ expect(result).to.deep.equal({args: {some: 'data'}, eventType});
56
56
  });
57
57
 
58
58
  it(`SHOULD queue the event first and then track it WHEN an event occurs before tracking library is available`, function () {
59
- const eventType = BID_RESPONSE;
60
- const args = { wat: 'wot' };
59
+ const eventType = BID_WON;
60
+ const args = {wat: 'wot'};
61
61
 
62
62
  events.emit(eventType, args);
63
63
  adapter.enableAnalytics();
@@ -65,9 +65,58 @@ FEATURE: Analytics Adapters API
65
65
  // As now AUCTION_DEBUG is triggered for WARNINGS too, the BID_RESPONSE goes last in the array
66
66
  const index = server.requests.length - 1;
67
67
  let result = JSON.parse(server.requests[index].requestBody);
68
- expect(result).to.deep.equal({eventType: 'bidResponse', args: {wat: 'wot'}});
68
+ expect(result).to.deep.equal({eventType, args: {wat: 'wot'}});
69
69
  });
70
70
 
71
+ describe('event filters', () => {
72
+ function fireEvents() {
73
+ events.emit(BID_WON, {});
74
+ events.emit(NO_BID, {});
75
+ }
76
+ function getEvents(ev) {
77
+ return server.requests
78
+ .map(r => JSON.parse(r.requestBody))
79
+ .filter(r => r.eventType === ev)
80
+ }
81
+
82
+ Object.entries({
83
+ 'whitelist includeEvents': {
84
+ includeEvents: [BID_WON]
85
+ },
86
+ 'blacklist excludeEvents': {
87
+ excludeEvents: [NO_BID]
88
+ },
89
+ 'give precedence to exclude over include': {
90
+ includeEvents: [BID_WON, NO_BID],
91
+ excludeEvents: [NO_BID]
92
+ }
93
+ }).forEach(([t, config]) => {
94
+ it(`should ${t}`, () => {
95
+ fireEvents();
96
+ adapter.enableAnalytics(config);
97
+ expect(getEvents(BID_WON).length).to.eql(1);
98
+ expect(getEvents(NO_BID).length).to.eql(0);
99
+ fireEvents();
100
+ expect(getEvents(BID_WON).length).to.eql(2);
101
+ expect(getEvents(NO_BID).length).to.eql(0);
102
+ })
103
+ })
104
+ })
105
+
106
+ it('should prevent infinite loops when track triggers other events', () => {
107
+ let i = 0;
108
+ adapter.track = ((orig) => {
109
+ return function (event) {
110
+ i++;
111
+ orig.call(this, event);
112
+ events.emit(BID_WON, {})
113
+ }
114
+ })(adapter.track);
115
+ adapter.enableAnalytics(config);
116
+ events.emit(BID_WON, {});
117
+ expect(i >= 100).to.eql(false);
118
+ })
119
+
71
120
  describe(`WHEN an event occurs after enable analytics\n`, function () {
72
121
  beforeEach(function () {
73
122
  sinon.stub(events, 'getEvents').returns([]); // these tests shouldn't be affected by previous tests
@@ -77,108 +126,26 @@ FEATURE: Analytics Adapters API
77
126
  events.getEvents.restore();
78
127
  });
79
128
 
80
- it('SHOULD call global when a bidWon event occurs', function () {
81
- const eventType = BID_WON;
82
- const args = { more: 'info' };
83
-
84
- adapter.enableAnalytics();
85
- events.emit(eventType, args);
86
-
87
- let result = JSON.parse(server.requests[0].requestBody);
88
- expect(result).to.deep.equal({args: {more: 'info'}, eventType: 'bidWon'});
89
- });
90
-
91
- it('SHOULD call global when a adRenderFailed event occurs', function () {
92
- const eventType = AD_RENDER_FAILED;
93
- const args = { call: 'adRenderFailed' };
94
-
95
- adapter.enableAnalytics();
96
- events.emit(eventType, args);
97
-
98
- let result = JSON.parse(server.requests[0].requestBody);
99
- expect(result).to.deep.equal({args: {call: 'adRenderFailed'}, eventType: 'adRenderFailed'});
100
- });
101
-
102
- it('SHOULD call global when a adRenderSucceeded event occurs', function () {
103
- const eventType = AD_RENDER_SUCCEEDED;
104
- const args = { call: 'adRenderSucceeded' };
105
-
106
- adapter.enableAnalytics();
107
- events.emit(eventType, args);
108
-
109
- let result = JSON.parse(server.requests[0].requestBody);
110
- expect(result).to.deep.equal({args: {call: 'adRenderSucceeded'}, eventType: 'adRenderSucceeded'});
111
- });
112
-
113
- it('SHOULD call global when an auction debug event occurs', function () {
114
- const eventType = AUCTION_DEBUG;
115
- const args = { call: 'auctionDebug' };
116
-
117
- adapter.enableAnalytics();
118
- events.emit(eventType, args);
119
-
120
- let result = JSON.parse(server.requests[0].requestBody);
121
- expect(result).to.deep.equal({args: {call: 'auctionDebug'}, eventType: 'auctionDebug'});
122
- });
123
-
124
- it('SHOULD call global when an addAdUnits event occurs', function () {
125
- const eventType = ADD_AD_UNITS;
126
- const args = { call: 'addAdUnits' };
127
-
128
- adapter.enableAnalytics();
129
- events.emit(eventType, args);
130
-
131
- let result = JSON.parse(server.requests[0].requestBody);
132
- expect(result).to.deep.equal({args: {call: 'addAdUnits'}, eventType: 'addAdUnits'});
133
- });
134
-
135
- it('SHOULD call global when a requestBids event occurs', function () {
136
- const eventType = REQUEST_BIDS;
137
- const args = { call: 'request' };
138
-
139
- adapter.enableAnalytics();
140
- events.emit(eventType, args);
141
-
142
- let result = JSON.parse(server.requests[0].requestBody);
143
- expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'requestBids'});
144
- });
145
-
146
- it('SHOULD call global when a bidRequest event occurs', function () {
147
- const eventType = BID_REQUESTED;
148
- const args = { call: 'request' };
149
-
150
- adapter.enableAnalytics();
151
- events.emit(eventType, args);
152
-
153
- let result = JSON.parse(server.requests[0].requestBody);
154
- expect(result).to.deep.equal({args: {call: 'request'}, eventType: 'bidRequested'});
155
- });
156
-
157
- it('SHOULD call global when a bidResponse event occurs', function () {
158
- const eventType = BID_RESPONSE;
159
- const args = { call: 'response' };
160
-
161
- adapter.enableAnalytics();
162
- events.emit(eventType, args);
163
-
164
- let result = JSON.parse(server.requests[0].requestBody);
165
- expect(result).to.deep.equal({args: {call: 'response'}, eventType: 'bidResponse'});
166
- });
167
-
168
- it('SHOULD call global when a bidTimeout event occurs', function () {
169
- const eventType = BID_TIMEOUT;
170
- const args = { call: 'timeout' };
129
+ Object.values(DEFAULT_INCLUDE_EVENTS).forEach(eventType => {
130
+ it(`SHOULD call global when a ${eventType} event occurs`, () => {
131
+ const args = {more: 'info'};
171
132
 
172
- adapter.enableAnalytics();
173
- events.emit(eventType, args);
133
+ adapter.enableAnalytics();
134
+ events.emit(eventType, args);
174
135
 
175
- let result = JSON.parse(server.requests[0].requestBody);
176
- expect(result).to.deep.equal({args: {call: 'timeout'}, eventType: 'bidTimeout'});
136
+ let result = JSON.parse(server.requests[server.requests.length - 1].requestBody);
137
+ sinon.assert.match(result, {
138
+ eventType,
139
+ args: {
140
+ more: 'info'
141
+ },
142
+ });
143
+ });
177
144
  });
178
145
 
179
146
  it('SHOULD NOT call global again when adapter.enableAnalytics is called with previous timeout', function () {
180
- const eventType = BID_TIMEOUT;
181
- const args = { call: 'timeout' };
147
+ const eventType = BID_WON;
148
+ const args = {call: 'timeout'};
182
149
 
183
150
  events.emit(eventType, args);
184
151
  adapter.enableAnalytics();
@@ -189,7 +156,7 @@ FEATURE: Analytics Adapters API
189
156
 
190
157
  describe(`AND sampling is enabled\n`, function () {
191
158
  const eventType = BID_WON;
192
- const args = { more: 'info' };
159
+ const args = {more: 'info'};
193
160
 
194
161
  beforeEach(function () {
195
162
  sinon.stub(Math, 'random').returns(0.5);
@@ -225,3 +192,39 @@ FEATURE: Analytics Adapters API
225
192
  });
226
193
  });
227
194
  });
195
+
196
+ describe('Analytics asynchronous event tracking', () => {
197
+ before(() => {
198
+ setDebounceDelay(100);
199
+ });
200
+ after(() => {
201
+ setDebounceDelay(0);
202
+ });
203
+
204
+ let adapter, clock;
205
+
206
+ beforeEach(() => {
207
+ clock = sinon.useFakeTimers();
208
+ adapter = new AnalyticsAdapter(config);
209
+ adapter.track = sinon.stub();
210
+ adapter.enableAnalytics({});
211
+ });
212
+
213
+ afterEach(() => {
214
+ clock.restore();
215
+ })
216
+
217
+ it('does not call track as long as events are coming', () => {
218
+ events.emit(BID_WON, {i: 0});
219
+ sinon.assert.notCalled(adapter.track);
220
+ clock.tick(10);
221
+ events.emit(BID_WON, {i: 1});
222
+ sinon.assert.notCalled(adapter.track);
223
+ clock.tick(10);
224
+ sinon.assert.notCalled(adapter.track);
225
+ clock.tick(100);
226
+ sinon.assert.calledTwice(adapter.track);
227
+ sinon.assert.calledWith(adapter.track.firstCall, {eventType: BID_WON, args: {i: 0}});
228
+ sinon.assert.calledWith(adapter.track.secondCall, {eventType: BID_WON, args: {i: 1}});
229
+ });
230
+ })