prebid.js 6.0.0 → 6.4.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 (201) hide show
  1. package/.babelrc.js +1 -7
  2. package/.circleci/config.yml +1 -1
  3. package/README.md +1 -1
  4. package/browsers.json +13 -29
  5. package/gulpfile.js +88 -82
  6. package/integrationExamples/gpt/weboramaRtdProvider_example.html +23 -14
  7. package/karma.conf.maker.js +2 -2
  8. package/modules/33acrossBidAdapter.js +189 -102
  9. package/modules/adagioBidAdapter.js +1 -1
  10. package/modules/addefendBidAdapter.js +1 -0
  11. package/modules/adheseBidAdapter.js +7 -2
  12. package/modules/adkernelBidAdapter.js +147 -61
  13. package/modules/adlivetechBidAdapter.md +61 -0
  14. package/modules/adlooxAdServerVideo.js +2 -2
  15. package/modules/adlooxAnalyticsAdapter.js +4 -4
  16. package/modules/admanBidAdapter.js +1 -0
  17. package/modules/admixerBidAdapter.js +3 -2
  18. package/modules/adnuntiusBidAdapter.js +5 -2
  19. package/modules/adomikAnalyticsAdapter.js +16 -4
  20. package/modules/adplusBidAdapter.js +203 -0
  21. package/modules/adplusBidAdapter.md +39 -0
  22. package/modules/adxcgBidAdapter.js +311 -359
  23. package/modules/adxcgBidAdapter.md +22 -21
  24. package/modules/adyoulikeBidAdapter.js +7 -2
  25. package/modules/aniviewBidAdapter.js +1 -1
  26. package/modules/appnexusBidAdapter.js +23 -3
  27. package/modules/beachfrontBidAdapter.js +14 -17
  28. package/modules/beopBidAdapter.js +6 -4
  29. package/modules/bidViewability.js +3 -3
  30. package/modules/bidViewabilityIO.js +3 -3
  31. package/modules/codefuelBidAdapter.js +1 -3
  32. package/modules/codefuelBidAdapter.md +3 -3
  33. package/modules/colossussspBidAdapter.js +7 -0
  34. package/modules/compassBidAdapter.js +201 -0
  35. package/modules/compassBidAdapter.md +79 -0
  36. package/modules/craftBidAdapter.js +5 -3
  37. package/modules/criteoBidAdapter.js +1 -1
  38. package/modules/currency.js +2 -2
  39. package/modules/cwireBidAdapter.js +3 -0
  40. package/modules/dailyhuntBidAdapter.js +435 -0
  41. package/modules/dailyhuntBidAdapter.md +4 -0
  42. package/modules/datablocksBidAdapter.js +3 -3
  43. package/modules/dchain.js +149 -0
  44. package/modules/dchain.md +45 -0
  45. package/modules/deepintentBidAdapter.js +1 -1
  46. package/modules/dspxBidAdapter.js +1 -1
  47. package/modules/emx_digitalBidAdapter.js +9 -1
  48. package/modules/engageyaBidAdapter.js +68 -54
  49. package/modules/feedadBidAdapter.js +2 -2
  50. package/modules/feedadBidAdapter.md +4 -2
  51. package/modules/freewheel-sspBidAdapter.js +6 -0
  52. package/modules/futureads.md +48 -0
  53. package/modules/glimpseBidAdapter.js +44 -16
  54. package/modules/goldbachBidAdapter.js +1176 -0
  55. package/modules/goldbachBidAdapter.md +151 -0
  56. package/modules/gptPreAuction.js +11 -5
  57. package/modules/gridBidAdapter.js +5 -4
  58. package/modules/gumgumBidAdapter.js +7 -3
  59. package/modules/id5IdSystem.md +6 -6
  60. package/modules/imRtdProvider.js +31 -0
  61. package/modules/improvedigitalBidAdapter.js +19 -3
  62. package/modules/instreamTracking.js +4 -4
  63. package/modules/intersectionRtdProvider.js +114 -0
  64. package/modules/invibesBidAdapter.js +64 -14
  65. package/modules/invibesBidAdapter.md +2 -1
  66. package/modules/ipromBidAdapter.js +79 -0
  67. package/modules/ixBidAdapter.js +185 -22
  68. package/modules/kinessoIdSystem.js +1 -1
  69. package/modules/limelightDigitalBidAdapter.js +2 -1
  70. package/modules/livewrappedBidAdapter.js +8 -2
  71. package/modules/lotamePanoramaIdSystem.js +80 -8
  72. package/modules/luponmediaBidAdapter.js +570 -0
  73. package/modules/mediasquareBidAdapter.js +1 -9
  74. package/modules/merkleIdSystem.js +5 -0
  75. package/modules/missenaBidAdapter.js +89 -0
  76. package/modules/nativoBidAdapter.js +27 -1
  77. package/modules/nextMillenniumBidAdapter.js +37 -7
  78. package/modules/oguryBidAdapter.js +2 -1
  79. package/modules/openxBidAdapter.js +6 -1
  80. package/modules/prebidServerBidAdapter/index.js +19 -15
  81. package/modules/pubgeniusBidAdapter.js +1 -1
  82. package/modules/pubmaticBidAdapter.js +5 -3
  83. package/modules/pubxaiAnalyticsAdapter.js +17 -0
  84. package/modules/relaidoBidAdapter.js +86 -65
  85. package/modules/richaudienceBidAdapter.js +2 -3
  86. package/modules/rtdModule/index.js +48 -18
  87. package/modules/rubiconBidAdapter.js +31 -19
  88. package/modules/saambaaBidAdapter.js +420 -0
  89. package/modules/saambaaBidAdapter.md +65 -68
  90. package/modules/seedtagBidAdapter.js +6 -0
  91. package/modules/sharedIdSystem.js +27 -1
  92. package/modules/smaatoBidAdapter.js +9 -1
  93. package/modules/smartxBidAdapter.js +17 -1
  94. package/modules/sspBCBidAdapter.js +34 -3
  95. package/modules/tappxBidAdapter.js +3 -1
  96. package/modules/targetVideoBidAdapter.js +187 -0
  97. package/modules/targetVideoBidAdapter.md +34 -0
  98. package/modules/telariaBidAdapter.js +2 -2
  99. package/modules/trustxBidAdapter.js +18 -17
  100. package/modules/undertoneBidAdapter.js +8 -1
  101. package/modules/userId/index.js +27 -2
  102. package/modules/ventes.md +71 -0
  103. package/modules/ventesBidAdapter.js +104 -64
  104. package/modules/ventesBidAdapter.md +0 -1
  105. package/modules/vidoomyBidAdapter.js +65 -108
  106. package/modules/visxBidAdapter.js +20 -3
  107. package/modules/visxBidAdapter.md +4 -6
  108. package/modules/weboramaRtdProvider.js +288 -73
  109. package/modules/weboramaRtdProvider.md +27 -10
  110. package/modules/yahoosspBidAdapter.js +5 -1
  111. package/modules/yahoosspBidAdapter.md +1 -1
  112. package/modules/yieldlabBidAdapter.js +41 -10
  113. package/modules/yieldlabBidAdapter.md +91 -48
  114. package/modules/yieldoneBidAdapter.js +115 -11
  115. package/modules/zetaSspBidAdapter.md +33 -1
  116. package/modules/zeta_global_sspBidAdapter.js +22 -1
  117. package/package.json +6 -1
  118. package/plugins/pbjsGlobals.js +28 -1
  119. package/src/adapterManager.js +14 -8
  120. package/src/auction.js +5 -4
  121. package/src/prebid.js +1 -2
  122. package/src/targeting.js +24 -3
  123. package/src/utils.js +41 -7
  124. package/test/helpers/prebidGlobal.js +1 -0
  125. package/test/spec/integration/faker/googletag.js +6 -0
  126. package/test/spec/modules/33acrossBidAdapter_spec.js +300 -78
  127. package/test/spec/modules/adheseBidAdapter_spec.js +27 -1
  128. package/test/spec/modules/adlooxAnalyticsAdapter_spec.js +6 -6
  129. package/test/spec/modules/adnuntiusBidAdapter_spec.js +35 -0
  130. package/test/spec/modules/adomikAnalyticsAdapter_spec.js +9 -1
  131. package/test/spec/modules/adplusBidAdapter_spec.js +213 -0
  132. package/test/spec/modules/adxcgBidAdapter_spec.js +820 -571
  133. package/test/spec/modules/adyoulikeBidAdapter_spec.js +26 -0
  134. package/test/spec/modules/appnexusBidAdapter_spec.js +63 -1
  135. package/test/spec/modules/beachfrontBidAdapter_spec.js +65 -1
  136. package/test/spec/modules/beopBidAdapter_spec.js +1 -1
  137. package/test/spec/modules/bidViewabilityIO_spec.js +2 -2
  138. package/test/spec/modules/bidViewability_spec.js +4 -4
  139. package/test/spec/modules/codefuelBidAdapter_spec.js +1 -1
  140. package/test/spec/modules/colossussspBidAdapter_spec.js +9 -0
  141. package/test/spec/modules/compassBidAdapter_spec.js +397 -0
  142. package/test/spec/modules/cwireBidAdapter_spec.js +10 -8
  143. package/test/spec/modules/dailyhuntBidAdapter_spec.js +404 -0
  144. package/test/spec/modules/datablocksBidAdapter_spec.js +3 -3
  145. package/test/spec/modules/dchain_spec.js +329 -0
  146. package/test/spec/modules/emx_digitalBidAdapter_spec.js +10 -0
  147. package/test/spec/modules/engageyaBidAdapter_spec.js +231 -95
  148. package/test/spec/modules/eplanningBidAdapter_spec.js +8 -8
  149. package/test/spec/modules/feedadBidAdapter_spec.js +15 -0
  150. package/test/spec/modules/freewheel-sspBidAdapter_spec.js +19 -0
  151. package/test/spec/modules/glimpseBidAdapter_spec.js +33 -0
  152. package/test/spec/modules/goldbachBidAdapter_spec.js +1359 -0
  153. package/test/spec/modules/gptPreAuction_spec.js +58 -4
  154. package/test/spec/modules/gumgumBidAdapter_spec.js +6 -0
  155. package/test/spec/modules/imRtdProvider_spec.js +25 -0
  156. package/test/spec/modules/improvedigitalBidAdapter_spec.js +3 -1
  157. package/test/spec/modules/intersectionRtdProvider_spec.js +141 -0
  158. package/test/spec/modules/invibesBidAdapter_spec.js +148 -4
  159. package/test/spec/modules/ipromBidAdapter_spec.js +195 -0
  160. package/test/spec/modules/ixBidAdapter_spec.js +293 -2
  161. package/test/spec/modules/konduitWrapper_spec.js +0 -1
  162. package/test/spec/modules/limelightDigitalBidAdapter_spec.js +10 -7
  163. package/test/spec/modules/livewrappedBidAdapter_spec.js +31 -0
  164. package/test/spec/modules/lotamePanoramaIdSystem_spec.js +227 -0
  165. package/test/spec/modules/luponmediaBidAdapter_spec.js +412 -0
  166. package/test/spec/modules/mediasquareBidAdapter_spec.js +4 -4
  167. package/test/spec/modules/merkleIdSystem_spec.js +18 -0
  168. package/test/spec/modules/missenaBidAdapter_spec.js +134 -0
  169. package/test/spec/modules/nativoBidAdapter_spec.js +35 -18
  170. package/test/spec/modules/nextMillenniumBidAdapter_spec.js +26 -1
  171. package/test/spec/modules/oguryBidAdapter_spec.js +13 -11
  172. package/test/spec/modules/openxBidAdapter_spec.js +5 -0
  173. package/test/spec/modules/prebidServerBidAdapter_spec.js +62 -2
  174. package/test/spec/modules/pubgeniusBidAdapter_spec.js +3 -3
  175. package/test/spec/modules/pubmaticBidAdapter_spec.js +1 -1
  176. package/test/spec/modules/pubxaiAnalyticsAdapter_spec.js +11 -0
  177. package/test/spec/modules/realTimeDataModule_spec.js +135 -49
  178. package/test/spec/modules/relaidoBidAdapter_spec.js +71 -63
  179. package/test/spec/modules/richaudienceBidAdapter_spec.js +2 -2
  180. package/test/spec/modules/rubiconBidAdapter_spec.js +65 -9
  181. package/test/spec/modules/seedtagBidAdapter_spec.js +3 -0
  182. package/test/spec/modules/sharedIdSystem_spec.js +52 -6
  183. package/test/spec/modules/smaatoBidAdapter_spec.js +61 -0
  184. package/test/spec/modules/smartxBidAdapter_spec.js +9 -0
  185. package/test/spec/modules/sspBCBidAdapter_spec.js +33 -3
  186. package/test/spec/modules/tappxBidAdapter_spec.js +4 -0
  187. package/test/spec/modules/targetVideoBidAdapter_spec.js +96 -0
  188. package/test/spec/modules/trustxBidAdapter_spec.js +42 -0
  189. package/test/spec/modules/userId_spec.js +51 -0
  190. package/test/spec/modules/vidoomyBidAdapter_spec.js +32 -13
  191. package/test/spec/modules/visxBidAdapter_spec.js +121 -5
  192. package/test/spec/modules/weboramaRtdProvider_spec.js +408 -214
  193. package/test/spec/modules/yahoosspBidAdapter_spec.js +28 -1
  194. package/test/spec/modules/yieldlabBidAdapter_spec.js +81 -0
  195. package/test/spec/modules/yieldoneBidAdapter_spec.js +299 -53
  196. package/test/spec/modules/zeta_global_sspBidAdapter_spec.js +33 -1
  197. package/test/spec/unit/core/adapterManager_spec.js +24 -6
  198. package/test/spec/unit/core/targeting_spec.js +116 -0
  199. package/test/spec/utils_spec.js +38 -0
  200. package/test/test_deps.js +3 -0
  201. package/test/test_index.js +1 -3
