prebid.js 7.3.0 → 7.6.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 (225) hide show
  1. package/.circleci/config.yml +11 -6
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/adagioBidAdapter.js +1 -1
  4. package/dist/adbookpspBidAdapter.js +1 -1
  5. package/dist/adgenerationBidAdapter.js +1 -1
  6. package/dist/adnuntiusBidAdapter.js +1 -1
  7. package/dist/adotBidAdapter.js +1 -1
  8. package/dist/adpod.js +1 -1
  9. package/dist/adrelevantisBidAdapter.js +1 -1
  10. package/dist/adrinoBidAdapter.js +1 -1
  11. package/dist/adtelligentBidAdapter.js +1 -1
  12. package/dist/adxcgBidAdapter.js +1 -1
  13. package/dist/ajaBidAdapter.js +1 -1
  14. package/dist/amxBidAdapter.js +1 -1
  15. package/dist/amxIdSystem.js +1 -1
  16. package/dist/appierAnalyticsAdapter.js +1 -1
  17. package/dist/appnexusBidAdapter.js +1 -1
  18. package/dist/asoBidAdapter.js +1 -1
  19. package/dist/atsAnalyticsAdapter.js +1 -1
  20. package/dist/axonixBidAdapter.js +1 -1
  21. package/dist/bidglassBidAdapter.js +1 -1
  22. package/dist/big-richmediaBidAdapter.js +1 -1
  23. package/dist/bridgewellBidAdapter.js +1 -1
  24. package/dist/brightMountainMediaBidAdapter.js +1 -1
  25. package/dist/byDataAnalyticsAdapter.js +1 -1
  26. package/dist/concertBidAdapter.js +1 -1
  27. package/dist/connectadBidAdapter.js +1 -1
  28. package/dist/consumableBidAdapter.js +1 -1
  29. package/dist/conversantBidAdapter.js +1 -1
  30. package/dist/craftBidAdapter.js +1 -1
  31. package/dist/criteoBidAdapter.js +1 -1
  32. package/dist/debugging-standalone.js +1 -1
  33. package/dist/debugging.js +1 -1
  34. package/dist/dspxBidAdapter.js +1 -1
  35. package/dist/eplanningBidAdapter.js +1 -1
  36. package/dist/finativeBidAdapter.js +1 -1
  37. package/dist/gdprEnforcement.js +1 -1
  38. package/dist/glimpseBidAdapter.js +1 -1
  39. package/dist/gmosspBidAdapter.js +1 -1
  40. package/dist/goldbachBidAdapter.js +1 -1
  41. package/dist/gridBidAdapter.js +1 -1
  42. package/dist/gridNMBidAdapter.js +1 -1
  43. package/dist/gumgumBidAdapter.js +1 -1
  44. package/dist/h12mediaBidAdapter.js +1 -1
  45. package/dist/hadronIdSystem.js +1 -1
  46. package/dist/hadronRtdProvider.js +1 -1
  47. package/dist/id5IdSystem.js +1 -1
  48. package/dist/imRtdProvider.js +1 -1
  49. package/dist/improvedigitalBidAdapter.js +1 -1
  50. package/dist/inmarBidAdapter.js +1 -1
  51. package/dist/insticatorBidAdapter.js +1 -1
  52. package/dist/ixBidAdapter.js +1 -1
  53. package/dist/justpremiumBidAdapter.js +1 -1
  54. package/dist/kargoAnalyticsAdapter.js +1 -1
  55. package/dist/kargoBidAdapter.js +1 -1
  56. package/dist/konduitAnalyticsAdapter.js +1 -1
  57. package/dist/kueezBidAdapter.js +1 -1
  58. package/dist/lassoBidAdapter.js +1 -1
  59. package/dist/liveyieldAnalyticsAdapter.js +1 -1
  60. package/dist/logicadBidAdapter.js +1 -1
  61. package/dist/loglyliftBidAdapter.js +1 -1
  62. package/dist/malltvAnalyticsAdapter.js +1 -1
  63. package/dist/marsmediaBidAdapter.js +1 -1
  64. package/dist/mediafuseBidAdapter.js +1 -1
  65. package/dist/mediasquareBidAdapter.js +1 -1
  66. package/dist/mgidBidAdapter.js +1 -1
  67. package/dist/minutemediaBidAdapter.js +1 -1
  68. package/dist/missenaBidAdapter.js +1 -1
  69. package/dist/newspassidBidAdapter.js +1 -0
  70. package/dist/nextMillenniumBidAdapter.js +1 -1
  71. package/dist/not-for-prod/prebid.js +131 -127
  72. package/dist/oguryBidAdapter.js +1 -1
  73. package/dist/onetagBidAdapter.js +1 -1
  74. package/dist/ooloAnalyticsAdapter.js +1 -1
  75. package/dist/openxOrtbBidAdapter.js +1 -0
  76. package/dist/outbrainBidAdapter.js +1 -1
  77. package/dist/parrableIdSystem.js +1 -1
  78. package/dist/pixfutureBidAdapter.js +1 -1
  79. package/dist/prebid-core.js +2 -2
  80. package/dist/priceFloors.js +1 -1
  81. package/dist/pubCommonId.js +1 -1
  82. package/dist/publinkIdSystem.js +1 -1
  83. package/dist/pubmaticBidAdapter.js +1 -1
  84. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  85. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  86. package/dist/pxyzBidAdapter.js +1 -1
  87. package/dist/quantcastBidAdapter.js +1 -1
  88. package/dist/rasBidAdapter.js +1 -0
  89. package/dist/readpeakBidAdapter.js +1 -1
  90. package/dist/relaidoBidAdapter.js +1 -1
  91. package/dist/rhythmoneBidAdapter.js +1 -1
  92. package/dist/riseBidAdapter.js +1 -1
  93. package/dist/rubiconAnalyticsAdapter.js +1 -1
  94. package/dist/rubiconBidAdapter.js +1 -1
  95. package/dist/seedingAllianceBidAdapter.js +1 -1
  96. package/dist/seedtagBidAdapter.js +1 -1
  97. package/dist/sharedIdSystem.js +1 -1
  98. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  99. package/dist/sharethroughBidAdapter.js +1 -1
  100. package/dist/shinezBidAdapter.js +1 -0
  101. package/dist/sizeMappingV2.js +1 -1
  102. package/dist/smaatoBidAdapter.js +1 -1
  103. package/dist/smartadserverBidAdapter.js +1 -1
  104. package/dist/smartxBidAdapter.js +1 -1
  105. package/dist/smilewantedBidAdapter.js +1 -1
  106. package/dist/sonobiBidAdapter.js +1 -1
  107. package/dist/sovrnAnalyticsAdapter.js +1 -1
  108. package/dist/sovrnBidAdapter.js +1 -1
  109. package/dist/sspBCBidAdapter.js +1 -1
  110. package/dist/sublimeBidAdapter.js +1 -1
  111. package/dist/synacormediaBidAdapter.js +1 -1
  112. package/dist/taboolaBidAdapter.js +1 -1
  113. package/dist/targetVideoBidAdapter.js +1 -1
  114. package/dist/teadsBidAdapter.js +1 -1
  115. package/dist/trionBidAdapter.js +1 -1
  116. package/dist/tripleliftBidAdapter.js +1 -1
  117. package/dist/ttdBidAdapter.js +1 -1
  118. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  119. package/dist/underdogmediaBidAdapter.js +1 -1
  120. package/dist/undertoneBidAdapter.js +1 -1
  121. package/dist/ventesBidAdapter.js +1 -1
  122. package/dist/vidazooBidAdapter.js +1 -1
  123. package/dist/videobyteBidAdapter.js +1 -1
  124. package/dist/visxBidAdapter.js +1 -1
  125. package/dist/vrtcalBidAdapter.js +1 -1
  126. package/dist/vuukleBidAdapter.js +1 -1
  127. package/dist/widespaceBidAdapter.js +1 -1
  128. package/dist/winrBidAdapter.js +1 -1
  129. package/dist/yahoosspBidAdapter.js +1 -1
  130. package/dist/yieldmoBidAdapter.js +1 -1
  131. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  132. package/gulpfile.js +1 -1
  133. package/karma.conf.maker.js +3 -1
  134. package/modules/adgenerationBidAdapter.js +24 -1
  135. package/modules/adnuntiusBidAdapter.js +26 -8
  136. package/modules/adotBidAdapter.js +13 -4
  137. package/modules/adrinoBidAdapter.js +10 -2
  138. package/modules/adrinoBidAdapter.md +6 -0
  139. package/modules/adtelligentBidAdapter.js +2 -1
  140. package/modules/appnexusBidAdapter.js +3 -3
  141. package/modules/atsAnalyticsAdapter.js +4 -5
  142. package/modules/byDataAnalyticsAdapter.js +172 -74
  143. package/modules/byDataAnalyticsAdapter.md +5 -6
  144. package/modules/consumableBidAdapter.js +12 -1
  145. package/modules/criteoBidAdapter.js +7 -1
  146. package/modules/cwireBidAdapter.md +1 -1
  147. package/modules/debugging/bidInterceptor.js +1 -1
  148. package/modules/debugging/index.js +2 -1
  149. package/modules/eplanningBidAdapter.js +82 -97
  150. package/modules/gdprEnforcement.js +8 -14
  151. package/modules/gridNMBidAdapter.js +45 -4
  152. package/modules/hadronAnalyticsAdapter.md +5 -5
  153. package/modules/hadronIdSystem.js +18 -5
  154. package/modules/hadronIdSystem.md +15 -11
  155. package/modules/hadronRtdProvider.js +14 -1
  156. package/modules/hadronRtdProvider.md +17 -13
  157. package/modules/imRtdProvider.js +0 -8
  158. package/modules/insticatorBidAdapter.js +9 -0
  159. package/modules/ixBidAdapter.js +462 -58
  160. package/modules/ixBidAdapter.md +95 -5
  161. package/modules/kargoAnalyticsAdapter.js +88 -6
  162. package/modules/kargoAnalyticsAdapter.md +33 -0
  163. package/modules/kargoBidAdapter.js +1 -2
  164. package/modules/minutemediaBidAdapter.js +1 -0
  165. package/modules/missenaBidAdapter.js +20 -2
  166. package/modules/newspassidBidAdapter.js +649 -0
  167. package/modules/nextMillenniumBidAdapter.js +17 -1
  168. package/modules/oguryBidAdapter.js +2 -0
  169. package/modules/openxBidAdapter.md +3 -1
  170. package/modules/openxOrtbBidAdapter.js +349 -0
  171. package/modules/openxOrtbBidAdapter.md +105 -0
  172. package/modules/priceFloors.js +1 -1
  173. package/modules/pubCommonId.js +1 -2
  174. package/modules/pubxaiAnalyticsAdapter.js +6 -1
  175. package/modules/rasBidAdapter.js +149 -0
  176. package/modules/rasBidAdapter.md +50 -0
  177. package/modules/readpeakBidAdapter.js +15 -6
  178. package/modules/relaidoBidAdapter.js +19 -4
  179. package/modules/seedtagBidAdapter.js +37 -1
  180. package/modules/sharedIdSystem.js +11 -5
  181. package/modules/sharethroughBidAdapter.js +9 -24
  182. package/modules/shinezBidAdapter.js +435 -0
  183. package/modules/shinezBidAdapter.md +76 -0
  184. package/modules/taboolaBidAdapter.js +1 -1
  185. package/modules/taboolaBidAdapter.md +3 -3
  186. package/modules/ventesBidAdapter.js +1 -1
  187. package/modules/ventesBidAdapter.md +1 -1
  188. package/modules/vrtcalBidAdapter.js +35 -0
  189. package/package.json +1 -1
  190. package/plugins/pbjsGlobals.js +2 -1
  191. package/src/storageManager.js +4 -5
  192. package/test/spec/modules/adgenerationBidAdapter_spec.js +52 -4
  193. package/test/spec/modules/adnuntiusBidAdapter_spec.js +126 -14
  194. package/test/spec/modules/adotBidAdapter_spec.js +12 -9
  195. package/test/spec/modules/adrinoBidAdapter_spec.js +22 -0
  196. package/test/spec/modules/appnexusBidAdapter_spec.js +165 -156
  197. package/test/spec/modules/byDataAnalyticsAdapter_spec.js +74 -24
  198. package/test/spec/modules/consumableBidAdapter_spec.js +75 -0
  199. package/test/spec/modules/criteoBidAdapter_spec.js +15 -5
  200. package/test/spec/modules/debugging_mod_spec.js +7 -0
  201. package/test/spec/modules/eplanningBidAdapter_spec.js +58 -18
  202. package/test/spec/modules/gdprEnforcement_spec.js +53 -100
  203. package/test/spec/modules/gridNMBidAdapter_spec.js +32 -0
  204. package/test/spec/modules/hadronIdSystem_spec.js +2 -2
  205. package/test/spec/modules/imRtdProvider_spec.js +0 -1
  206. package/test/spec/modules/insticatorBidAdapter_spec.js +22 -1
  207. package/test/spec/modules/ixBidAdapter_spec.js +470 -10
  208. package/test/spec/modules/kargoAnalyticsAdapter_spec.js +42 -0
  209. package/test/spec/modules/kargoBidAdapter_spec.js +1 -0
  210. package/test/spec/modules/minutemediaBidAdapter_spec.js +3 -0
  211. package/test/spec/modules/missenaBidAdapter_spec.js +36 -14
  212. package/test/spec/modules/newspassidBidAdapter_spec.js +1793 -0
  213. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +20 -0
  214. package/test/spec/modules/openxOrtbBidAdapter_spec.js +1303 -0
  215. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +5 -0
  216. package/test/spec/modules/rasBidAdapter_spec.js +190 -0
  217. package/test/spec/modules/readpeakBidAdapter_spec.js +1 -0
  218. package/test/spec/modules/relaidoBidAdapter_spec.js +29 -2
  219. package/test/spec/modules/seedtagBidAdapter_spec.js +29 -0
  220. package/test/spec/modules/sharethroughBidAdapter_spec.js +4 -4
  221. package/test/spec/modules/shinezBidAdapter_spec.js +479 -0
  222. package/test/spec/modules/taboolaBidAdapter_spec.js +1 -1
  223. package/test/spec/modules/ventesBidAdapter_spec.js +2 -2
  224. package/test/spec/modules/vrtcalBidAdapter_spec.js +17 -0
  225. package/webpack.conf.js +1 -1
