prebid.js 9.52.0 → 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 (235) hide show
  1. package/.circleci/config.yml +27 -4
  2. package/creative/crossDomain.js +4 -2
  3. package/dist/33acrossAnalyticsAdapter.js +1 -1
  4. package/dist/33acrossBidAdapter.js +1 -1
  5. package/dist/33acrossIdSystem.js +1 -1
  6. package/dist/BTBidAdapter.js +1 -1
  7. package/dist/adagioAnalyticsAdapter.js +1 -1
  8. package/dist/adagioBidAdapter.js +1 -1
  9. package/dist/adagioUtils.js +1 -1
  10. package/dist/addefendBidAdapter.js +1 -1
  11. package/dist/adgenerationBidAdapter.js +1 -1
  12. package/dist/adlooxRtdProvider.js +1 -1
  13. package/dist/adqueryBidAdapter.js +1 -1
  14. package/dist/adrelevantisBidAdapter.js +1 -1
  15. package/dist/adstirBidAdapter.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/adyoulikeBidAdapter.js +1 -1
  20. package/dist/agmaAnalyticsAdapter.js +1 -1
  21. package/dist/ajaBidAdapter.js +1 -1
  22. package/dist/amxBidAdapter.js +1 -1
  23. package/dist/amxIdSystem.js +1 -1
  24. package/dist/aniviewBidAdapter.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/axonixBidAdapter.js +1 -1
  29. package/dist/beopBidAdapter.js +1 -1
  30. package/dist/bidglassBidAdapter.js +1 -1
  31. package/dist/big-richmediaBidAdapter.js +1 -1
  32. package/dist/bitmediaBidAdapter.js +1 -1
  33. package/dist/bridBidAdapter.js +1 -1
  34. package/dist/bridgeuppBidAdapter.js +1 -1
  35. package/dist/bridgewellBidAdapter.js +1 -1
  36. package/dist/brightMountainMediaBidAdapter.js +1 -1
  37. package/dist/carodaBidAdapter.js +1 -1
  38. package/dist/chromeAiRtdProvider.js +1 -0
  39. package/dist/chtnwBidAdapter.js +1 -1
  40. package/dist/chunk-core.js +1 -1
  41. package/dist/concertBidAdapter.js +1 -1
  42. package/dist/connectadBidAdapter.js +1 -1
  43. package/dist/consumableBidAdapter.js +1 -1
  44. package/dist/contxtfulBidAdapter.js +1 -1
  45. package/dist/conversantAnalyticsAdapter.js +1 -1
  46. package/dist/conversantBidAdapter.js +1 -1
  47. package/dist/craftBidAdapter.js +1 -1
  48. package/dist/criteoBidAdapter.js +1 -1
  49. package/dist/cwireBidAdapter.js +1 -1
  50. package/dist/dailymotionBidAdapter.js +1 -1
  51. package/dist/debugging-standalone.js +1 -1
  52. package/dist/dependencies.json +10 -2
  53. package/dist/dspxBidAdapter.js +1 -1
  54. package/dist/dxkultureBidAdapter.js +1 -1
  55. package/dist/eplanningBidAdapter.js +1 -1
  56. package/dist/equativBidAdapter.js +1 -1
  57. package/dist/eskimiBidAdapter.js +1 -1
  58. package/dist/euidIdSystem.js +1 -1
  59. package/dist/exadsBidAdapter.js +1 -1
  60. package/dist/excoBidAdapter.js +1 -1
  61. package/dist/fanAdapter.js +1 -1
  62. package/dist/feedadBidAdapter.js +1 -1
  63. package/dist/finativeBidAdapter.js +1 -1
  64. package/dist/freewheel-sspBidAdapter.js +1 -1
  65. package/dist/gmosspBidAdapter.js +1 -1
  66. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  67. package/dist/greenbidsBidAdapter.js +1 -1
  68. package/dist/greenbidsRtdProvider.js +1 -1
  69. package/dist/gridBidAdapter.js +1 -1
  70. package/dist/gumgumBidAdapter.js +1 -1
  71. package/dist/h12mediaBidAdapter.js +1 -1
  72. package/dist/hypelabBidAdapter.js +1 -1
  73. package/dist/id5AnalyticsAdapter.js +1 -1
  74. package/dist/id5IdSystem.js +1 -1
  75. package/dist/imdsBidAdapter.js +1 -1
  76. package/dist/improvedigitalBidAdapter.js +1 -1
  77. package/dist/inmobiBidAdapter.js +1 -1
  78. package/dist/insticatorBidAdapter.js +1 -1
  79. package/dist/intentIqAnalyticsAdapter.js +1 -1
  80. package/dist/ixBidAdapter.js +1 -1
  81. package/dist/jixieBidAdapter.js +1 -1
  82. package/dist/jixieIdSystem.js +1 -0
  83. package/dist/justpremiumBidAdapter.js +1 -1
  84. package/dist/kargoBidAdapter.js +1 -1
  85. package/dist/kimberliteBidAdapter.js +1 -1
  86. package/dist/konduitAnalyticsAdapter.js +1 -1
  87. package/dist/kueezBidAdapter.js +1 -1
  88. package/dist/lassoBidAdapter.js +1 -1
  89. package/dist/lifestreetBidAdapter.js +1 -1
  90. package/dist/liveIntentId.js +1 -1
  91. package/dist/logicadBidAdapter.js +1 -1
  92. package/dist/loglyliftBidAdapter.js +1 -1
  93. package/dist/luceadBidAdapter.js +1 -1
  94. package/dist/mabidderBidAdapter.js +1 -1
  95. package/dist/madsenseBidAdapter.js +1 -1
  96. package/dist/magniteAnalyticsAdapter.js +1 -1
  97. package/dist/malltvAnalyticsAdapter.js +1 -1
  98. package/dist/marsmediaBidAdapter.js +1 -1
  99. package/dist/mediafuseBidAdapter.js +1 -1
  100. package/dist/medianetBidAdapter.js +1 -1
  101. package/dist/medianetUtils.js +1 -1
  102. package/dist/mediasquareBidAdapter.js +1 -1
  103. package/dist/mgidBidAdapter.js +1 -1
  104. package/dist/missenaBidAdapter.js +1 -1
  105. package/dist/mobilefuseBidAdapter.js +1 -1
  106. package/dist/nextMillenniumBidAdapter.js +1 -1
  107. package/dist/nexx360Utils.js +1 -1
  108. package/dist/nobidAnalyticsAdapter.js +1 -1
  109. package/dist/nobidBidAdapter.js +1 -1
  110. package/dist/nodalsAiRtdProvider.js +1 -1
  111. package/dist/not-for-prod/prebid.js +175 -173
  112. package/dist/oguryBidAdapter.js +1 -1
  113. package/dist/onetagBidAdapter.js +1 -1
  114. package/dist/ooloAnalyticsAdapter.js +1 -1
  115. package/dist/openxBidAdapter.js +1 -1
  116. package/dist/optidigitalBidAdapter.js +1 -1
  117. package/dist/orbidderBidAdapter.js +1 -1
  118. package/dist/ortb2.5Translator.js +1 -1
  119. package/dist/outbrainBidAdapter.js +1 -1
  120. package/dist/ozoneBidAdapter.js +1 -1
  121. package/dist/pixfutureBidAdapter.js +1 -1
  122. package/dist/prebidServerBidAdapter.js +1 -1
  123. package/dist/publinkIdSystem.js +1 -1
  124. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  125. package/dist/pubmaticBidAdapter.js +1 -1
  126. package/dist/pubmaticRtdProvider.js +1 -1
  127. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  128. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  129. package/dist/pxyzBidAdapter.js +1 -1
  130. package/dist/quantcastBidAdapter.js +1 -1
  131. package/dist/readpeakBidAdapter.js +1 -1
  132. package/dist/relaidoBidAdapter.js +1 -1
  133. package/dist/relevatehealthBidAdapter.js +1 -1
  134. package/dist/retailspotBidAdapter.js +1 -1
  135. package/dist/rhythmoneBidAdapter.js +1 -1
  136. package/dist/riseUtils.js +1 -1
  137. package/dist/rubiconBidAdapter.js +1 -1
  138. package/dist/seedingAllianceBidAdapter.js +1 -1
  139. package/dist/seedtagBidAdapter.js +1 -1
  140. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  141. package/dist/sharethroughBidAdapter.js +1 -1
  142. package/dist/showheroes-bsBidAdapter.js +1 -1
  143. package/dist/smaatoBidAdapter.js +1 -1
  144. package/dist/smartadserverBidAdapter.js +1 -1
  145. package/dist/smartxBidAdapter.js +1 -1
  146. package/dist/smilewantedBidAdapter.js +1 -1
  147. package/dist/snigelBidAdapter.js +1 -1
  148. package/dist/sonobiBidAdapter.js +1 -1
  149. package/dist/sovrnBidAdapter.js +1 -1
  150. package/dist/sparteoBidAdapter.js +1 -1
  151. package/dist/sspBCBidAdapter.js +1 -1
  152. package/dist/stvBidAdapter.js +1 -1
  153. package/dist/sublimeBidAdapter.js +1 -1
  154. package/dist/taboolaBidAdapter.js +1 -1
  155. package/dist/tappxBidAdapter.js +1 -1
  156. package/dist/targetVideoBidAdapter.js +1 -1
  157. package/dist/teadsBidAdapter.js +1 -1
  158. package/dist/terceptAnalyticsAdapter.js +1 -1
  159. package/dist/themoneytizerBidAdapter.js +1 -1
  160. package/dist/trionBidAdapter.js +1 -1
  161. package/dist/tripleliftBidAdapter.js +1 -1
  162. package/dist/ttdBidAdapter.js +1 -1
  163. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  164. package/dist/uid2IdSystem.js +1 -1
  165. package/dist/underdogmediaBidAdapter.js +1 -1
  166. package/dist/undertoneBidAdapter.js +1 -1
  167. package/dist/unrulyBidAdapter.js +1 -1
  168. package/dist/userId.js +1 -1
  169. package/dist/vidazooUtils.js +1 -1
  170. package/dist/videobyteBidAdapter.js +1 -1
  171. package/dist/visxBidAdapter.js +1 -1
  172. package/dist/vuukleBidAdapter.js +1 -1
  173. package/dist/widespaceBidAdapter.js +1 -1
  174. package/dist/winrBidAdapter.js +1 -1
  175. package/dist/yahooAdsBidAdapter.js +1 -1
  176. package/dist/yandexBidAdapter.js +1 -1
  177. package/dist/yieldmoBidAdapter.js +1 -1
  178. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  179. package/gulpfile.js +12 -6
  180. package/integrationExamples/chromeai/japanese.html +224 -0
  181. package/integrationExamples/gpt/x-domain/creative.html +1 -1
  182. package/karma.conf.maker.js +7 -7
  183. package/karmaRunner.js +3 -3
  184. package/libraries/liveIntentId/shared.js +16 -0
  185. package/modules/.submodules.json +1 -0
  186. package/modules/aniviewBidAdapter.js +32 -23
  187. package/modules/chromeAiRtdProvider.js +421 -0
  188. package/modules/chromeAiRtdProvider.md +230 -0
  189. package/modules/fanAdapter.js +318 -124
  190. package/modules/ixBidAdapter.js +5 -0
  191. package/modules/jixieIdSystem.js +186 -0
  192. package/modules/ozoneBidAdapter.js +214 -336
  193. package/modules/prebidServerBidAdapter/index.js +59 -35
  194. package/modules/pubmaticRtdProvider.js +418 -4
  195. package/modules/pubmaticRtdProvider.md +12 -2
  196. package/modules/relevatehealthBidAdapter.js +20 -130
  197. package/modules/relevatehealthBidAdapter.md +1 -2
  198. package/modules/sovrnBidAdapter.js +4 -4
  199. package/modules/teadsBidAdapter.js +5 -0
  200. package/modules/ttdBidAdapter.js +5 -4
  201. package/modules/userId/index.js +30 -31
  202. package/package.json +5 -4
  203. package/src/adapterManager.js +3 -0
  204. package/test/spec/libraries/cmUtils_spec.js +17 -12
  205. package/test/spec/modules/aniviewBidAdapter_spec.js +15 -2
  206. package/test/spec/modules/chromeAiRtdProvider_spec.js +393 -0
  207. package/test/spec/modules/dgkeywordRtdProvider_spec.js +5 -2
  208. package/test/spec/modules/euidIdSystem_spec.js +9 -3
  209. package/test/spec/modules/fanAdapter_spec.js +264 -268
  210. package/test/spec/modules/id5IdSystem_spec.js +57 -101
  211. package/test/spec/modules/identityLinkIdSystem_spec.js +1 -0
  212. package/test/spec/modules/idxIdSystem_spec.js +2 -75
  213. package/test/spec/modules/instreamTracking_spec.js +15 -18
  214. package/test/spec/modules/ixBidAdapter_spec.js +26 -0
  215. package/test/spec/modules/jixieIdSystem_spec.js +303 -0
  216. package/test/spec/modules/liveIntentExternalIdSystem_spec.js +5 -0
  217. package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +5 -0
  218. package/test/spec/modules/liveIntentIdSystem_spec.js +38 -0
  219. package/test/spec/modules/lmpIdSystem_spec.js +2 -81
  220. package/test/spec/modules/ozoneBidAdapter_spec.js +511 -658
  221. package/test/spec/modules/prebidServerBidAdapter_spec.js +72 -2
  222. package/test/spec/modules/pubmaticBidAdapter_spec.js +411 -126
  223. package/test/spec/modules/pubmaticRtdProvider_spec.js +946 -2
  224. package/test/spec/modules/raynRtdProvider_spec.js +18 -22
  225. package/test/spec/modules/relevatehealthBidAdapter_spec.js +9 -39
  226. package/test/spec/modules/sharedIdSystem_spec.js +3 -3
  227. package/test/spec/modules/sovrnBidAdapter_spec.js +71 -3
  228. package/test/spec/modules/teadsBidAdapter_spec.js +9 -4
  229. package/test/spec/modules/ttdBidAdapter_spec.js +24 -2
  230. package/test/spec/modules/uid2IdSystem_helpers.js +5 -2
  231. package/test/spec/modules/userId_spec.js +142 -387
  232. package/test/spec/modules/yieldoneAnalyticsAdapter_spec.js +13 -12
  233. package/test/spec/modules/zeotapIdPlusIdSystem_spec.js +3 -69
  234. package/wdio.shared.conf.js +2 -2
  235. package/CLAUDE.md +0 -1