@@ -0,0 +1,79 @@
1
+ import { logError } from '../src/utils.js';
2
+ import { registerBidder } from '../src/adapters/bidderFactory.js';
3
+
4
+ const BIDDER_CODE = 'iprom';
5
+ const ENDPOINT_URL = 'https://core.iprom.net/programmatic';
6
+ const VERSION = 'v1.0.2';
7
+ const DEFAULT_CURRENCY = 'EUR';
8
+ const DEFAULT_NETREVENUE = true;
9
+ const DEFAULT_TTL = 360;
10
+
11
+ export const spec = {
12
+ code: BIDDER_CODE,
13
+ isBidRequestValid: function ({ bidder, params = {} } = {}) {
14
+ // id parameter checks
15
+ if (!params.id) {
16
+ logError(`${bidder}: Parameter 'id' missing`);
17
+ return false;
18
+ } else if (typeof params.id !== 'string') {
19
+ logError(`${bidder}: Parameter 'id' needs to be a string`);
20
+ return false;
21
+ }
22
+ // dimension parameter checks
23
+ if (!params.dimension) {
24
+ logError(`${bidder}: Required parameter 'dimension' missing`);
25
+ return false;
26
+ } else if (typeof params.dimension !== 'string') {
27
+ logError(`${bidder}: Parameter 'dimension' needs to be a string`);
28
+ return false;
29
+ }
30
+
31
+ return true;
32
+ },
33
+
34
+ buildRequests: function (validBidRequests, bidderRequest) {
35
+ const payload = {
36
+ bids: validBidRequests,
37
+ referer: bidderRequest.refererInfo,
38
+ version: VERSION
39
+ };
40
+ const payloadString = JSON.stringify(payload);
41
+
42
+ return {
43
+ method: 'POST',
44
+ url: ENDPOINT_URL,
45
+ data: payloadString
46
+ };
47
+ },
48
+
49
+ interpretResponse: function (serverResponse, request) {
50
+ let bids = serverResponse.body;
51
+
52
+ const bidResponses = [];
53
+
54
+ bids.forEach(bid => {
55
+ const b = {
56
+ ad: bid.ad,
57
+ requestId: bid.requestId,
58
+ cpm: bid.cpm,
59
+ width: bid.width,
60
+ height: bid.height,
61
+ creativeId: bid.creativeId,
62
+ currency: bid.currency || DEFAULT_CURRENCY,
63
+ netRevenue: bid.netRevenue || DEFAULT_NETREVENUE,
64
+ ttl: bid.ttl || DEFAULT_TTL,
65
+ meta: {},
66
+ };
67
+
68
+ if (bid.aDomains && bid.aDomains.length) {
69
+ b.meta.advertiserDomains = bid.aDomains;
70
+ }
71
+
72
+ bidResponses.push(b);
73
+ });
74
+
75
+ return bidResponses;
76
+ },
77
+ }
78
+
79
+ registerBidder(spec);
@@ -1,6 +1,9 @@
1
- import { deepAccess, parseGPTSingleSizeArray, inIframe, deepClone, logError, logWarn, isFn, contains, isInteger, isArray, deepSetValue, parseQueryStringParameters, isEmpty, mergeDeep, convertTypes } from '../src/utils.js';
1
+ import { deepAccess, parseGPTSingleSizeArray, inIframe, deepClone, logError, logWarn, isFn, contains, isInteger, isArray, deepSetValue, parseQueryStringParameters, isEmpty, mergeDeep, convertTypes, hasDeviceAccess } from '../src/utils.js';
2
2
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
3
3
  import { config } from '../src/config.js';
