prebid.js 9.53.1 → 9.53.2

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 (185) hide show
  1. package/dist/33acrossAnalyticsAdapter.js +1 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/BTBidAdapter.js +1 -1
  5. package/dist/adagioAnalyticsAdapter.js +1 -1
  6. package/dist/adagioBidAdapter.js +1 -1
  7. package/dist/adagioUtils.js +1 -1
  8. package/dist/addefendBidAdapter.js +1 -1
  9. package/dist/adgenerationBidAdapter.js +1 -1
  10. package/dist/adlooxRtdProvider.js +1 -1
  11. package/dist/adqueryBidAdapter.js +1 -1
  12. package/dist/adrelevantisBidAdapter.js +1 -1
  13. package/dist/adstirBidAdapter.js +1 -1
  14. package/dist/adtrgtmeBidAdapter.js +1 -1
  15. package/dist/adxcgAnalyticsAdapter.js +1 -1
  16. package/dist/adxcgBidAdapter.js +1 -1
  17. package/dist/adyoulikeBidAdapter.js +1 -1
  18. package/dist/agmaAnalyticsAdapter.js +1 -1
  19. package/dist/ajaBidAdapter.js +1 -1
  20. package/dist/amxBidAdapter.js +1 -1
  21. package/dist/amxIdSystem.js +1 -1
  22. package/dist/aniviewBidAdapter.js +1 -1
  23. package/dist/appierAnalyticsAdapter.js +1 -1
  24. package/dist/appnexusBidAdapter.js +1 -1
  25. package/dist/asoBidAdapter.js +1 -1
  26. package/dist/axonixBidAdapter.js +1 -1
  27. package/dist/beopBidAdapter.js +1 -1
  28. package/dist/bidglassBidAdapter.js +1 -1
  29. package/dist/big-richmediaBidAdapter.js +1 -1
  30. package/dist/bitmediaBidAdapter.js +1 -1
  31. package/dist/bridBidAdapter.js +1 -1
  32. package/dist/bridgeuppBidAdapter.js +1 -1
  33. package/dist/bridgewellBidAdapter.js +1 -1
  34. package/dist/brightMountainMediaBidAdapter.js +1 -1
  35. package/dist/carodaBidAdapter.js +1 -1
  36. package/dist/chtnwBidAdapter.js +1 -1
  37. package/dist/chunk-core.js +1 -1
  38. package/dist/concertBidAdapter.js +1 -1
  39. package/dist/connectadBidAdapter.js +1 -1
  40. package/dist/consumableBidAdapter.js +1 -1
  41. package/dist/contxtfulBidAdapter.js +1 -1
  42. package/dist/conversantAnalyticsAdapter.js +1 -1
  43. package/dist/conversantBidAdapter.js +1 -1
  44. package/dist/craftBidAdapter.js +1 -1
  45. package/dist/criteoBidAdapter.js +1 -1
  46. package/dist/cwireBidAdapter.js +1 -1
  47. package/dist/dailymotionBidAdapter.js +1 -1
  48. package/dist/dependencies.json +6 -1
  49. package/dist/dspxBidAdapter.js +1 -1
  50. package/dist/dxkultureBidAdapter.js +1 -1
  51. package/dist/eplanningBidAdapter.js +1 -1
  52. package/dist/equativBidAdapter.js +1 -1
  53. package/dist/eskimiBidAdapter.js +1 -1
  54. package/dist/euidIdSystem.js +1 -1
  55. package/dist/exadsBidAdapter.js +1 -1
  56. package/dist/excoBidAdapter.js +1 -1
  57. package/dist/fanAdapter.js +1 -1
  58. package/dist/feedadBidAdapter.js +1 -1
  59. package/dist/finativeBidAdapter.js +1 -1
  60. package/dist/freewheel-sspBidAdapter.js +1 -1
  61. package/dist/gmosspBidAdapter.js +1 -1
  62. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  63. package/dist/greenbidsBidAdapter.js +1 -1
  64. package/dist/greenbidsRtdProvider.js +1 -1
  65. package/dist/gridBidAdapter.js +1 -1
  66. package/dist/gumgumBidAdapter.js +1 -1
  67. package/dist/h12mediaBidAdapter.js +1 -1
  68. package/dist/hypelabBidAdapter.js +1 -1
  69. package/dist/id5AnalyticsAdapter.js +1 -1
  70. package/dist/id5IdSystem.js +1 -1
  71. package/dist/imdsBidAdapter.js +1 -1
  72. package/dist/improvedigitalBidAdapter.js +1 -1
  73. package/dist/inmobiBidAdapter.js +1 -1
  74. package/dist/insticatorBidAdapter.js +1 -1
  75. package/dist/intentIqAnalyticsAdapter.js +1 -1
  76. package/dist/ixBidAdapter.js +1 -1
  77. package/dist/jixieBidAdapter.js +1 -1
  78. package/dist/justpremiumBidAdapter.js +1 -1
  79. package/dist/kargoBidAdapter.js +1 -1
  80. package/dist/kimberliteBidAdapter.js +1 -1
  81. package/dist/konduitAnalyticsAdapter.js +1 -1
  82. package/dist/kueezBidAdapter.js +1 -1
  83. package/dist/lassoBidAdapter.js +1 -1
  84. package/dist/lifestreetBidAdapter.js +1 -1
  85. package/dist/liveIntentId.js +1 -1
  86. package/dist/logicadBidAdapter.js +1 -1
  87. package/dist/loglyliftBidAdapter.js +1 -1
  88. package/dist/luceadBidAdapter.js +1 -1
  89. package/dist/mabidderBidAdapter.js +1 -1
  90. package/dist/madsenseBidAdapter.js +1 -1
  91. package/dist/magniteAnalyticsAdapter.js +1 -1
  92. package/dist/malltvAnalyticsAdapter.js +1 -1
  93. package/dist/marsmediaBidAdapter.js +1 -1
  94. package/dist/mediafuseBidAdapter.js +1 -1
  95. package/dist/medianetBidAdapter.js +1 -1
  96. package/dist/medianetUtils.js +1 -1
  97. package/dist/mediasquareBidAdapter.js +1 -1
  98. package/dist/mgidBidAdapter.js +1 -1
  99. package/dist/missenaBidAdapter.js +1 -1
  100. package/dist/mobilefuseBidAdapter.js +1 -1
  101. package/dist/nextMillenniumBidAdapter.js +1 -1
  102. package/dist/nexx360Utils.js +1 -1
  103. package/dist/nobidAnalyticsAdapter.js +1 -1
  104. package/dist/nobidBidAdapter.js +1 -1
  105. package/dist/nodalsAiRtdProvider.js +1 -1
  106. package/dist/not-for-prod/prebid.js +168 -168
  107. package/dist/oguryBidAdapter.js +1 -1
  108. package/dist/onetagBidAdapter.js +1 -1
  109. package/dist/ooloAnalyticsAdapter.js +1 -1
  110. package/dist/openxBidAdapter.js +1 -1
  111. package/dist/optidigitalBidAdapter.js +1 -1
  112. package/dist/orbidderBidAdapter.js +1 -1
  113. package/dist/outbrainBidAdapter.js +1 -1
  114. package/dist/pixfutureBidAdapter.js +1 -1
  115. package/dist/publinkIdSystem.js +1 -1
  116. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  117. package/dist/pubmaticBidAdapter.js +1 -1
  118. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  119. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  120. package/dist/pxyzBidAdapter.js +1 -1
  121. package/dist/quantcastBidAdapter.js +1 -1
  122. package/dist/readpeakBidAdapter.js +1 -1
  123. package/dist/relaidoBidAdapter.js +1 -1
  124. package/dist/retailspotBidAdapter.js +1 -1
  125. package/dist/rhythmoneBidAdapter.js +1 -1
  126. package/dist/riseUtils.js +1 -1
  127. package/dist/rubiconBidAdapter.js +1 -1
  128. package/dist/seedingAllianceBidAdapter.js +1 -1
  129. package/dist/seedtagBidAdapter.js +1 -1
  130. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  131. package/dist/sharethroughBidAdapter.js +1 -1
  132. package/dist/showheroes-bsBidAdapter.js +1 -1
  133. package/dist/smaatoBidAdapter.js +1 -1
  134. package/dist/smartadserverBidAdapter.js +1 -1
  135. package/dist/smartxBidAdapter.js +1 -1
  136. package/dist/smilewantedBidAdapter.js +1 -1
  137. package/dist/snigelBidAdapter.js +1 -1
  138. package/dist/sonobiBidAdapter.js +1 -1
  139. package/dist/sovrnBidAdapter.js +1 -1
  140. package/dist/sparteoBidAdapter.js +1 -1
  141. package/dist/sspBCBidAdapter.js +1 -1
  142. package/dist/stvBidAdapter.js +1 -1
  143. package/dist/sublimeBidAdapter.js +1 -1
  144. package/dist/taboolaBidAdapter.js +1 -1
  145. package/dist/tappxBidAdapter.js +1 -1
  146. package/dist/targetVideoBidAdapter.js +1 -1
  147. package/dist/teadsBidAdapter.js +1 -1
  148. package/dist/terceptAnalyticsAdapter.js +1 -1
  149. package/dist/themoneytizerBidAdapter.js +1 -1
  150. package/dist/trionBidAdapter.js +1 -1
  151. package/dist/tripleliftBidAdapter.js +1 -1
  152. package/dist/ttdBidAdapter.js +1 -1
  153. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  154. package/dist/uid2IdSystem.js +1 -1
  155. package/dist/underdogmediaBidAdapter.js +1 -1
  156. package/dist/undertoneBidAdapter.js +1 -1
  157. package/dist/unrulyBidAdapter.js +1 -1
  158. package/dist/userId.js +1 -1
  159. package/dist/vidazooUtils.js +1 -1
  160. package/dist/videobyteBidAdapter.js +1 -1
  161. package/dist/visxBidAdapter.js +1 -1
  162. package/dist/vuukleBidAdapter.js +1 -1
  163. package/dist/widespaceBidAdapter.js +1 -1
  164. package/dist/winrBidAdapter.js +1 -1
  165. package/dist/yahooAdsBidAdapter.js +1 -1
  166. package/dist/yandexBidAdapter.js +1 -1
  167. package/dist/yieldmoBidAdapter.js +1 -1
  168. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  169. package/libraries/liveIntentId/shared.js +16 -0
  170. package/modules/fanAdapter.js +318 -124
  171. package/modules/userId/index.js +30 -31
  172. package/package.json +4 -4
  173. package/test/spec/modules/euidIdSystem_spec.js +9 -3
  174. package/test/spec/modules/fanAdapter_spec.js +264 -268
  175. package/test/spec/modules/id5IdSystem_spec.js +57 -101
  176. package/test/spec/modules/idxIdSystem_spec.js +2 -75
  177. package/test/spec/modules/liveIntentExternalIdSystem_spec.js +5 -0
  178. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
  179. package/test/spec/modules/liveIntentIdSystem_spec.js +38 -0
  180. package/test/spec/modules/lmpIdSystem_spec.js +2 -81
  181. package/test/spec/modules/pubmaticBidAdapter_spec.js +411 -126
  182. package/test/spec/modules/sharedIdSystem_spec.js +3 -3
  183. package/test/spec/modules/uid2IdSystem_helpers.js +5 -2
  184. package/test/spec/modules/userId_spec.js +142 -387
  185. package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +3 -69