@@ -17,12 +17,12 @@ import {
17
17
  parseGPTSingleSizeArray,
18
18
  parseQueryStringParameters
19
19
  } from '../src/utils.js';
20
- import {BANNER, VIDEO} from '../src/mediaTypes.js';
20
+ import {BANNER, VIDEO, NATIVE} from '../src/mediaTypes.js';
21
21
  import {config} from '../src/config.js';
22
22
  import CONSTANTS from '../src/constants.json';
23
23
  import {getStorageManager, validateStorageEnforcement} from '../src/storageManager.js';
24
24
  import * as events from '../src/events.js';
25
- import {find, includes} from '../src/polyfill.js';
25
+ import {find} from '../src/polyfill.js';
26
26
  import {registerBidder} from '../src/adapters/bidderFactory.js';
27
27
  import {INSTREAM, OUTSTREAM} from '../src/video.js';
28
28
  import {Renderer} from '../src/Renderer.js';
@@ -30,14 +30,14 @@ import {Renderer} from '../src/Renderer.js';
30
30
  const BIDDER_CODE = 'ix';
31
31
  const ALIAS_BIDDER_CODE = 'roundel';
32
32
  const GLOBAL_VENDOR_ID = 10;
33
- const MODULE_TYPE = 'bid-adapter';
34
33
  const SECURE_BID_URL = 'https://htlb.casalemedia.com/openrtb/pbjs';