4
+ import CONSTANTS from '../src/constants.json';
5
+ import { getStorageManager, validateStorageEnforcement } from '../src/storageManager.js';
6
+ import events from '../src/events.js';
4
7
  import find from 'core-js-pure/features/array/find.js';
5
8
  import { registerBidder } from '../src/adapters/bidderFactory.js';
6
9
  import { INSTREAM, OUTSTREAM } from '../src/video.js';
@@ -20,15 +23,23 @@ const VIDEO_TIME_TO_LIVE = 3600; // 1hr
20
23
  const NET_REVENUE = true;
21
24
  const MAX_REQUEST_SIZE = 8000;
22
25
  const MAX_REQUEST_LIMIT = 4;
23
-
24
26
  const PRICE_TO_DOLLAR_FACTOR = {
25
27
  JPY: 1
26
28
  };
27
29
  const USER_SYNC_URL = 'https://js-sec.indexww.com/um/ixmatch.html';
28
30
  const RENDERER_URL = 'https://js-sec.indexww.com/htv/video-player.js';
29
31
  const FLOOR_SOURCE = { PBJS: 'p', IX: 'x' };
30
- // determines which eids we send and the rtiPartner field in ext
31
-
32
+ export const ERROR_CODES = {
33
+ BID_SIZE_INVALID_FORMAT: 1,
34
+ BID_SIZE_NOT_INCLUDED: 2,
35
+ PROPERTY_NOT_INCLUDED: 3,
36
+ SITE_ID_INVALID_VALUE: 4,
37
+ BID_FLOOR_INVALID_FORMAT: 5,
38
+ IX_FPD_EXCEEDS_MAX_SIZE: 6,
39
+ EXCEEDS_MAX_SIZE: 7,
40
+ PB_FPD_EXCEEDS_MAX_SIZE: 8,
41
+ VIDEO_DURATION_INVALID: 9
42
+ };
32
43
  const FIRST_PARTY_DATA = {
33
44
  SITE: [
34
45
  'id', 'name', 'domain', 'cat', 'sectioncat', 'pagecat', 'page', 'ref', 'search', 'mobile',
@@ -36,7 +47,6 @@ const FIRST_PARTY_DATA = {
36
47
  ],
37
48
  USER: ['id', 'buyeruid', 'yob', 'gender', 'keywords', 'customdata', 'geo', 'data', 'ext']
38
49
  };
39
-
40
50
  const SOURCE_RTI_MAPPING = {
41
51
  'liveramp.com': 'idl',
42
52
  'netid.de': 'NETID',
@@ -45,7 +55,6 @@ const SOURCE_RTI_MAPPING = {
45
55
  'uidapi.com': 'UID2',
46
56
  'adserver.org': 'TDID'
47
57
  };
48
-
49
58
  const PROVIDERS = [
50
59
  'britepoolid',
51
60
  'id5id',
@@ -62,9 +71,7 @@ const PROVIDERS = [
62
71
  'TDID',
63
72
  'flocId'
64
73
  ];
65
-
66
74
  const REQUIRED_VIDEO_PARAMS = ['mimes', 'minduration', 'maxduration']; // note: protocol/protocols is also reqd
67
-
68
75
  const VIDEO_PARAMS_ALLOW_LIST = [
69
76
  'mimes', 'minduration', 'maxduration', 'protocols', 'protocol',
70
77
  'startdelay', 'placement', 'linearity', 'skip', 'skipmin',
@@ -73,6 +80,17 @@ const VIDEO_PARAMS_ALLOW_LIST = [
73
80
  'delivery', 'pos', 'companionad', 'api', 'companiontype', 'ext',
74
81
  'playerSize', 'w', 'h'
75
82
  ];
83
+ const LOCAL_STORAGE_KEY = 'ixdiag';
84
+ let hasRegisteredHandler = false;
85
+ export const storage = getStorageManager(GLOBAL_VENDOR_ID, BIDDER_CODE);
86
+
87
+ // 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.
88
+ const MEDIA_TYPES = {
89
+ Banner: 1,
90
+ Video: 2,
91
+ Audio: 3,
92
+ Native: 4
93
+ }
76
94
 
77
95
  /**
78
96
  * Transform valid bid request config object to banner impression object that will be sent to ad server.
@@ -125,7 +143,10 @@ function bidToVideoImp(bid) {
125
143
  }
126
144
 
127
145
  if (imp.video.minduration > imp.video.maxduration) {
128
- logError(`IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]`);
146
+ logError(
147
+ `IX Bid Adapter: video minduration [${imp.video.minduration}] cannot be greater than video maxduration [${imp.video.maxduration}]`,
148
+ { bidder: BIDDER_CODE, code: ERROR_CODES.VIDEO_DURATION_INVALID }
149
+ );
129
150
  return {};
130
151
  }
131
152
 
@@ -262,9 +283,14 @@ function parseBid(rawBid, currency, bidRequest) {
262
283
  bid.currency = currency;
263
284
  bid.creativeId = rawBid.hasOwnProperty('crid') ? rawBid.crid : '-';
264
285
 
265
- // in the event of a video
266
- if (deepAccess(rawBid, 'ext.vasturl')) {
286
+ if (rawBid.mtype == MEDIA_TYPES.Video) {
287
+ bid.vastXml = rawBid.adm
288
+ } else if (rawBid.ext && rawBid.ext.vasturl) {
267
289
  bid.vastUrl = rawBid.ext.vasturl
290
+ }
291
+
292
+ // in the event of a video
293
+ if ((rawBid.ext && rawBid.ext.vasturl) || rawBid.mtype == MEDIA_TYPES.Video) {
268
294
  bid.width = bidRequest.video.w;
269
295
  bid.height = bidRequest.video.h;
270
296
  bid.mediaType = VIDEO;
@@ -498,6 +524,13 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
498
524
  r.ext.ixdiag[key] = ixdiag[key];
499
525
  }
500
526
 
527
+ // Get cached errors stored in LocalStorage
528
+ const cachedErrors = getCachedErrors();
529
+
530
+ if (!isEmpty(cachedErrors)) {
531
+ r.ext.ixdiag.err = cachedErrors;
532
+ }
533
+
501
534
  // if an schain is provided, send it along
502
535
  if (validBidRequests[0].schain) {
503
536
  r.source = {
@@ -576,7 +609,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
576
609
  const baseRequestSize = `${baseUrl}${parseQueryStringParameters({ ...payload, r: JSON.stringify(r) })}`.length;
577
610
 
578
611
  if (baseRequestSize > MAX_REQUEST_SIZE) {
579
- logError('ix bidder: Base request size has exceeded maximum request size.');
612
+ logError('IX Bid Adapter: Base request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.EXCEEDS_MAX_SIZE });
580
613
  return requests;
581
614
  }
582
615
 
@@ -606,7 +639,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
606
639
  }
607
640
  currentRequestSize += fpdRequestSize;
608
641
  } else {
609
- logError('ix bidder: IX config FPD request size has exceeded maximum request size.');
642
+ logError('IX Bid Adapter: IX config FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.IX_FPD_EXCEEDS_MAX_SIZE });
610
643
  }
611
644
  }
612
645
 
@@ -713,7 +746,7 @@ function buildRequest(validBidRequests, bidderRequest, impressions, version) {
713
746
  const fpdRequestSize = encodeURIComponent(JSON.stringify({ ...site, ...user })).length;
714
747
  currentRequestSize += fpdRequestSize;
715
748
  } else {
716
- logError('ix bidder: FPD request size has exceeded maximum request size.');
749
+ logError('IX Bid Adapter: FPD request size has exceeded maximum request size.', { bidder: BIDDER_CODE, code: ERROR_CODES.PB_FPD_EXCEEDS_MAX_SIZE });
717
750
  }
718
751
  }
719
752
 
@@ -946,10 +979,117 @@ function createMissingBannerImp(bid, imp, newSize) {
946
979
  }
947
980
 
948
981
  /**
982
+ * @typedef {Array[message: string, err: Object<bidder: string, code: number>]} ErrorData
983
+ * @property {string} message - The error message.
984
+ * @property {object} err - The error object.
985
+ * @property {string} err.bidder - The bidder of the error.
986
+ * @property {string} err.code - The error code.
987
+ */
988
+
989
+ /**
990
+ * Error Event handler that receives type and arguments in a data object.
991
+ *
992
+ * @param {ErrorData} data
993
+ */
994
+ function storeErrorEventData(data) {
995
+ if (!storage.localStorageIsEnabled()) {
996
+ return;
997
+ }
998
+
999
+ let currentStorage;
1000
+
1001
+ try {
1002
+ currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}');
1003
+ } catch (e) {
1004
+ logWarn('ix can not read ixdiag from localStorage.');
1005
+ }
1006
+
1007
+ const todayDate = new Date();
1008
+
1009
+ Object.keys(currentStorage).map((errorDate) => {
1010
+ const date = new Date(errorDate);
1011
+
1012
+ if (date.setDate(date.getDate() + 7) - todayDate < 0) {
1013
+ delete currentStorage[errorDate];
1014
+ }
1015
+ });
1016
+
1017
+ if (data.type === 'ERROR' && data.arguments && data.arguments[1] && data.arguments[1].bidder === BIDDER_CODE) {
1018
+ const todayString = todayDate.toISOString().slice(0, 10);
1019
+
1020
+ const errorCode = data.arguments[1].code;
1021
+
1022
+ if (errorCode) {
1023
+ currentStorage[todayString] = currentStorage[todayString] || {};
1024
+
1025
+ if (!Number(currentStorage[todayString][errorCode])) {
1026
+ currentStorage[todayString][errorCode] = 0;
1027
+ }
1028
+
1029
+ currentStorage[todayString][errorCode]++;
1030
+ };
1031
+ }
1032
+
1033
+ storage.setDataInLocalStorage(LOCAL_STORAGE_KEY, JSON.stringify(currentStorage));
1034
+ }
1035
+
1036
+ /**
1037
+ * Event handler for storing data into local storage. It will only store data if
1038
+ * local storage premissions are avaliable
1039
+ */
1040
+ function localStorageHandler(data) {
1041
+ if (data.type === 'ERROR' && data.arguments && data.arguments[1] && data.arguments[1].bidder === BIDDER_CODE) {
1042
+ const DEFAULT_ENFORCEMENT_SETTINGS = {
1043
+ hasEnforcementHook: false,
1044
+ valid: hasDeviceAccess()
1045
+ };
1046
+ validateStorageEnforcement(GLOBAL_VENDOR_ID, BIDDER_CODE, DEFAULT_ENFORCEMENT_SETTINGS, (permissions) => {
1047
+ if (permissions.valid) {
1048
+ storeErrorEventData(data);
1049
+ }
1050
+ });
1051
+ }
1052
+ }
1053
+
1054
+ /**
1055
+ * Get ixdiag stored in LocalStorage and format to be added to request payload
1056
+ *
1057
+ * @returns {Object} Object with error codes and counts
1058
+ */
1059
+ function getCachedErrors() {
1060
+ if (!storage.localStorageIsEnabled()) {
1061
+ return;
1062
+ }
1063
+
1064
+ const errors = {};
1065
+ let currentStorage;
1066
+
1067
+ try {
1068
+ currentStorage = JSON.parse(storage.getDataFromLocalStorage(LOCAL_STORAGE_KEY) || '{}');
1069
+ } catch (e) {
1070
+ logError('ix can not read ixdiag from localStorage.');
1071
+ return null;
1072
+ }
1073
+
1074
+ Object.keys(currentStorage).forEach((date) => {
1075
+ Object.keys(currentStorage[date]).forEach((code) => {
1076
+ if (typeof currentStorage[date][code] === 'number') {
1077
+ errors[code] = errors[code]
1078
+ ? errors[code] + currentStorage[date][code]
1079
+ : currentStorage[date][code];
1080
+ }
1081
+ });
1082
+ });
1083
+
1084
+ return errors;
1085
+ }
1086
+
1087
+ /**
1088
+ *
949
1089
  * Initialize Outstream Renderer
950
1090
  * @param {Object} bid
951
1091
  */
952
- function outstreamRenderer (bid) {
1092
+ function outstreamRenderer(bid) {
953
1093
  bid.renderer.push(() => {
954
1094
  var config = {
955
1095
  width: bid.width,
@@ -957,7 +1097,13 @@ function outstreamRenderer (bid) {
957
1097
  timeout: 3000
958
1098
  };
959
1099
 
960
- window.IXOutstreamPlayer(bid.vastUrl, bid.adUnitCode, config);
1100
+ // IXOutstreamPlayer supports both vastUrl and vastXml, so we can pass either.
1101
+ // Since vastUrl is going to be deprecated from exchange response, vastXml takes priority.
1102
+ if (bid.vastXml) {
1103
+ window.IXOutstreamPlayer(bid.vastXml, bid.adUnitCode, config);
1104
+ } else {
1105
+ window.IXOutstreamPlayer(bid.vastUrl, bid.adUnitCode, config);
1106
+ }
961
1107
  });
962
1108
  }
963
1109
 
@@ -966,7 +1112,7 @@ function outstreamRenderer (bid) {
966
1112
  * @param {string} id
967
1113
  * @returns {Renderer}
968
1114
  */
969
- function createRenderer (id) {
1115
+ function createRenderer(id) {
970
1116
  const renderer = Renderer.install({
971
1117
  id: id,
972
1118
  url: RENDERER_URL,
@@ -1000,6 +1146,12 @@ export const spec = {
1000
1146
  * @return {boolean} True if this is a valid bid, and false otherwise.
1001
1147
  */
1002
1148
  isBidRequestValid: function (bid) {
1149
+ if (!hasRegisteredHandler) {
1150
+ events.on(CONSTANTS.EVENTS.AUCTION_DEBUG, localStorageHandler);
1151
+ events.on(CONSTANTS.EVENTS.AD_RENDER_FAILED, localStorageHandler);
1152
+ hasRegisteredHandler = true;
1153
+ }
1154
+
1003
1155
  const paramsVideoRef = deepAccess(bid, 'params.video');
1004
1156
  const paramsSize = deepAccess(bid, 'params.size');
1005
1157
  const mediaTypeBannerSizes = deepAccess(bid, 'mediaTypes.banner.sizes');
@@ -1009,6 +1161,7 @@ export const spec = {
1009
1161
  const hasBidFloorCur = bid.params.hasOwnProperty('bidFloorCur');
1010
1162
 
1011
1163
  if (bid.hasOwnProperty('mediaType') && !(contains(SUPPORTED_AD_TYPES, bid.mediaType))) {
1164
+ logWarn('IX Bid Adapter: media type is not supported.');
1012
1165
  return false;
1013
1166
  }
1014
1167
 
@@ -1020,26 +1173,26 @@ export const spec = {
1020
1173
  // since there is an ix bidder level size, make sure its valid
1021
1174
  const ixSize = getFirstSize(paramsSize);
1022
1175
  if (!ixSize) {
1023
- logError('ix bidder params: size has invalid format.');
1176
+ logError('IX Bid Adapter: size has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_INVALID_FORMAT });
1024
1177
  return false;
1025
1178
  }
1026
1179
  // check if the ix bidder level size, is present in ad unit level
1027
1180
  if (!includesSize(bid.sizes, ixSize) &&
1028
1181
  !(includesSize(mediaTypeVideoPlayerSize, ixSize)) &&
1029
1182
  !(includesSize(mediaTypeBannerSizes, ixSize))) {
1030
- logError('ix bidder params: bid size is not included in ad unit sizes or player size.');
1183
+ logError('IX Bid Adapter: bid size is not included in ad unit sizes or player size.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_SIZE_NOT_INCLUDED });
1031
1184
  return false;
1032
1185
  }
1033
1186
  }
1034
1187
 
1035
1188
  if (typeof bid.params.siteId !== 'string' && typeof bid.params.siteId !== 'number') {
1036
- logError('ix bidder params: siteId must be string or number value.');
1189
+ logError('IX Bid Adapter: siteId must be string or number value.', { bidder: BIDDER_CODE, code: ERROR_CODES.SITE_ID_INVALID_VALUE });
1037
1190
  return false;
1038
1191
  }
1039
1192
 
1040
1193
  if (hasBidFloor || hasBidFloorCur) {
1041
1194
  if (!(hasBidFloor && hasBidFloorCur && isValidBidFloorParams(bid.params.bidFloor, bid.params.bidFloorCur))) {
1042
- logError('ix bidder params: bidFloor / bidFloorCur parameter has invalid format.');
1195
+ logError('IX Bid Adapter: bidFloor / bidFloorCur parameter has invalid format.', { bidder: BIDDER_CODE, code: ERROR_CODES.BID_FLOOR_INVALID_FORMAT });
1043
1196
  return false;
1044
1197
  }
1045
1198
  }
@@ -1048,7 +1201,7 @@ export const spec = {
1048
1201
  const errorList = checkVideoParams(mediaTypeVideoRef, paramsVideoRef);
1049
1202
  if (errorList.length) {
1050
1203
  errorList.forEach((err) => {
1051
- logError(err);
1204
+ logError(err, { bidder: BIDDER_CODE, code: ERROR_CODES.PROPERTY_NOT_INCLUDED });
1052
1205
  });
1053
1206
  return false;
1054
1207
  }
@@ -1169,6 +1322,16 @@ export const spec = {
1169
1322
 
1170
1323
  bids.push(bid);
1171
1324
  }
1325
+
1326
+ if (deepAccess(requestBid, 'ext.ixdiag.err')) {
1327
+ if (storage.localStorageIsEnabled()) {
1328
+ try {
1329
+ storage.removeDataFromLocalStorage(LOCAL_STORAGE_KEY);
1330
+ } catch (e) {
1331
+ logError('ix can not clear ixdiag from localStorage.');
1332
+ }
1333
+ }
1334
+ }
1172
1335
  }
1173
1336
 
1174
1337
  return bids;
@@ -180,7 +180,7 @@ function kinessoSyncUrl(accountId, consentData) {
180
180
  const usPrivacyString = uspDataHandler.getConsentData();
181
181
  let kinessoSyncUrl = `${ID_SVC}?accountid=${accountId}`;
182
182
  if (usPrivacyString) {
183
- kinessoSyncUrl = `${kinessoSyncUrl}?us_privacy=${usPrivacyString}`;
183
+ kinessoSyncUrl = `${kinessoSyncUrl}&us_privacy=${usPrivacyString}`;
184
184
  }
185
185
  if (!consentData || typeof consentData.gdprApplies !== 'boolean' || !consentData.gdprApplies) return kinessoSyncUrl;
186
186
 
@@ -158,7 +158,8 @@ function buildPlacement(bidRequest) {
158
158
  height: size[1]
159
159
  }
160
160
  }),
161
- type: bidRequest.params.adUnitType.toUpperCase()
161
+ type: bidRequest.params.adUnitType.toUpperCase(),
162
+ publisherId: bidRequest.params.publisherId
162
163
  }
163
164
  }
164
165
  }
@@ -1,4 +1,4 @@
1
- import { isSafariBrowser, deepAccess, getWindowTop } from '../src/utils.js';
1
+ import { isSafariBrowser, deepAccess, getWindowTop, mergeDeep } from '../src/utils.js';
2
2
  import { registerBidder } from '../src/adapters/bidderFactory.js';
3
3
  import { config } from '../src/config.js';
4
4
  import find from 'core-js-pure/features/array/find.js';
@@ -60,11 +60,17 @@ export const spec = {
60
60
  const bundle = find(bidRequests, hasBundleParam);
61
61
  const tid = find(bidRequests, hasTidParam);
62
62
  const schain = bidRequests[0].schain;
63
+ let ortb2 = config.getConfig('ortb2');
64
+ const eids = handleEids(bidRequests);
63
65
  bidUrl = bidUrl ? bidUrl.params.bidUrl : URL;
64
66
  url = url ? url.params.url : (getAppDomain() || getTopWindowLocation(bidderRequest));
65
67
  test = test ? test.params.test : undefined;
66
68
  var adRequests = bidRequests.map(bidToAdRequest);
67
69
 
70
+ if (eids) {
71
+ ortb2 = mergeDeep(ortb2 || {}, eids);
72
+ }
73
+
68
74
  const payload = {
69
75
  auctionId: auctionId ? auctionId.auctionId : undefined,
70
76
  publisherId: publisherId ? publisherId.params.publisherId : undefined,
@@ -86,7 +92,7 @@ export const spec = {
86
92
  cookieSupport: !isSafariBrowser() && storage.cookiesAreEnabled(),
87
93
  rcv: getAdblockerRecovered(),
88
94
  adRequests: [...adRequests],
89
- rtbData: handleEids(bidRequests),
95
+ rtbData: ortb2,
90
96
  schain: schain
91
97
  };
92
98
 
@@ -4,10 +4,20 @@
4
4
  * @module modules/lotamePanoramaId
5
5
  * @requires module:modules/userId
6
6
  */
7
- import { timestamp, isStr, logError, isBoolean, buildUrl, isEmpty, isArray } from '../src/utils.js';
7
+ import {
8
+ timestamp,
9
+ isStr,
10
+ logError,
11
+ isBoolean,
12
+ buildUrl,
13
+ isEmpty,
14
+ isArray,
15
+ isEmptyStr
16
+ } from '../src/utils.js';
8
17
  import { ajax } from '../src/ajax.js';
9
18
  import { submodule } from '../src/hook.js';
10
19
  import { getStorageManager } from '../src/storageManager.js';
20
+ import { uspDataHandler } from '../src/adapterManager.js';
11
21
 
12
22
  const KEY_ID = 'panoramaId';
13
23
  const KEY_EXPIRY = `${KEY_ID}_expiry`;
@@ -115,14 +125,23 @@ function saveLotameCache(
115
125
 
116
126
  /**
117
127
  * Retrieve all the cached values from cookies and/or local storage
128
+ * @param {Number} clientId
118
129
  */
119
- function getLotameLocalCache() {
130
+ function getLotameLocalCache(clientId = undefined) {
120
131
  let cache = {
121
132
  data: getFromStorage(KEY_ID),
122
133
  expiryTimestampMs: 0,
134
+ clientExpiryTimestampMs: 0,
123
135
  };
124
136
 
125
137
  try {
138
+ if (clientId) {
139
+ const rawClientExpiry = getFromStorage(`${KEY_EXPIRY}_${clientId}`);
140
+ if (isStr(rawClientExpiry)) {
141
+ cache.clientExpiryTimestampMs = parseInt(rawClientExpiry, 10);
142
+ }
143
+ }
144
+
126
145
  const rawExpiry = getFromStorage(KEY_EXPIRY);
127
146
  if (isStr(rawExpiry)) {
128
147
  cache.expiryTimestampMs = parseInt(rawExpiry, 10);
@@ -191,11 +210,25 @@ export const lotamePanoramaIdSubmodule = {
191
210
  */
192
211
  getId(config, consentData, cacheIdObj) {
193
212
  cookieDomain = lotamePanoramaIdSubmodule.findRootDomain();
194
- let localCache = getLotameLocalCache();
213
+ const configParams = (config && config.params) || {};
214
+ const clientId = configParams.clientId;
215
+ const hasCustomClientId = !isEmpty(clientId);
216
+ const localCache = getLotameLocalCache(clientId);
195
217
 
196
- let refreshNeeded = Date.now() > localCache.expiryTimestampMs;
218
+ const hasExpiredPanoId = Date.now() > localCache.expiryTimestampMs;
219
+
220
+ if (hasCustomClientId) {
221
+ const hasFreshClientNoConsent = Date.now() < localCache.clientExpiryTimestampMs;
222
+ if (hasFreshClientNoConsent) {
223
+ // There is no consent
224
+ return {
225
+ id: undefined,
226
+ reason: 'NO_CLIENT_CONSENT',
227
+ };
228
+ }
229
+ }
197
230
 
198
- if (!refreshNeeded) {
231
+ if (!hasExpiredPanoId) {
199
232
  return {
200
233
  id: localCache.data,
201
234
  };
@@ -203,6 +236,18 @@ export const lotamePanoramaIdSubmodule = {
203
236
 
204
237
  const storedUserId = getProfileId();
205
238
 
239
+ // Add CCPA Consent data handling
240
+ const usp = uspDataHandler.getConsentData();
241
+
242
+ let usPrivacy;
243
+ if (typeof usp !== 'undefined' && !isEmpty(usp) && !isEmptyStr(usp)) {
244
+ usPrivacy = usp;
245
+ }
246
+ if (!usPrivacy) {
247
+ // fallback to 1st party cookie
248
+ usPrivacy = getFromStorage('us_privacy');
249
+ }
250
+
206
251
  const resolveIdFunction = function (callback) {
207
252
  let queryParams = {};
208
253
  if (storedUserId) {
@@ -226,6 +271,17 @@ export const lotamePanoramaIdSubmodule = {
226
271
  if (consentString) {
227
272
  queryParams.gdpr_consent = consentString;
228
273
  }
274
+
275
+ // Add usPrivacy to the url
276
+ if (usPrivacy) {
277
+ queryParams.us_privacy = usPrivacy;
278
+ }
279
+
280
+ // Add clientId to the url
281
+ if (hasCustomClientId) {
282
+ queryParams.c = clientId;
283
+ }
284
+
229
285
  const url = buildUrl({
230
286
  protocol: 'https',
231
287
  host: `id.crwdcntrl.net`,
@@ -239,15 +295,31 @@ export const lotamePanoramaIdSubmodule = {
239
295
  if (response) {
240
296
  try {
241
297
  let responseObj = JSON.parse(response);
242
- const shouldUpdateProfileId = !(
298
+ const hasNoConsentErrors = !(
243
299
  isArray(responseObj.errors) &&
244
300
  responseObj.errors.indexOf(MISSING_CORE_CONSENT) !== -1
245
301
  );
246
302
 
303
+ if (hasCustomClientId) {
304
+ if (hasNoConsentErrors) {
305
+ clearLotameCache(`${KEY_EXPIRY}_${clientId}`);
306
+ } else if (isStr(responseObj.no_consent) && responseObj.no_consent === 'CLIENT') {
307
+ saveLotameCache(
308
+ `${KEY_EXPIRY}_${clientId}`,
309
+ responseObj.expiry_ts,
310
+ responseObj.expiry_ts
311
+ );
312
+
313
+ // End Processing
314
+ callback();
315
+ return;
316
+ }
317
+ }
318
+
247
319
  saveLotameCache(KEY_EXPIRY, responseObj.expiry_ts, responseObj.expiry_ts);
248
320
 
249
321
  if (isStr(responseObj.profile_id)) {
250
- if (shouldUpdateProfileId) {
322
+ if (hasNoConsentErrors) {
251
323
  setProfileId(responseObj.profile_id);
252
324
  }
253
325
 
@@ -262,7 +334,7 @@ export const lotamePanoramaIdSubmodule = {
262
334
  clearLotameCache(KEY_ID);
263
335
  }
264
336
  } else {
265
- if (shouldUpdateProfileId) {
337
+ if (hasNoConsentErrors) {
266
338
  clearLotameCache(KEY_PROFILE);
267
339
  }
268
340
  clearLotameCache(KEY_ID);