@@ -1,176 +1,370 @@
1
- import * as utils from '../src/utils.js';
2
- import { ajax } from '../src/ajax.js';
3
- import { BANNER, NATIVE } from '../src/mediaTypes.js';
1
+ import { ortbConverter } from '../libraries/ortbConverter/converter.js';
4
2
  import { registerBidder } from '../src/adapters/bidderFactory.js';
5
-
6
- /**
7
- * @typedef {import('../src/adapters/bidderFactory.js').BidderRequest} BidderRequest
8
- * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
9
- * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
10
- * @typedef {import('../src/adapters/bidderFactory.js').ServerResponse} ServerResponse
11
- */
3
+ import { BANNER, VIDEO } from '../src/mediaTypes.js';
4
+ import { deepAccess, deepSetValue, logInfo, logWarn, logError, triggerPixel } from '../src/utils.js';
5
+ import { getStorageManager } from '../src/storageManager.js';
6
+ import { Renderer } from '../src/Renderer.js';
7
+ import { getGptSlotInfoForAdUnitCode } from '../libraries/gptUtils/gptUtils.js';
12
8
 
13
9
  const BIDDER_CODE = 'freedomadnetwork';
14
- const BASE_URL = 'https://srv.freedomadnetwork.com';
10
+ const BIDDER_VERSION = '0.2.0';
11
+ const NETWORK_ENDPOINTS = {
12
+ 'fan': 'https://srv.freedomadnetwork.com/ortb',
13
+ 'armanet': 'https://srv.armanet.us/ortb',
14
+ 'test': 'http://localhost:8001/ortb',
15
+ };
15
16
 