35
- const SUPPORTED_AD_TYPES = [BANNER, VIDEO];
34
+ const SUPPORTED_AD_TYPES = [BANNER, VIDEO, NATIVE];
36
35
  const BANNER_ENDPOINT_VERSION = 7.2;
37
36
  const VIDEO_ENDPOINT_VERSION = 8.1;
38
37
  const CENT_TO_DOLLAR_FACTOR = 100;
39
38
  const BANNER_TIME_TO_LIVE = 300;
40
39
  const VIDEO_TIME_TO_LIVE = 3600; // 1hr
40
+ const NATIVE_TIME_TO_LIVE = 3600; // Since native can have video, use ttl same as video
41
41
  const NET_REVENUE = true;
42
42
  const MAX_REQUEST_SIZE = 8000;
43
43
  const MAX_REQUEST_LIMIT = 4;
@@ -45,9 +45,9 @@ const OUTSTREAM_MINIMUM_PLAYER_SIZE = [144, 144];
45
45
  const PRICE_TO_DOLLAR_FACTOR = {
46
46
  JPY: 1
47
47
  };
48
- const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
49
-
48
+ const IFRAME_USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
50
49
  const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' };
50
+ const IMG_USER_SYNC_URL = 'https://dsum.casalemedia.com/pbusermatch?origin=prebid'
51
51
  export const ERROR_CODES = {
52
52
  BID_SIZE_INVALID_FORMAT: 1,
53
53
  BID_SIZE_NOT_INCLUDED: 2,
@@ -100,9 +100,99 @@ const VIDEO_PARAMS_ALLOW_LIST = [
100
100
  'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext',
101
101
  'playerSize', 'w', 'h'
102
102
  ];
103
+ const NATIVE_ASSET_TYPES = {
104
+ TITLE: 100,
105
+ IMG: 200,
106
+ VIDEO: 300,
107
+ DATA: 400
108
+ };
109
+ const NATIVE_IMAGE_TYPES = {
110
+ ICON: 1,
111
+ MAIN: 3
112
+ };
113
+ const NATIVE_DATA_TYPES = {
114
+ SPONSORED: 1,
115
+ DESC: 2,
116
+ RATING: 3,
117
+ LIKES: 4,
118
+ DOWNLOADS: 5,
119
+ PRICE: 6,
120
+ SALEPRICE: 7,
121
+ PHONE: 8,
122
+ ADDRESS: 9,
123
+ DESC2: 10,
124
+ DISPLAYURL: 11,
125
+ CTATEXT: 12
126
+ };
127
+ const NATIVE_DATA_MAP = {
128
+ [NATIVE_DATA_TYPES.SPONSORED]: 'sponsoredBy',
129
+ [NATIVE_DATA_TYPES.DESC]: 'body',
130
+ [NATIVE_DATA_TYPES.RATING]: 'rating',
131
+ [NATIVE_DATA_TYPES.LIKES]: 'likes',
132
+ [NATIVE_DATA_TYPES.DOWNLOADS]: 'downloads',
133
+ [NATIVE_DATA_TYPES.PRICE]: 'price',
134
+ [NATIVE_DATA_TYPES.SALEPRICE]: 'salePrice',
135
+ [NATIVE_DATA_TYPES.PHONE]: 'phone',
136
+ [NATIVE_DATA_TYPES.ADDRESS]: 'address',
137
+ [NATIVE_DATA_TYPES.DESC2]: 'body2',
138
+ [NATIVE_DATA_TYPES.DISPLAYURL]: 'displayUrl',
139
+ [NATIVE_DATA_TYPES.CTATEXT]: 'cta'
140
+ };
141
+ const NATIVE_ASSETS_MAP = {
142
+ 'title': { assetType: NATIVE_ASSET_TYPES.TITLE },
143
+ 'icon': { assetType: NATIVE_ASSET_TYPES.IMG, subtype: NATIVE_IMAGE_TYPES.ICON },
144
+ 'image': { assetType: NATIVE_ASSET_TYPES.IMG, subtype: NATIVE_IMAGE_TYPES.MAIN },
145
+ 'sponsoredBy': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.SPONSORED },
146
+ 'body': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DESC },
147
+ 'rating': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.RATING },
148
+ 'likes': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.LIKES },
149
+ 'downloads': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DOWNLOADS },
150
+ 'price': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.PRICE },
151
+ 'salePrice': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.SALEPRICE },
152
+ 'phone': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.PHONE },
153
+ 'address': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.ADDRESS },
154
+ 'body2': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DESC2 },
155
+ 'displayUrl': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.DISPLAYURL },
156
+ 'cta': { assetType: NATIVE_ASSET_TYPES.DATA, subtype: NATIVE_DATA_TYPES.CTATEXT },
157
+ 'video': { assetType: NATIVE_ASSET_TYPES.VIDEO }
158
+ };
159
+ const NATIVE_ALLOWED_PROPERTIES = [
160
+ 'rendererUrl',
161
+ 'sendTargetingKeys',
162
+ 'adTemplate',
163
+ 'type',
164
+ 'ext',
165
+ 'privacyLink',
166
+ 'clickUrl',
167
+ 'privacyIcon'
168
+ ];
169
+ const NATIVE_ASSET_DEFAULT = {
170
+ TITLE: {
171
+ LEN: 25
172
+ },
173
+ VIDEO: {
174
+ MIMES: [
175
+ 'video/mp4',
176
+ 'video/webm'
177
+ ],
178
+ MINDURATION: 0,
179
+ MAXDURATION: 120,
180
+ PROTOCOLS: [2, 3, 5, 6],
181
+ }
182
+ };
183
+ const NATIVE_EVENT_TYPES = {
184
+ IMRESSION: 1
185
+ };
186
+ const NATIVE_EVENT_TRACKING_METHOD = {
187
+ IMG: 1,
188
+ JS: 2
189
+ };
103
190
  const LOCAL_STORAGE_KEY = 'ixdiag';