@@ -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);
@@ -1188,6 +1188,11 @@ function addFPD(bidderRequest, r, fpd, site, user) {
1188
1188
  if (ipv6) {
1189
1189
  deepSetValue(r, 'device.ipv6', ipv6);
1190
1190
  }
1191
+
1192
+ const geo = fpd.device.geo;
1193
+ if (geo) {
1194
+ deepSetValue(r, 'device.geo', geo);
1195
+ }
1191
1196
  }
1192
1197
 
1193
1198
  // regulations from ortb2
@@ -0,0 +1,186 @@
1
+ /**
2
+ * This module adds the jixie to the User ID module
3
+ * The {@link module:modules/userId} module is required
4
+ * @module modules/jixieIdSystem
5
+ * @requires module:modules/userId
6
+ */
7
+
8
+ import { submodule } from '../src/hook.js';
9
+ import { getStorageManager } from '../src/storageManager.js';
10
+ import { ajax } from '../src/ajax.js';
11
+ import { parseUrl, buildUrl, isPlainObject, timestamp } from '../src/utils.js';
12
+ import { MODULE_TYPE_UID } from '../src/activities/modules.js';
13
+
14
+ /**
15
+ * @typedef {import('../modules/userId/index.js').Submodule} Submodule
16
+ * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig
17
+ * @typedef {import('../modules/userId/index.js').ConsentData} ConsentData
18
+ * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse
19
+ */
20
+
21
+ const MODULE_NAME = 'jixieId';
22
+ const STD_JXID_KEY = '_jxx';
23
+ const PBJS_JXID_KEY = 'pbjx_jxx';
24
+ const PBJS_IDLOGSTR_KEY = 'pbjx_idlog';
25
+ const TRACKER_EP_FROM_IDMODULE = 'https://traid.jixie.io/api/usersyncpbjs'
26
+ const CK_LIFE_DAYS = 365;
27
+ const ONE_YEAR_IN_MS = 365 * 24 * 60 * 60 * 1000;
28
+
29
+ export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });
30
+
31
+ /**
32
+ * remove any property in obj that is null or undefined
33
+ * @param {*} obj
34
+ */
35
+ function removeNullProp(obj) {
36
+ for (const key in obj) {
37
+ if (obj[key] === null || obj[key] === undefined) {
38
+ delete obj[key];
39
+ }
40
+ }
41
+ }
42
+
43
+ /**
44
+ * save the info returned by our endpoint into cookie
45
+ * @param {object} response
46
+ */
47
+ function persistExtInfo(response) {
48
+ let o = response;
49
+ if (o) {
50
+ const ageMS = (CK_LIFE_DAYS) * 24 * 60 * 60 * 1000;
51
+ const expireDT = new Date(timestamp() + ageMS).toUTCString();
52
+ if (o.client_id) {
53
+ storage.setCookie(PBJS_JXID_KEY, o.client_id, expireDT);
54
+ }
55
+ if (o.idlog) {
56
+ storage.setCookie(PBJS_IDLOGSTR_KEY, o.idlog, expireDT);
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * build the full url to call the jixie endpoint
63
+ * @param {Object} params - config params from the pbjs setup
64
+ * @param {Object} gdprConsent
65
+ * @returns {string} a full url to call by ajax
66
+ */
67
+ function buildIdCallUrl(params, gdprConsent) {
68
+ let url = parseUrl(params.idendpoint || TRACKER_EP_FROM_IDMODULE);
69
+
70
+ if (gdprConsent) {
71
+ url.search.gdpr_consent = gdprConsent && gdprConsent.gdprApplies ? gdprConsent.consentString : '';
72
+ }
73
+ if (params) {
74
+ if (params.accountid) { url.search.accountid = params.accountid; }
75
+ url.search.client_id = storage.getCookie(PBJS_JXID_KEY);
76
+ url.search.idlog = storage.getCookie(PBJS_IDLOGSTR_KEY);
77
+ if (Array.isArray(params.pubExtIds)) {
78
+ params.pubExtIds.forEach((extId) => {
79
+ if (extId.ckname) {
80
+ url.search[extId.pname] = storage.getCookie(extId.ckname);
81
+ } else if (extId.lsname) {
82
+ url.search[extId.pname] = storage.getDataFromLocalStorage(extId.lsname);
83
+ }
84
+ });
85
+ }
86
+ }
87
+ removeNullProp(url.search);
88
+ return buildUrl(url);
89
+ }
90
+
91
+ /**
92
+ * just to check if the page has jixie publisher script planted
93
+ * @returns {boolean}
94
+ */
95
+ function pgHasJxEvtScript() {
96
+ return ((window && window.jixie_o));
97
+ }
98
+
99
+ /**
100
+ * analyze the log string from the server side to see if it is now time to
101
+ * call the server again
102
+ * @param {*} logstr a formatted string
103
+ * @return {boolean}
104
+ */
105
+ function shouldCallSrv(logstr) {
106
+ if (!logstr) return true;
107
+ let now = Date.now();
108
+ let tsStr = logstr.split('_')[0];
109
+ let ts = parseInt(tsStr, 10);
110
+ if (!(tsStr.length == 13 && ts && ts >= (now - ONE_YEAR_IN_MS) && ts <= (now + ONE_YEAR_IN_MS))) {
111
+ ts = undefined;
112
+ }
113
+ return (ts === undefined || (ts && now > ts));
114
+ }
115
+
116
+ /** @type {Submodule} */
117
+ export const jixieIdSubmodule = {
118
+ /**
119
+ * used to link submodule with config
120
+ * @type {string}
121
+ */
122
+ name: MODULE_NAME,
123
+ /**
124
+ * decode the stored id value for passing to bid requests
125
+ * @function
126
+ * @param {string} value
127
+ * @returns {{jixieId: string} | undefined}
128
+ */
129
+ decode(value) {
130
+ return (value != null && value.length > 0 ? { jixieId: value } : undefined);
131
+ },
132
+ /**
133
+ * performs action to obtain id
134
+ * Use a publink cookie first if it is present, otherwise use prebids copy, if neither are available callout to get a new id
135
+ * @function
136
+ * @param {SubmoduleConfig} [config] Config object with params and storage properties
137
+ * @param {ConsentData|undefined} gdprConsent GDPR consent
138
+ * @returns {IdResponse}
139
+ */
140
+ getId(config, gdprConsent) {
141
+ if (!isPlainObject(config.params)) {
142
+ config.params = {};
143
+ }
144
+ const options = { method: 'GET', withCredentials: true };
145
+ const resp = function(callback) {
146
+ let jxId;
147
+ // If page has jixie script we use the standard jixie id cookie
148
+ if (pgHasJxEvtScript()) {
149
+ jxId = storage.getCookie(config.params.stdjxidckname || STD_JXID_KEY);
150
+ callback(jxId || null);
151
+ return;
152
+ }
153
+ // Case of no jixie script runs on this site:
154
+ jxId = storage.getCookie(PBJS_JXID_KEY);
155
+ let idLogStr = storage.getCookie(PBJS_IDLOGSTR_KEY);
156
+ if (jxId && !shouldCallSrv(idLogStr)) {
157
+ callback(jxId);
158
+ } else {
159
+ let handleResponse = function(responseText, xhr) {
160
+ if (xhr.status === 200) {
161
+ let response = JSON.parse(responseText);
162
+ if (response && response.data && response.data.success) {
163
+ response = response.data
164
+ persistExtInfo(response);
165
+ callback(response.client_id);
166
+ if (response.telcoep) {
167
+ ajax(response.telcoep, undefined, undefined, options);
168
+ }
169
+ }
170
+ }
171
+ };
172
+ ajax(
173
+ buildIdCallUrl(config.params, gdprConsent && gdprConsent.gdpr ? gdprConsent.gdpr : null), handleResponse, undefined, options
174
+ );
175
+ }
176
+ };
177
+ return { callback: resp };
178
+ },
179
+ eids: {
180
+ 'jixieId': {
181
+ source: 'jixie.io',
182
+ atype: 3
183
+ },
184
+ },
185
+ };
186
+ submodule('userId', jixieIdSubmodule);