16
- /**
17
- * Build OpenRTB request from bidRequest and bidderRequest
18
- *
19
- * @param {BidRequest} bid
20
- * @param {BidderRequest} bidderRequest
21
- * @returns {Request}
22
- */
23
- function buildBidRequest(bid, bidderRequest) {
24
- const payload = {
25
- id: bid.bidId,
26
- tmax: bidderRequest.timeout,
27
- placements: [bid.params.placementId],
28
- at: 1,
29
- user: {}
30
- }
17
+ const DEFAULT_ENDPOINT = NETWORK_ENDPOINTS['fan'];
18
+ const DEFAULT_CURRENCY = 'USD';
19
+ const DEFAULT_TTL = 300;
31
20
 
32
- const gdprConsent = utils.deepAccess(bidderRequest, 'gdprConsent');
33
- if (!!gdprConsent && gdprConsent.gdprApplies) {
34
- payload.user.gdpr = 1;
35
- payload.user.consent = gdprConsent.consentString;
36
- }
21
+ export const storage = getStorageManager({bidderCode: BIDDER_CODE});
37
22
 
38
- const uspConsent = utils.deepAccess(bidderRequest, 'uspConsent');
39
- if (uspConsent) {
40
- payload.user.usp = uspConsent;
41
- }
23
+ const converter = ortbConverter({
24
+ context: {
25
+ netRevenue: true,
26
+ ttl: DEFAULT_TTL,
27
+ currency: DEFAULT_CURRENCY
28
+ },
29
+
30
+ imp(buildImp, bidRequest, context) {
31
+ const imp = buildImp(bidRequest, context);
32
+
33
+ // Add custom fields to impression
34
+ if (bidRequest.params.placementId) {
35
+ imp.tagid = bidRequest.params.placementId;
36
+ }
37
+
38
+ // Add floor price
39
+ if (bidRequest.params.bidFloor) {
40
+ imp.bidfloor = parseFloat(bidRequest.params.bidFloor);
41
+ imp.bidfloorcur = bidRequest.params.bidFloorCur || DEFAULT_CURRENCY;
42
+ }
43
+
44
+ // Add custom extensions
45
+ deepSetValue(imp, 'ext.prebid.storedrequest.id', bidRequest.params.placementId);
46
+ deepSetValue(imp, 'ext.bidder', {
47
+ network: bidRequest.params.network || 'fan',
48
+ placementId: bidRequest.params.placementId
49
+ });
50
+
51
+ return imp;
52
+ },
53
+
54
+ request(buildRequest, imps, bidderRequest, context) {
55
+ const request = buildRequest(imps, bidderRequest, context);
56
+
57
+ // First price auction
58
+ request.at = 1;
59
+ request.cur = [DEFAULT_CURRENCY];
60
+
61
+ // Add source information
62
+ deepSetValue(request, 'source.tid', bidderRequest.auctionId);
63
+
64
+ // Add custom extensions
65
+ deepSetValue(request, 'ext.prebid.channel', BIDDER_CODE);
66
+ deepSetValue(request, 'ext.prebid.version', BIDDER_VERSION);
67
+
68
+ // Add user extensions
69
+ const firstBid = imps[0];
70
+ const pbUser = firstBid.userId || {};
71
+ request.user = request.user || {};
72
+ request.user.ext = request.user.ext || {};
42
73
 
43
- return {
44
- method: 'POST',
45
- url: BASE_URL + '/pb/req',
46
- data: JSON.stringify(payload),
47
- options: {
48
- contentType: 'application/json',
49
- withCredentials: false,
50
- customHeaders: {
51
- 'Accept-Language': 'en;q=10',
52
- },
53
- },
54
- originalBidRequest: bid
74
+ if (pbUser.tdid) {
75
+ request.user.ext.tdid = pbUser.tdid;
76
+ }
77
+
78
+ if (window.geck) {
79
+ request.user.ext.adi = window.geck;
80
+ }
81
+
82
+ if (pbUser.pubcid) {
83
+ request.user.ext.pubcid = pbUser.pubcid;
84
+ }
85
+
86
+ if (pbUser.id5id?.uid) {
87
+ request.user.ext.id5id = pbUser.id5id.uid;
88
+ }
89
+
90
+ if (pbUser.lipb?.lipbid) {
91
+ request.user.ext.lipbid = pbUser.lipb.lipbid;
92
+ }
93
+
94
+ return request;
95
+ },
96
+
97
+ bidResponse(buildBidResponse, bid, context) {
98
+ const { bidRequest } = context;
99
+ const bidResponse = buildBidResponse(bid, context);
100
+
101
+ // Add custom bid response fields
102
+ bidResponse.meta = bidResponse.meta || {};
103
+ bidResponse.meta.networkName = BIDDER_CODE;
104
+ bidResponse.meta.advertiserDomains = bid.adomain || [];
105
+
106
+ if (bid.ext && bid.ext.libertas) {
107
+ bidResponse.meta.libertas = bid.ext.libertas;
108
+ }
109
+
110
+ // Add tracking URLs
111
+ if (bid.nurl) {
112
+ bidResponse.nurl = bid.nurl;
113
+ }
114
+
115
+ // Handle different ad formats
116
+ if (bidResponse.mediaType === BANNER) {
117
+ bidResponse.ad = bid.adm;
118
+ bidResponse.width = bid.w;
119
+ bidResponse.height = bid.h;
120
+ } else if (bidResponse.mediaType === VIDEO) {
121
+ bidResponse.vastXml = bid.adm;
122
+ bidResponse.width = bid.w;
123
+ bidResponse.height = bid.h;
124
+ }
125
+
126
+ // Add renderer if needed for outstream video
127
+ if (bidResponse.mediaType === VIDEO && bid.ext.libertas.ovp) {
128
+ bidResponse.width = bid.w;
129
+ bidResponse.height = bid.h;
130
+ bidResponse.renderer = createRenderer(bidRequest, bid.ext.libertas.vp);
131
+ }
132
+
133
+ return bidResponse;
55
134
  }
56
- }
135
+ });
57
136
 
58
137
  export const spec = {
59
138
  code: BIDDER_CODE,
60
- isBidRequestValid: function(bid) {
61
- if (!bid) {
62
- utils.logWarn(BIDDER_CODE, 'Invalid bid', bid);
139
+ supportedMediaTypes: [BANNER, VIDEO],
140
+
141
+ isBidRequestValid(bid) {
142
+ // Validate minimum required parameters
143
+ if (!bid.params) {
144
+ logError(`${BIDDER_CODE}: bid.params is required`);
63
145
 
64
146
  return false;
65
147
  }
66
148
 
67
- if (!bid.params) {
68
- utils.logWarn(BIDDER_CODE, 'bid.params is required');
149
+ // Validate placement ID
150
+ if (!bid.params.placementId) {
151
+ logError(`${BIDDER_CODE}: placementId is required`);
69
152
 
70
153
  return false;
71
154
  }
72
155
 
73
- if (!bid.params.placementId) {
74
- utils.logWarn(BIDDER_CODE, 'bid.params.placementId is required');
156
+ // Validate network parameter
157
+ if (bid.params.network && !NETWORK_ENDPOINTS[bid.params.network]) {
158
+ logError(`${BIDDER_CODE}: Invalid network: ${bid.params.network}`);
75
159
 
76
160
  return false;
77
161
  }
78
162
 
79
- var banner = utils.deepAccess(bid, 'mediaTypes.banner');
80
- if (banner === undefined) {
163
+ // Validate media types
164
+ if (!bid.mediaTypes || (!bid.mediaTypes.banner && !bid.mediaTypes.video)) {
165
+ logError(`${BIDDER_CODE}: Only banner and video mediaTypes are supported`);
166
+
81
167
  return false;
82
168
  }
83
169
 
170
+ // Validate video parameters if video mediaType is present
171
+ if (bid.mediaTypes.video) {
172
+ const video = bid.mediaTypes.video;
173
+ if (!video.mimes || !Array.isArray(video.mimes) || video.mimes.length === 0) {
174
+ logError(`${BIDDER_CODE}: video.mimes is required for video ads`);
175
+
176
+ return false;
177
+ }
178
+
179
+ if (!video.playerSize || !Array.isArray(video.playerSize)) {
180
+ logError(`${BIDDER_CODE}: video.playerSize is required for video ads`);
181
+
182
+ return false;
183
+ }
184
+ }
185
+
84
186
  return true;
85
187
  },
86
188
 
87
- buildRequests: function(validBidRequests, bidderRequest) {
88
- return validBidRequests.map(bid => buildBidRequest(bid, bidderRequest));
189
+ /**
190
+ * Make server requests from the list of BidRequests
191
+ */
192
+ buildRequests(validBidRequests, bidderRequest) {
193
+ const requestsByNetwork = validBidRequests.reduce((acc, bid) => {
194
+ const network = bid.params.network || 'fan';
195
+ if (!acc[network]) {
196
+ acc[network] = [];
197
+ }
198
+ acc[network].push(bid);
199
+
200
+ return acc;
201
+ }, {});
202
+
203
+ return Object.entries(requestsByNetwork).map(([network, bids]) => {
204
+ const data = converter.toORTB({
205
+ bidRequests: bids,
206
+ bidderRequest,
207
+ context: { network }
208
+ });
209
+
210
+ return {
211
+ method: 'POST',
212
+ url: NETWORK_ENDPOINTS[network] || DEFAULT_ENDPOINT,
213
+ data,
214
+ options: {
215
+ contentType: 'application/json',
216
+ withCredentials: false
217
+ },
218
+ bids
219
+ };
220
+ });
89
221
  },
90
222
 
91
223
  /**
92
- * Unpack the response from the server into a list of bids.
93
- *
94
- * @param {ServerResponse} serverResponse A successful response from the server.
95
- * @return {Bid[]} An array of bids which were nested inside the server.
224
+ * Unpack the response from the server into a list of bids
96
225
  */
97
- interpretResponse: function (serverResponse, bidRequest) {
98
- const serverBody = serverResponse.body;
99
- let bidResponses = [];
100
-
101
- if (!serverBody) {
102
- return bidResponses;
103
- }
104
-
105
- serverBody.forEach((response) => {
106
- const bidResponse = {
107
- requestId: response.id,
108
- bidid: response.bidid,
109
- impid: response.impid,
110
- userId: response.userId,
111
- cpm: response.cpm,
112
- currency: response.currency,
113
- width: response.width,
114
- height: response.height,
115
- ad: response.payload,
116
- ttl: response.ttl,
117
- creativeId: response.crid,
118
- netRevenue: response.netRevenue,
119
- trackers: response.trackers,
120
- meta: {
121
- mediaType: response.mediaType,
122
- advertiserDomains: response.domains,
123
- }
124
- };
226
+ interpretResponse(serverResponse, bidRequest) {
227
+ if (!serverResponse.body) {
228
+ return [];
229
+ }
125
230
 
126
- bidResponses.push(bidResponse);
231
+ const response = converter.fromORTB({
232
+ response: serverResponse.body,
233
+ request: bidRequest.data,
127
234
  });
128
235
 
129
- return bidResponses;
236
+ return response.bids || [];
130
237
  },
131
238
 
132
239
  /**
133
- * Register bidder specific code, which will execute if a bid from this bidder won the auction
134
- *
135
- * @param {Bid} bid The bid that won the auction
240
+ * Handle bidder errors
136
241
  */
137
- onBidWon: function (bid) {
138
- if (!bid) {
139
- return;
140
- }
242
+ onBidderError: function(error) {
243
+ logError(`${BIDDER_CODE} bidder error`, error);
244
+ },
141
245
 
142
- const payload = {
143
- id: bid.bidid,
144
- impid: bid.impid,
145
- t: bid.cpm,
146
- u: bid.userId,
246
+ /**
247
+ * Register user sync pixels
248
+ */
249
+ getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) {
250
+ if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) {
251
+ return [];
147
252
  }
148
253
 
149
- ajax(BASE_URL + '/pb/imp', null, JSON.stringify(payload), {
150
- method: 'POST',
151
- customHeaders: {
152
- 'Accept-Language': 'en;q=10',
153
- },
254
+ const syncs = [];
255
+ const seenUrls = new Set();
256
+
257
+ serverResponses.forEach(response => {
258
+ const userSync = deepAccess(response.body, 'ext.sync');
259
+ if (!userSync) {
260
+ return;
261
+ }
262
+
263
+ if (syncOptions.iframeEnabled && userSync.iframe) {
264
+ userSync.iframe.forEach(sync => {
265
+ const url = buildSyncUrl(sync.url, gdprConsent, uspConsent, gppConsent);
266
+ if (!seenUrls.has(url)) {
267
+ seenUrls.add(url);
268
+ syncs.push({
269
+ type: 'iframe',
270
+ url
271
+ });
272
+ }
273
+ });
274
+ }
275
+
276
+ if (syncOptions.pixelEnabled && userSync.image) {
277
+ userSync.image.forEach(sync => {
278
+ const url = buildSyncUrl(sync.url, gdprConsent, uspConsent, gppConsent);
279
+ if (!seenUrls.has(url)) {
280
+ seenUrls.add(url);
281
+ syncs.push({
282
+ type: 'image',
283
+ url
284
+ });
285
+ }
286
+ });
287
+ }
154
288
  });
155
289
 
156
- if (bid.trackers && bid.trackers.length > 0) {
157
- for (var i = 0; i < bid.trackers.length; i++) {
158
- if (bid.trackers[i].type == 0) {
159
- utils.triggerPixel(bid.trackers[i].url);
290
+ return syncs;
291
+ },
292
+
293
+ /**
294
+ * Handle bid won event
295
+ */
296
+ onBidWon(bid) {
297
+ logInfo(`${BIDDER_CODE}: Bid won`, bid);
298
+
299
+ if (bid.nurl) {
300
+ triggerPixel(bid.nurl);
301
+ }
302
+
303
+ if (bid.meta.libertas.pxl && bid.meta.libertas.pxl.length > 0) {
304
+ for (var i = 0; i < bid.meta.libertas.pxl.length; i++) {
305
+ if (bid.meta.libertas.pxl[i].type == 0) {
306
+ triggerPixel(bid.meta.libertas.pxl[i].url);
160
307
  }
161
308
  }
162
309
  }
163
310
  },
164
- onSetTargeting: function(bid) {},
165
- onBidderError: function(error) {
166
- utils.logError(`${BIDDER_CODE} bidder error`, error);
167
- },
168
- getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
169
- const syncs = [];
170
- return syncs;
171
- },
172
- onTimeout: function(timeoutData) {},
173
- supportedMediaTypes: [BANNER, NATIVE]
311
+ };
312
+
313
+ /**
314
+ * Build sync URL with privacy parameters
315
+ */
316
+ function buildSyncUrl(baseUrl, gdprConsent, uspConsent, gppConsent) {
317
+ try {
318
+ const url = new URL(baseUrl);
319
+
320
+ if (gdprConsent) {
321
+ url.searchParams.set('gdpr', gdprConsent.gdprApplies ? '1' : '0');
322
+ if (gdprConsent.consentString) {
323
+ url.searchParams.set('gdpr_consent', gdprConsent.consentString);
324
+ }
325
+ }
326
+
327
+ if (uspConsent) {
328
+ url.searchParams.set('us_privacy', uspConsent);
329
+ }
330
+
331
+ if (gppConsent?.gppString) {
332
+ url.searchParams.set('gpp', gppConsent.gppString);
333
+ if (gppConsent.applicableSections?.length) {
334
+ url.searchParams.set('gpp_sid', gppConsent.applicableSections.join(','));
335
+ }
336
+ }
337
+
338
+ return url.toString();
339
+ } catch (e) {
340
+ logWarn(`${BIDDER_CODE}: Invalid sync URL: ${baseUrl}`);
341
+
342
+ return baseUrl;
343
+ }
344
+ }
345
+
346
+ /**
347
+ * Create renderer for outstream video
348
+ */
349
+ function createRenderer(bid, videoPlayerUrl) {
350
+ const renderer = Renderer.install({
351
+ url: videoPlayerUrl,
352
+ loaded: false,
353
+ adUnitCode: bid.adUnitCode,
354
+ });
355
+
356
+ try {
357
+ renderer.setRender(function (bidResponse) {
358
+ const divId = document.getElementById(bid.adUnitCode) ? bid.adUnitCode : getGptSlotInfoForAdUnitCode(bid.adUnitCode).divId;
359
+ const adUnit = document.getElementById(divId);
360
+
361
+ window.createOutstreamPlayer(adUnit, bidResponse.vastXml, bid.width, bid.height);
362
+ });
363
+ } catch (error) {
364
+ logWarn('Renderer error: setRender() failed', error);
365
+ }
366
+
367
+ return renderer;
174
368
  }
175
369
 
176
370
  registerBidder(spec);
@@ -571,25 +571,21 @@ export function enrichEids(ortb2Fragments) {
571
571
  export function addIdData({adUnits, ortb2Fragments}) {
572
572
  ortb2Fragments = ortb2Fragments ?? {global: {}, bidder: {}}
573
573
  enrichEids(ortb2Fragments);
574
- if ([adUnits].some(i => !Array.isArray(i) || !i.length)) {
575
- return;
574
+
575
+ // Set bid.userId for backward compatibility with tests
576
+ if (adUnits && Array.isArray(adUnits) && adUnits.length) {
577
+ const globalIds = getIds(initializedSubmodules.global);
578
+ adUnits.forEach(adUnit => {
579
+ if (adUnit.bids && Array.isArray(adUnit.bids)) {
580
+ adUnit.bids.forEach(bid => {
581
+ const bidderIds = Object.assign({}, globalIds, getIds(initializedSubmodules.bidder[bid.bidder] ?? {}));
582
+ if (Object.keys(bidderIds).length > 0) {
583
+ bid.userId = bidderIds;
584
+ }
585
+ });
586
+ }
587
+ });
576
588
  }
577
- const globalIds = getIds(initializedSubmodules.global);
578
- const globalEids = ortb2Fragments.global.user?.ext?.eids || [];
579
- adUnits.forEach(adUnit => {
580
- if (adUnit.bids && isArray(adUnit.bids)) {
581
- adUnit.bids.forEach(bid => {
582
- const bidderIds = Object.assign({}, globalIds, getIds(initializedSubmodules.bidder[bid.bidder] ?? {}));
583
- const bidderEids = globalEids.concat(ortb2Fragments.bidder?.[bid.bidder]?.user?.ext?.eids || []);
584
- if (Object.keys(bidderIds).length > 0) {
585
- bid.userId = bidderIds;
586
- }
587
- if (bidderEids.length > 0) {
588
- bid.userIdAsEids = bidderEids;
589
- }
590
- });
591
- }
592
- });
593
589
  }
594
590
 
595
591
  const INIT_CANCELED = {};
@@ -724,15 +720,22 @@ export const startAuctionHook = timedAuctionHook('userId', function requestBidsH
724
720
  });
725
721
 
726
722
  /**
727
- * Append user id data from config to bids to be accessed in adapters when there are no submodules.
728
- * @param {function} fn required; The next function in the chain, used by hook.js
729
- * @param {Object} reqBidsConfigObj required; This is the same param that's used in pbjs.requestBids.
723
+ * Alias bid requests' `userIdAsEids` to `ortb2.user.ext.eids`
724
+ * Do this lazily (instead of attaching a copy) so that it also shows EIDs added after the userId module runs (e.g. from RTD modules)
730
725
  */
731
- export const addUserIdsHook = timedAuctionHook('userId', function requestBidsHook(fn, reqBidsConfigObj) {
732
- addIdData(reqBidsConfigObj);
733
- // calling fn allows prebid to continue processing
734
- fn.call(this, reqBidsConfigObj);
735
- });
726
+ function aliasEidsHook(next, bidderRequests) {
727
+ bidderRequests.forEach(bidderRequest => {
728
+ bidderRequest.bids.forEach(bid =>
729
+ Object.defineProperty(bid, 'userIdAsEids', {
730
+ configurable: true,
731
+ get() {
732
+ return bidderRequest.ortb2.user?.ext?.eids;
733
+ }
734
+ })
735
+ )
736
+ })
737
+ next(bidderRequests);
738
+ }
736
739
 
737
740
  /**
738
741
  * Is startAuctionHook added
@@ -1158,7 +1161,6 @@ function updateSubmodules() {
1158
1161
 
1159
1162
  if (submodules.length) {
1160
1163
  if (!addedStartAuctionHook()) {
1161
- startAuction.getHooks({hook: addUserIdsHook}).remove();
1162
1164
  startAuction.before(startAuctionHook, 100) // use higher priority than dataController / rtd
1163
1165
  adapterManager.callDataDeletionRequest.before(requestDataDeletion);
1164
1166
  coreGetPPID.after((next) => next(getPPID()));
@@ -1259,6 +1261,7 @@ export function init(config, {mkDelay = delay} = {}) {
1259
1261
  }
1260
1262
  }
1261
1263
  });
1264
+ adapterManager.makeBidRequests.after(aliasEidsHook);
1262
1265
 
1263
1266
  // exposing getUserIds function in global-name-space so that userIds stored in Prebid can be used by external codes.
1264
1267
  (getGlobal()).getUserIds = getUserIds;
@@ -1268,10 +1271,6 @@ export function init(config, {mkDelay = delay} = {}) {
1268
1271
  (getGlobal()).refreshUserIds = normalizePromise(refreshUserIds);
1269
1272
  (getGlobal()).getUserIdsAsync = normalizePromise(getUserIdsAsync);
1270
1273
  (getGlobal()).getUserIdsAsEidBySource = getUserIdsAsEidBySource;
1271
- if (!addedStartAuctionHook()) {
1272
- // Add ortb2.user.ext.eids even if 0 submodules are added
1273
- startAuction.before(addUserIdsHook, 100); // use higher priority than dataController / rtd
1274
- }
1275
1274
  }
1276
1275
 
1277
1276
  export function resetUserIds() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prebid.js",
3
- "version": "9.53.1",
3
+ "version": "9.53.2",
4
4
  "description": "Header Bidding Management Library",
5
5
  "main": "src/prebid.public.js",
6
6
  "exports": {
@@ -123,8 +123,7 @@
123
123
  "webpack": "^5.70.0",
124
124
  "webpack-bundle-analyzer": "^4.5.0",
125
125
  "webpack-manifest-plugin": "^5.0.0",
126
- "webpack-stream": "^7.0.0",
127
- "yargs": "^1.3.1"
126
+ "webpack-stream": "^7.0.0"
128
127
  },
129
128
  "dependencies": {
130
129
  "@babel/core": "^7.27.4",
@@ -139,7 +138,8 @@
139
138
  "fun-hooks": "^1.1.0",
140
139
  "gulp-wrap": "^0.15.0",
141
140
  "klona": "^2.0.6",
142
- "live-connect-js": "^7.2.0"
141
+ "live-connect-js": "^7.2.0",
142
+ "yargs": "^1.3.1"
143
143
  },
144
144
  "optionalDependencies": {
145
145
  "fsevents": "^2.3.2"
@@ -38,9 +38,15 @@ const cstgApiUrl = 'https://prod.euid.eu/v2/token/client-generate';
38
38
  const headers = { 'Content-Type': 'application/json' };
39
39
  const makeSuccessResponseBody = (token) => btoa(JSON.stringify({ status: 'success', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: token } }));
40
40
  const makeOptoutResponseBody = (token) => btoa(JSON.stringify({ status: 'optout', body: { ...apiHelpers.makeTokenResponse(initialToken), advertising_token: token } }));
41
- const expectToken = (bid, token) => expect(bid?.userId ?? {}).to.deep.include(makeEuidIdentityContainer(token));
42
- const expectOptout = (bid, token) => expect(bid?.userId ?? {}).to.deep.include(makeEuidOptoutContainer(token));
43
- const expectNoIdentity = (bid) => expect(bid).to.not.haveOwnProperty('userId');
41
+ function findEuid(bid) {
42
+ return (bid?.userIdAsEids ?? []).find(e => e.source === 'euid.eu');
43
+ }
44
+ const expectToken = (bid, token) => {
45
+ const eid = findEuid(bid);
46
+ expect(eid && eid.uids[0].id).to.equal(token);
47
+ };
48
+ const expectOptout = (bid) => expect(findEuid(bid)).to.be.undefined;
49
+ const expectNoIdentity = (bid) => expect(findEuid(bid)).to.be.undefined;
44
50
 
45
51
  describe('EUID module', function() {
46
52
  let suiteSandbox, restoreSubtleToUndefined = false;