104
191
  let hasRegisteredHandler = false;
105
192
  export const storage = getStorageManager({gvlid: GLOBAL_VENDOR_ID, bidderCode: BIDDER_CODE});
193
+ let siteID = 0;
194
+ let gdprConsent = '';
195
+ let usPrivacy = '';
106
196
 
107
197
  // Possible values for bidResponse.seatBid[].bid[].mtype which indicates the type of the creative markup so that it can properly be associated with the right sub-object of the BidRequest.Imp.
108
198
  const MEDIA_TYPES = {
@@ -110,7 +200,7 @@ const MEDIA_TYPES = {
110
200
  Video: 2,
111
201
  Audio: 3,
112
202
  Native: 4
113
- }
203
+ };
114
204
 
115
205
  /**
116
206
  * Transform valid bid request config object to banner impression object that will be sent to ad server.
@@ -197,7 +287,7 @@ function bidToVideoImp(bid) {
197
287
  imp.ext.sid = parseGPTSingleSizeArray(impSize);
198
288
  }
199
289
  } else {
200
- logWarn('IX Bid Adapter: Video size is missing in [mediaTypes.video] missing');
290
+ logWarn('IX Bid Adapter: Video size is missing in [mediaTypes.video]');
201
291
  return {};
202
292
  }
203
293
  }
@@ -207,6 +297,143 @@ function bidToVideoImp(bid) {
207
297
  return imp;
208
298
  }
209
299
 
300
+ /**
301
+ * Transform valid bid request config object to native impression object that will be sent to ad server.
302
+ *
303
+ * @param {object} bid A valid bid request config object.
304
+ * @return {object} A impression object that will be sent to ad server.
305
+ */
306
+ function bidToNativeImp(bid) {
307
+ const imp = bidToImp(bid);
308
+ const nativeAdUnitRef = deepAccess(bid, 'mediaTypes.native');
309
+
310
+ const assets = []
311
+
312
+ // Convert all native assets to imp object
313
+ for (const [adUnitProperty, adUnitValues] of Object.entries(nativeAdUnitRef)) {
314
+ if (!NATIVE_ASSETS_MAP[adUnitProperty]) {
315
+ continue;
316
+ }
317
+
318
+ const { assetType, subtype } = NATIVE_ASSETS_MAP[adUnitProperty];
319
+ let asset;
320
+ switch (assetType) {
321
+ case NATIVE_ASSET_TYPES.TITLE:
322
+ asset = createNativeTitleRequest(adUnitValues);
323
+ break;
324
+ case NATIVE_ASSET_TYPES.IMG:
325
+ asset = createNativeImgRequest(adUnitValues, subtype);
326
+ break;
327
+ case NATIVE_ASSET_TYPES.VIDEO:
328
+ asset = createNativeVideoRequest(adUnitValues);
329
+ break;
330
+ case NATIVE_ASSET_TYPES.DATA:
331
+ asset = createNativeDataRequest(adUnitValues, subtype);
332
+ break;
333
+ }
334
+ asset.id = assetType + (subtype || 0);
335
+ assets.push(asset);
336
+ }
337
+
338
+ if (assets.length === 0) {
339
+ logWarn('IX Bid Adapter: Native bid does not contain recognised assets in [mediaTypes.native]');
340
+ return {};
341
+ }
342
+
343
+ const request = {
344
+ assets: assets,
345
+ ver: '1.2',
346
+ eventtrackers: [{
347
+ event: 1,
348
+ methods: [1, 2]
349
+ }],
350
+ privacy: 1
351
+ }
352
+
353
+ imp.native = {
354
+ request: JSON.stringify(request),
355
+ ver: '1.2'
356
+ };
357
+
358
+ _applyFloor(bid, imp, NATIVE);
359
+
360
+ return imp;
361
+ }
362
+
363
+ /**
364
+ * Converts native bid asset to a native impression asset
365
+ * @param {object} bidAsset PBJS bid asset object
366
+ * @returns {object} IX impression asset object
367
+ */
368
+ function createNativeTitleRequest(bidAsset) {
369
+ return {
370
+ required: bidAsset.required ? 1 : 0,
371
+ title: {
372
+ len: bidAsset.len ? bidAsset.len : NATIVE_ASSET_DEFAULT.TITLE.LEN,
373
+ ext: bidAsset.ext
374
+ }
375
+ }
376
+ }
377
+
378
+ /**
379
+ * Converts native bid asset to a native impression asset
380
+ * @param {object} bidAsset PBJS bid asset object
381
+ * @param {int} type The image type
382
+ * @returns {object} IX impression asset object
383
+ */
384
+ function createNativeImgRequest(bidAsset, type) {
385
+ let asset = {
386
+ required: bidAsset.required ? 1 : 0,
387
+ img: {
388
+ type: type,
389
+ mimes: bidAsset.mimes,
390
+ ext: bidAsset.ext
391
+ }
392
+ }
393
+
394
+ if (bidAsset.hasOwnProperty('sizes') && bidAsset.sizes.length === 2) {
395
+ asset.img.wmin = bidAsset.sizes[0];
396
+ asset.img.hmin = bidAsset.sizes[1];
397
+ }
398
+
399
+ return asset
400
+ }
401
+
402
+ /**
403
+ * Converts native bid asset to a native impression asset
404
+ * @param {object} bidAsset PBJS bid asset object
405
+ * @returns {object} IX impression asset object
406
+ */
407
+ function createNativeVideoRequest(bidAsset) {
408
+ return {
409
+ required: bidAsset.required ? 1 : 0,
410
+ video: {
411
+ mimes: bidAsset.mimes ? bidAsset.mimes : NATIVE_ASSET_DEFAULT.VIDEO.MIMES,
412
+ minduration: bidAsset.minduration ? bidAsset.minduration : NATIVE_ASSET_DEFAULT.VIDEO.MINDURATION,
413
+ maxduration: bidAsset.maxduration ? bidAsset.maxduration : NATIVE_ASSET_DEFAULT.VIDEO.MAXDURATION,
414
+ protocols: bidAsset.protocols ? bidAsset.protocols : NATIVE_ASSET_DEFAULT.VIDEO.PROTOCOLS,
415
+ ext: bidAsset.ext
416
+ }
417
+ }
418
+ }
419
+
420
+ /**
421
+ * Converts native bid asset to a native impression asset
422
+ * @param {object} bidAsset PBJS bid asset object
423
+ * @param {int} type The image type
424
+ * @returns {object} IX impression asset object
425
+ */
426
+ function createNativeDataRequest(bidAsset, type) {
427
+ return {
428
+ required: bidAsset.required ? 1 : 0,
429
+ data: {
430
+ type: type,
431
+ len: bidAsset.len,
432
+ ext: bidAsset.ext
433
+ }
434
+ }
435
+ }
436
+
210
437
  /**
211
438
  * Converts an incoming PBJS bid to an IX Impression
212
439
  * @param {object} bid PBJS bid object
@@ -309,6 +536,16 @@ function parseBid(rawBid, currency, bidRequest) {
309
536
  bid.vastUrl = rawBid.ext.vasturl
310
537
  }
311
538
 
539
+ let parsedAdm = null;
540
+ // Detect whether the adm is (probably) JSON
541
+ if (typeof rawBid.adm === 'string' && rawBid.adm[0] === '{' && rawBid.adm[rawBid.adm.length - 1] === '}') {
542
+ try {
543
+ parsedAdm = JSON.parse(rawBid.adm);
544
+ } catch (err) {
545
+ logWarn('adm looks like JSON but failed to parse: ', err);
546
+ }
547
+ }
548
+
312
549
  // in the event of a video
313
550
  if ((rawBid.ext && rawBid.ext.vasturl) || rawBid.mtype == MEDIA_TYPES.Video) {
314
551
  bid.width = bidRequest.video.w;
@@ -316,6 +553,12 @@ function parseBid(rawBid, currency, bidRequest) {
316
553
  bid.mediaType = VIDEO;
317
554
  bid.mediaTypes = bidRequest.mediaTypes;
318
555
  bid.ttl = isValidExpiry ? rawBid.exp : VIDEO_TIME_TO_LIVE;
556
+ } else if (parsedAdm && parsedAdm.native) {
557
+ bid.native = interpretNativeAdm(parsedAdm.native)
558
+ bid.width = rawBid.w ? rawBid.w : 1;
559
+ bid.height = rawBid.h ? rawBid.h : 1;
560
+ bid.mediaType = NATIVE;
561
+ bid.ttl = isValidExpiry ? rawBid.exp : NATIVE_TIME_TO_LIVE;
319
562
  } else {
320
563
  bid.ad = rawBid.adm;
321
564
  bid.width = rawBid.w;
@@ -335,6 +578,84 @@ function parseBid(rawBid, currency, bidRequest) {
335
578
  return bid;
336
579
  }
337
580
 
581
+ /**
582
+ * Parse native adm and set native asset key names recognized by Prebid.js
583
+ * @param {string} adm Native adm complience
584
+ */
585
+ function interpretNativeAdm(nativeResponse) {
586
+ const native = {
587
+ clickUrl: nativeResponse.link.url,
588
+ privacyLink: nativeResponse.privacy
589
+ };
590
+
591
+ for (const asset of nativeResponse.assets) {
592
+ const subtype = asset.id % 100;
593
+ const assetType = asset.id - subtype;
594
+
595
+ switch (assetType) {
596
+ case NATIVE_ASSET_TYPES.TITLE:
597
+ native.title = asset.title && asset.title.text;
598
+ break;
599
+ case NATIVE_ASSET_TYPES.IMG:
600
+ const image = {
601
+ url: asset.img && asset.img.url,
602
+ height: asset.img && asset.img.h,
603
+ width: asset.img && asset.img.w
604
+ };
605
+ native[subtype === NATIVE_IMAGE_TYPES.ICON ? 'icon' : 'image'] = image;
606
+ break;
607
+ case NATIVE_ASSET_TYPES.VIDEO:
608
+ native.video = asset.video && asset.video.vasttag;
609
+ break;
610
+ case NATIVE_ASSET_TYPES.DATA:
611
+ setDataAsset(native, asset, subtype);
612
+ break;
613
+ default:
614
+ logWarn(`IX Bid Adapter: native asset ID ${asset.id} could not be recognized`);
615
+ }
616
+ }
617
+
618
+ setTrackers(native, nativeResponse);
619
+ return native;
620
+ }
621
+
622
+ function setDataAsset(native, asset, type) {
623
+ if (!(type in NATIVE_DATA_MAP)) {
624
+ logWarn(`IX Bid Adapter: native data asset type ${type} is not supported`);
625
+ return;
626
+ }
627
+ native[NATIVE_DATA_MAP[type]] = asset.data && asset.data.value;
628
+ }
629
+
630
+ function setTrackers(native, nativeResponse) {
631
+ native.impressionTrackers = []
632
+
633
+ if (Array.isArray(nativeResponse.imptrackers)) {
634
+ native.impressionTrackers.push(...nativeResponse.imptrackers)
635
+ }
636
+
637
+ if (Array.isArray(nativeResponse.link.clicktrackers)) {
638
+ native.impressionTrackers.push(...nativeResponse.link.clicktrackers)
639
+ }
640
+
641
+ if (Array.isArray(nativeResponse.eventtrackers)) {
642
+ nativeResponse.eventtrackers.forEach(tracker => {
643
+ if (tracker.event !== NATIVE_EVENT_TYPES.IMRESSION) {
644
+ return
645
+ }
646
+
647
+ switch (tracker.method) {
648
+ case NATIVE_EVENT_TRACKING_METHOD.IMG:
649
+ native.impressionTrackers.push(tracker.url);
650
+ break;
651
+ case NATIVE_EVENT_TRACKING_METHOD.JS:
652
+ native.javascriptTrackers = `<script src=\"${tracker.url}\"></script>`;
653
+ break;
654
+ }
655
+ })
656
+ }
657
+ }
658
+
338
659
  /**
339
660
  * Determines whether or not the given object is valid size format.
340
661
  *
@@ -432,6 +753,27 @@ function isValidBidFloorParams(bidFloor, bidFloorCur) {
432
753
  bidFloorCur.match(curRegex));
433
754
  }
434
755
 
756
+ function nativeMediaTypeValid(nativeObj) {
757
+ if (nativeObj === undefined) {
758
+ return true;
759
+ }
760
+
761
+ let hasValidAsset = false;
762
+
763
+ for (const property in nativeObj) {
764
+ if (!(property in NATIVE_ASSETS_MAP) && !NATIVE_ALLOWED_PROPERTIES.includes(property)) {
765
+ logError('IX Bid Adapter: native', { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED });
766
+ return false;
767
+ }
768
+
769
+ if (property in NATIVE_ASSETS_MAP) {
770
+ hasValidAsset = true;
771
+ }
772
+ }
773
+
774
+ return hasValidAsset;
775
+ }
776
+
435
777
  /**
436
778
  * Get bid request object with the associated id.
437
779
  *
@@ -485,7 +827,7 @@ function getEidInfo(allEids) {
485
827
  * @param {array} validBidRequests A list of valid bid request config objects.
486
828
  * @param {object} bidderRequest An object containing other info like gdprConsent.
487
829
  * @param {object} impressions An object containing a list of impression objects describing the bids for each transactionId
488
- * @param {array} version Endpoint version denoting banner or video.
830
+ * @param {array} version Endpoint version denoting banner, video or native.
489
831
  * @return {array} List of objects describing the request to the server.
490
832
  *
491
833
  */
@@ -542,6 +884,11 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
542
884
  if (tmax) {
543
885
  r.ext.ixdiag.tmax = tmax
544
886
  }
887
+
888
+ if (config.getConfig('userSync')) {
889
+ r.ext.ixdiag.syncsPerBidder = config.getConfig('userSync').syncsPerBidder;
890
+ }
891
+
545
892
  // Get cached errors stored in LocalStorage
546
893
  const cachedErrors = getCachedErrors();
547
894
 
@@ -570,7 +917,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
570
917
  // Apply GDPR information to the request if GDPR is enabled.
571
918
  if (bidderRequest) {
572
919
  if (bidderRequest.gdprConsent) {
573
- const gdprConsent = bidderRequest.gdprConsent;
920
+ gdprConsent = bidderRequest.gdprConsent;
574
921
 
575
922
  if (gdprConsent.hasOwnProperty('gdprApplies')) {
576
923
  r.regs = {
@@ -596,6 +943,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
596
943
 
597
944
  if (bidderRequest.uspConsent) {
598
945
  deepSetValue(r, 'regs.ext.us_privacy', bidderRequest.uspConsent);
946
+ usPrivacy = bidderRequest.uspConsent;
599
947
  }
600
948
 
601
949
  if (pageUrl) {
@@ -609,8 +957,12 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
609
957
 
610
958
  const payload = {};
611
959
  // Use the siteId in the first bid request as the main siteId.
612
- payload.s = validBidRequests[0].params.siteId;
960
+ siteID = validBidRequests[0].params.siteId;
961
+ payload.s = siteID;
613
962
  payload.v = version;
963
+ if (version) {
964
+ payload.v = version;
965
+ }
614
966
  payload.ac = 'j';
615
967
  payload.sd = 1;
616
968
 
@@ -698,6 +1050,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
698
1050
 
699
1051
  const gpid = impressions[transactionIds[adUnitIndex]].gpid;
700
1052
  const dfpAdUnitCode = impressions[transactionIds[adUnitIndex]].dfp_ad_unit_code;
1053
+ const tid = impressions[transactionIds[adUnitIndex]].tid
701
1054
  if (impressionObjects.length && BANNER in impressionObjects[0]) {
702
1055
  const { id, banner: { topframe } } = impressionObjects[0];
703
1056
  const _bannerImpression = {
@@ -708,10 +1061,11 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
708
1061
  },
709
1062
  }
710
1063
 
711
- if (dfpAdUnitCode || gpid) {
1064
+ if (dfpAdUnitCode || gpid || tid) {
712
1065
  _bannerImpression.ext = {};
713
1066
  _bannerImpression.ext.dfp_ad_unit_code = dfpAdUnitCode;
714
1067
  _bannerImpression.ext.gpid = gpid;
1068
+ _bannerImpression.ext.tid = tid;
715
1069
  }
716
1070
 
717
1071
  if ('bidfloor' in impressionObjects[0]) {
@@ -892,6 +1246,22 @@ function removeFromSizes(bannerSizeList, bannerSize) {
892
1246
  }
893
1247
  }
894
1248
 
1249
+ /**
1250
+ * Creates IX Native impressions based on validBidRequests
1251
+ * @param {object} validBidRequest valid request provided by prebid
1252
+ * @param {object} nativeImps reference to created native impressions
1253
+ */
1254
+ function createNativeImps(validBidRequest, nativeImps) {
1255
+ const imp = bidToNativeImp(validBidRequest);
1256
+
1257
+ if (Object.keys(imp).length != 0) {
1258
+ nativeImps[validBidRequest.transactionId] = {};
1259
+ nativeImps[validBidRequest.transactionId].ixImps = [];
1260
+ nativeImps[validBidRequest.transactionId].ixImps.push(imp);
1261
+ nativeImps[validBidRequest.transactionId].gpid = deepAccess(validBidRequest, 'ortb2Imp.ext.gpid')
1262
+ }
1263
+ }
1264
+
895
1265
  /**
896
1266
  * Creates IX Video impressions based on validBidRequests
897
1267
  * @param {object} validBidRequest valid request provided by prebid
@@ -904,6 +1274,7 @@ function createVideoImps(validBidRequest, videoImps) {
904
1274
  videoImps[validBidRequest.transactionId].ixImps = [];
905
1275
  videoImps[validBidRequest.transactionId].ixImps.push(imp);
906
1276
  videoImps[validBidRequest.transactionId].gpid = deepAccess(validBidRequest, 'ortb2Imp.ext.gpid');
1277
+ videoImps[validBidRequest.transactionId].tid = deepAccess(validBidRequest, 'ortb2Imp.ext.tid');
907
1278
  }
908
1279
  }
909
1280
 
@@ -930,6 +1301,7 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps) {
930
1301
 
931
1302
  bannerImps[validBidRequest.transactionId].gpid = deepAccess(validBidRequest, 'ortb2Imp.ext.gpid');
932
1303
  bannerImps[validBidRequest.transactionId].dfp_ad_unit_code = deepAccess(validBidRequest, 'ortb2Imp.ext.data.adserver.adslot');
1304
+ bannerImps[validBidRequest.transactionId].tid = deepAccess(validBidRequest, 'ortb2Imp.ext.tid');
933
1305
 
934
1306
  // Create IX imps from params.size
935
1307
  if (bannerSizeDefined) {
@@ -944,19 +1316,6 @@ function createBannerImps(validBidRequest, missingBannerSizes, bannerImps) {
944
1316
  }
945
1317
  }
946
1318
 
947
- /**
948
- * Determines IX configuration type based on IX params
949
- * @param {object} valid IX configured param
950
- * @returns {string}
951
- */
952
- function detectParamsType(validBidRequest) {
953
- if (deepAccess(validBidRequest, 'mediaTypes.video') && bidToVideoImp(validBidRequest).video) {
954
- return VIDEO;
955
- }
956
-
957
- return BANNER;
958
- }
959
-
960
1319
  /**
961
1320
  * Updates the Object to track missing banner sizes.
962
1321
  *
@@ -1069,7 +1428,7 @@ function localStorageHandler(data) {
1069
1428
  hasEnforcementHook: false,
1070
1429
  valid: hasDeviceAccess()
1071
1430
  };
1072
- validateStorageEnforcement(GLOBAL_VENDOR_ID, BIDDER_CODE, MODULE_TYPE, DEFAULT_ENFORCEMENT_SETTINGS, (permissions) => {
1431
+ validateStorageEnforcement(GLOBAL_VENDOR_ID, BIDDER_CODE, DEFAULT_ENFORCEMENT_SETTINGS, (permissions) => {
1073
1432
  if (permissions.valid) {
1074
1433
  storeErrorEventData(data);
1075
1434
  }
@@ -1170,6 +1529,7 @@ function isIndexRendererPreferred(bid) {
1170
1529
  }
1171
1530
 
1172
1531
  const isValid = !!(typeof (renderer) === 'object' && renderer.url && renderer.render);
1532
+
1173
1533
  // if renderer on the adunit is not valid or it's only a backup, our renderer may be used
1174
1534
  return !isValid || renderer.backupOnly;
1175
1535
  }
@@ -1202,6 +1562,7 @@ export const spec = {
1202
1562
  const paramsSize = deepAccess(bid, 'params.size');
1203
1563
  const mediaTypeBannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes');
1204
1564
  const mediaTypeVideoRef = deepAccess(bid, 'mediaTypes.video');
1565
+ const mediaTypeNativeRef = deepAccess(bid, 'mediaTypes.native');
1205
1566
  const mediaTypeVideoPlayerSize = deepAccess(bid, 'mediaTypes.video.playerSize');
1206
1567
  const hasBidFloor = bid.params.hasOwnProperty('bidFloor');
1207
1568
  const hasBidFloorCur = bid.params.hasOwnProperty('bidFloorCur');
@@ -1268,7 +1629,7 @@ export const spec = {
1268
1629
  }
1269
1630
  }
1270
1631
 
1271
- return true;
1632
+ return nativeMediaTypeValid(mediaTypeNativeRef);
1272
1633
  },
1273
1634
 
1274
1635
  /**
@@ -1282,41 +1643,32 @@ export const spec = {
1282
1643
  const reqs = []; // Stores banner + video requests
1283
1644
  const bannerImps = {}; // Stores created banner impressions
1284
1645
  const videoImps = {}; // Stores created video impressions
1285
- const multiFormatAdUnits = {}; // Stores references identified multi-format adUnits
1646
+ const nativeImps = {}; // Stores created native impressions
1286
1647
  const missingBannerSizes = {}; // To capture the missing sizes i.e not configured for ix
1287
1648
 
1288
1649
  // Step 1: Create impresssions from IX params
1289
1650
  validBidRequests.forEach((validBidRequest) => {
1290
1651
  const adUnitMediaTypes = Object.keys(deepAccess(validBidRequest, 'mediaTypes', {}))
1291
1652
 
1292
- switch (detectParamsType(validBidRequest)) {
1293
- case BANNER:
1294
- createBannerImps(validBidRequest, missingBannerSizes, bannerImps);
1295
- break;
1296
- case VIDEO:
1297
- createVideoImps(validBidRequest, videoImps)
1298
- break;
1299
- }
1300
-
1301
- if (includes(adUnitMediaTypes, BANNER) && includes(adUnitMediaTypes, VIDEO)) {
1302
- multiFormatAdUnits[validBidRequest.transactionId] = validBidRequest;
1303
- }
1304
- });
1305
-
1306
- // Step 2: Create impressions for multi-format adunits missing configurations
1307
- Object.keys(multiFormatAdUnits).forEach((transactionId) => {
1308
- const validBidRequest = multiFormatAdUnits[transactionId];
1309
- if (!bannerImps[transactionId]) {
1310
- createBannerImps(validBidRequest, missingBannerSizes, bannerImps);
1311
- }
1312
-
1313
- if (!videoImps[transactionId]) {
1314
- createVideoImps(validBidRequest, videoImps)
1653
+ for (const type in adUnitMediaTypes) {
1654
+ switch (adUnitMediaTypes[type]) {
1655
+ case BANNER:
1656
+ createBannerImps(validBidRequest, missingBannerSizes, bannerImps);
1657
+ break;
1658
+ case VIDEO:
1659
+ createVideoImps(validBidRequest, videoImps)
1660
+ break;
1661
+ case NATIVE:
1662
+ createNativeImps(validBidRequest, nativeImps)
1663
+ break;
1664
+ default:
1665
+ logWarn(`IX Bid Adapter: ad unit mediaTypes ${type} is not supported`)
1666
+ }
1315
1667
  }
1316
1668
  });
1317
1669
 
1318
- // Step 3: Update banner impressions with missing sizes
1319
- for (var transactionId in missingBannerSizes) {
1670
+ // Step 2: Update banner impressions with missing sizes
1671
+ for (let transactionId in missingBannerSizes) {
1320
1672
  if (missingBannerSizes.hasOwnProperty(transactionId)) {
1321
1673
  let missingSizes = missingBannerSizes[transactionId].missingSizes;
1322
1674
 
@@ -1337,13 +1689,16 @@ export const spec = {
1337
1689
  }
1338
1690
  }
1339
1691
 
1340
- // Step 4: Build banner & video requests
1692
+ // Step 4: Build banner, video & native requests
1341
1693
  if (Object.keys(bannerImps).length > 0) {
1342
1694
  reqs.push(...buildRequest(validBidRequests, bidderRequest, bannerImps, BANNER_ENDPOINT_VERSION));
1343
1695
  }
1344
1696
  if (Object.keys(videoImps).length > 0) {
1345
1697
  reqs.push(...buildRequest(validBidRequests, bidderRequest, videoImps, VIDEO_ENDPOINT_VERSION));
1346
1698
  }
1699
+ if (Object.keys(nativeImps).length > 0) {
1700
+ reqs.push(...buildRequest(validBidRequests, bidderRequest, nativeImps));
1701
+ }
1347
1702
 
1348
1703
  return reqs;
1349
1704
  },
@@ -1422,11 +1777,60 @@ export const spec = {
1422
1777
  * @returns {array} User sync pixels
1423
1778
  */
1424
1779
  getUserSyncs: function (syncOptions, serverResponses) {
1425
- return (syncOptions.iframeEnabled) ? [{
1426
- type: 'iframe',
1427
- url: USER_SYNC_URL
1428
- }] : [];
1780
+ const syncs = [];
1781
+ let publisherSyncsPerBidderOverride = null;
1782
+ if (serverResponses.length > 0) {
1783
+ publisherSyncsPerBidderOverride = deepAccess(serverResponses[0], 'body.ext.publishersyncsperbidderoverride');
1784
+ }
1785
+ if (publisherSyncsPerBidderOverride !== undefined && publisherSyncsPerBidderOverride == 0) {
1786
+ return [];
1787
+ }
1788
+ if (syncOptions.iframeEnabled) {
1789
+ syncs.push({
1790
+ type: 'iframe',
1791
+ url: IFRAME_USER_SYNC_URL
1792
+ })
1793
+ } else {
1794
+ let publisherSyncsPerBidder = null;
1795
+ if (config.getConfig('userSync')) {
1796
+ publisherSyncsPerBidder = config.getConfig('userSync').syncsPerBidder
1797
+ }
1798
+ if (publisherSyncsPerBidder === 0) {
1799
+ publisherSyncsPerBidder = publisherSyncsPerBidderOverride
1800
+ }
1801
+ if (publisherSyncsPerBidderOverride && (publisherSyncsPerBidder === 0 || publisherSyncsPerBidder)) {
1802
+ publisherSyncsPerBidder = publisherSyncsPerBidderOverride > publisherSyncsPerBidder ? publisherSyncsPerBidder : publisherSyncsPerBidderOverride
1803
+ } else {
1804
+ publisherSyncsPerBidder = 1
1805
+ }
1806
+ for (let i = 0; i < publisherSyncsPerBidder; i++) {
1807
+ syncs.push({
1808
+ type: 'image',
1809
+ url: buildImgSyncUrl(publisherSyncsPerBidder, i)
1810
+ })
1811
+ }
1812
+ }
1813
+ return syncs;
1429
1814
  }
1430
1815
  };
1431
1816
 
1817
+ /**
1818
+ * Build img user sync url
1819
+ * @param {int} syncsPerBidder number of syncs Per Bidder
1820
+ * @param {int} index index to pass
1821
+ * @returns {string} img user sync url
1822
+ */
1823
+ function buildImgSyncUrl(syncsPerBidder, index) {
1824
+ let consentString = '';
1825
+ let gdprApplies = '0';
1826
+ if (gdprConsent && gdprConsent.hasOwnProperty('gdprApplies')) {
1827
+ gdprApplies = gdprConsent.gdprApplies ? '1' : '0';
1828
+ }
1829
+ if (gdprConsent && gdprConsent.hasOwnProperty('consentString')) {
1830
+ consentString = gdprConsent.consentString || '';
1831
+ }
1832
+
1833
+ return IMG_USER_SYNC_URL + '&site_id=' + siteID.toString() + '&p=' + syncsPerBidder.toString() + '&i=' + index.toString() + '&gdpr=' + gdprApplies + '&gdpr_consent=' + consentString + '&us_privacy=' + (usPrivacy || '');
1834
+ }
1835
+
1432
1836
  registerBidder(spec);