prebid.js 7.40.0 → 7.41.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 (167) hide show
  1. package/dist/33acrossBidAdapter.js +1 -1
  2. package/dist/33acrossIdSystem.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/adrelevantisBidAdapter.js +1 -1
  7. package/dist/adtrgtmeBidAdapter.js +1 -1
  8. package/dist/aduptechBidAdapter.js +1 -1
  9. package/dist/adxcgBidAdapter.js +1 -1
  10. package/dist/adyoulikeBidAdapter.js +1 -1
  11. package/dist/ajaBidAdapter.js +1 -1
  12. package/dist/amxBidAdapter.js +1 -1
  13. package/dist/amxIdSystem.js +1 -1
  14. package/dist/appierAnalyticsAdapter.js +1 -1
  15. package/dist/appnexusBidAdapter.js +1 -1
  16. package/dist/asoBidAdapter.js +1 -1
  17. package/dist/axonixBidAdapter.js +1 -1
  18. package/dist/bidglassBidAdapter.js +1 -1
  19. package/dist/big-richmediaBidAdapter.js +1 -1
  20. package/dist/bridgewellBidAdapter.js +1 -1
  21. package/dist/brightMountainMediaBidAdapter.js +1 -1
  22. package/dist/browsiBidAdapter.js +1 -0
  23. package/dist/carodaBidAdapter.js +1 -1
  24. package/dist/chtnwBidAdapter.js +1 -1
  25. package/dist/cleanmedianetBidAdapter.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/conversantAnalyticsAdapter.js +1 -1
  30. package/dist/conversantBidAdapter.js +1 -1
  31. package/dist/craftBidAdapter.js +1 -1
  32. package/dist/criteoBidAdapter.js +1 -1
  33. package/dist/cwireBidAdapter.js +1 -1
  34. package/dist/dfpAdServerVideo.js +1 -1
  35. package/dist/dspxBidAdapter.js +1 -1
  36. package/dist/eplanningBidAdapter.js +1 -1
  37. package/dist/feedadBidAdapter.js +1 -1
  38. package/dist/finativeBidAdapter.js +1 -1
  39. package/dist/freewheel-sspBidAdapter.js +1 -1
  40. package/dist/glimpseBidAdapter.js +1 -1
  41. package/dist/gmosspBidAdapter.js +1 -1
  42. package/dist/goldbachBidAdapter.js +1 -1
  43. package/dist/gridBidAdapter.js +1 -1
  44. package/dist/gridNMBidAdapter.js +1 -1
  45. package/dist/gumgumBidAdapter.js +1 -1
  46. package/dist/h12mediaBidAdapter.js +1 -1
  47. package/dist/id5IdSystem.js +1 -1
  48. package/dist/improvedigitalBidAdapter.js +1 -1
  49. package/dist/inmarBidAdapter.js +1 -1
  50. package/dist/insticatorBidAdapter.js +1 -1
  51. package/dist/ixBidAdapter.js +1 -1
  52. package/dist/justpremiumBidAdapter.js +1 -1
  53. package/dist/kargoBidAdapter.js +1 -1
  54. package/dist/konduitAnalyticsAdapter.js +1 -1
  55. package/dist/kueezBidAdapter.js +1 -1
  56. package/dist/kueezRtbBidAdapter.js +1 -1
  57. package/dist/lassoBidAdapter.js +1 -1
  58. package/dist/lifestreetBidAdapter.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/magniteAnalyticsAdapter.js +1 -1
  63. package/dist/malltvAnalyticsAdapter.js +1 -1
  64. package/dist/marsmediaBidAdapter.js +1 -1
  65. package/dist/mediafuseBidAdapter.js +1 -1
  66. package/dist/mediasquareBidAdapter.js +1 -1
  67. package/dist/mgidBidAdapter.js +1 -1
  68. package/dist/minutemediaBidAdapter.js +1 -1
  69. package/dist/minutemediaplusBidAdapter.js +1 -1
  70. package/dist/missenaBidAdapter.js +1 -1
  71. package/dist/nexx360BidAdapter.js +1 -1
  72. package/dist/nobidBidAdapter.js +1 -1
  73. package/dist/not-for-prod/prebid.js +130 -129
  74. package/dist/oguryBidAdapter.js +1 -1
  75. package/dist/onetagBidAdapter.js +1 -1
  76. package/dist/ooloAnalyticsAdapter.js +1 -1
  77. package/dist/optidigitalBidAdapter.js +1 -1
  78. package/dist/outbrainBidAdapter.js +1 -1
  79. package/dist/parrableIdSystem.js +1 -1
  80. package/dist/permutiveRtdProvider.js +1 -1
  81. package/dist/pixfutureBidAdapter.js +1 -1
  82. package/dist/prebid-core.js +1 -1
  83. package/dist/publinkIdSystem.js +1 -1
  84. package/dist/pubmaticBidAdapter.js +1 -1
  85. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  86. package/dist/pubwiseBidAdapter.js +1 -1
  87. package/dist/pxyzBidAdapter.js +1 -1
  88. package/dist/quantcastBidAdapter.js +1 -1
  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/sharethroughAnalyticsAdapter.js +1 -1
  98. package/dist/sharethroughBidAdapter.js +1 -1
  99. package/dist/shinezBidAdapter.js +1 -1
  100. package/dist/smaatoBidAdapter.js +1 -1
  101. package/dist/smartadserverBidAdapter.js +1 -1
  102. package/dist/smartxBidAdapter.js +1 -1
  103. package/dist/smilewantedBidAdapter.js +1 -1
  104. package/dist/sonobiBidAdapter.js +1 -1
  105. package/dist/sovrnAnalyticsAdapter.js +1 -1
  106. package/dist/sovrnBidAdapter.js +1 -1
  107. package/dist/sspBCBidAdapter.js +1 -1
  108. package/dist/stvBidAdapter.js +1 -0
  109. package/dist/sublimeBidAdapter.js +1 -1
  110. package/dist/synacormediaBidAdapter.js +1 -1
  111. package/dist/targetVideoBidAdapter.js +1 -1
  112. package/dist/teadsBidAdapter.js +1 -1
  113. package/dist/trionBidAdapter.js +1 -1
  114. package/dist/tripleliftBidAdapter.js +1 -1
  115. package/dist/ttdBidAdapter.js +1 -1
  116. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  117. package/dist/uid2IdSystem.js +1 -1
  118. package/dist/underdogmediaBidAdapter.js +1 -1
  119. package/dist/undertoneBidAdapter.js +1 -1
  120. package/dist/vidazooBidAdapter.js +1 -1
  121. package/dist/videobyteBidAdapter.js +1 -1
  122. package/dist/visxBidAdapter.js +1 -1
  123. package/dist/vuukleBidAdapter.js +1 -1
  124. package/dist/widespaceBidAdapter.js +1 -1
  125. package/dist/winrBidAdapter.js +1 -1
  126. package/dist/yahoosspBidAdapter.js +1 -1
  127. package/dist/yandexBidAdapter.js +1 -1
  128. package/dist/yieldmoBidAdapter.js +1 -1
  129. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  130. package/integrationExamples/gpt/x-domain/creative.html +1 -1
  131. package/modules/aduptechBidAdapter.js +43 -37
  132. package/modules/browsiBidAdapter.js +171 -0
  133. package/modules/browsiBidAdapter.md +38 -0
  134. package/modules/cleanmedianetBidAdapter.js +191 -126
  135. package/modules/cleanmedianetBidAdapter.md +64 -18
  136. package/modules/conversantBidAdapter.js +4 -0
  137. package/modules/dfpAdServerVideo.js +8 -8
  138. package/modules/freewheel-sspBidAdapter.js +9 -0
  139. package/modules/gridBidAdapter.js +12 -1
  140. package/modules/ixBidAdapter.js +1 -1
  141. package/modules/missenaBidAdapter.js +2 -1
  142. package/modules/neuwoRtdProvider.js +1 -1
  143. package/modules/nobidBidAdapter.js +13 -2
  144. package/modules/nobidBidAdapter.md +2 -2
  145. package/modules/permutiveRtdProvider.js +8 -2
  146. package/modules/pubwiseBidAdapter.js +265 -33
  147. package/modules/stvBidAdapter.js +330 -0
  148. package/modules/stvBidAdapter.md +62 -0
  149. package/modules/yandexBidAdapter.js +259 -71
  150. package/modules/yandexBidAdapter.md +52 -15
  151. package/package.json +1 -1
  152. package/src/videoCache.js +4 -4
  153. package/test/spec/modules/browsiBidAdapter_spec.js +209 -0
  154. package/test/spec/modules/cleanmedianetBidAdapter_spec.js +462 -407
  155. package/test/spec/modules/conversantBidAdapter_spec.js +8 -0
  156. package/test/spec/modules/dfpAdServerVideo_spec.js +36 -4
  157. package/test/spec/modules/freewheel-sspBidAdapter_spec.js +19 -0
  158. package/test/spec/modules/gridBidAdapter_spec.js +24 -0
  159. package/test/spec/modules/ixBidAdapter_spec.js +4 -4
  160. package/test/spec/modules/nobidBidAdapter_spec.js +32 -0
  161. package/test/spec/modules/permutiveRtdProvider_spec.js +61 -4
  162. package/test/spec/modules/pubwiseBidAdapter_spec.js +313 -3
  163. package/test/spec/modules/stvBidAdapter_spec.js +402 -0
  164. package/test/spec/modules/yandexBidAdapter_spec.js +315 -45
  165. package/test/spec/videoCache_spec.js +23 -0
  166. package/dist/flocIdSystem.js +0 -1
  167. package/modules/flocIdSystem.js +0 -0
@@ -90,7 +90,7 @@ export const spec = {
90
90
  let userExt = null;
91
91
  let endpoint = null;
92
92
  let forceBidderName = false;
93
- let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo} = bidderRequest || {};
93
+ let {bidderRequestId, auctionId, gdprConsent, uspConsent, timeout, refererInfo, gppConsent} = bidderRequest || {};
94
94
 
95
95
  const referer = refererInfo ? encodeURIComponent(refererInfo.page) : '';
96
96
  const tmax = timeout || config.getConfig('bidderTimeout');
@@ -340,11 +340,22 @@ export const spec = {
340
340
  }
341
341
  };
342
342
  }
343
+ const ortb2Regs = deepAccess(bidderRequest, 'ortb2.regs') || {};
344
+ if (gppConsent || ortb2Regs?.gpp) {
345
+ const gpp = {
346
+ gpp: gppConsent?.gppString ?? ortb2Regs?.gpp,
347
+ gpp_sid: gppConsent?.applicableSections ?? ortb2Regs?.gpp_sid
348
+ };
349
+ request.regs = mergeDeep(request?.regs ?? {}, gpp);
350
+ }
343
351
 
344
352
  if (uspConsent) {
345
353
  if (!request.regs) {
346
354
  request.regs = {ext: {}};
347
355
  }
356
+ if (!request.regs.ext) {
357
+ request.regs.ext = {};
358
+ }
348
359
  request.regs.ext.us_privacy = uspConsent;
349
360
  }
350
361
 
@@ -833,7 +833,7 @@ function applyRegulations(r, bidderRequest) {
833
833
 
834
834
  if (gdprConsent.hasOwnProperty('addtlConsent') && gdprConsent.addtlConsent) {
835
835
  r.user.ext.consented_providers_settings = {
836
- consented_providers: gdprConsent.addtlConsent
836
+ addtl_consent: gdprConsent.addtlConsent
837
837
  };
838
838
  }
839
839
  }
@@ -60,6 +60,7 @@ export const spec = {
60
60
  if (bidRequest.params.isInternal) {
61
61
  payload.is_internal = bidRequest.params.isInternal;
62
62
  }
63
+ payload.userEids = bidRequest.userIdAsEids || [];
63
64
  return {
64
65
  method: 'POST',
65
66
  url: baseUrl + '?' + formatQS({ t: bidRequest.params.apiKey }),
@@ -127,7 +128,7 @@ export const spec = {
127
128
  protocol: 'https',
128
129
  hostname,
129
130
  pathname: '/v1/bidsuccess',
130
- search: { t: bid.params[0].apiKey },
131
+ search: { t: bid.params[0].apiKey, provider: bid.meta?.networkName, cpm: bid.cpm, currency: bid.currency },
131
132
  })
132
133
  );
133
134
  logInfo('Missena - Bid won', bid);
@@ -11,7 +11,7 @@ const CATTAX_IAB = 6 // IAB Tech Lab Content Taxonomy 2.2
11
11
  const RESPONSE_IAB_TIER_1 = 'marketing_categories.iab_tier_1'
12
12
  const RESPONSE_IAB_TIER_2 = 'marketing_categories.iab_tier_2'
13
13
 
14
- function init(config = {}, userConsent = '') {
14
+ function init(config = {}, userConsent) {
15
15
  config.params = config.params || {}
16
16
  // ignore module if publicToken is missing (module setup failure)
17
17
  if (!config.params.publicToken) {
@@ -8,7 +8,7 @@ import {hasPurpose1Consent} from '../src/utils/gpdr.js';
8
8
  const GVLID = 816;
9
9
  const BIDDER_CODE = 'nobid';
10
10
  const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE});
11
- window.nobidVersion = '1.3.2';
11
+ window.nobidVersion = '1.3.3';
12
12
  window.nobid = window.nobid || {};
13
13
  window.nobid.bidResponses = window.nobid.bidResponses || {};
14
14
  window.nobid.timeoutTotal = 0;
@@ -175,6 +175,9 @@ function nobidBuildRequests(bids, bidderRequest) {
175
175
  if (adunitObject.div) {
176
176
  a.d = adunitObject.div;
177
177
  }
178
+ if (adunitObject.floor) {
179
+ a.floor = adunitObject.floor;
180
+ }
178
181
  if (adunitObject.targeting) {
179
182
  a.g = adunitObject.targeting;
180
183
  } else {
@@ -201,6 +204,12 @@ function nobidBuildRequests(bids, bidderRequest) {
201
204
  adunits.push(a);
202
205
  return adunits;
203
206
  }
207
+ function getFloor (bid) {
208
+ if (bid && typeof bid.getFloor === 'function' && bid.getFloor().floor) {
209
+ return bid.getFloor().floor;
210
+ }
211
+ return null;
212
+ }
204
213
  if (typeof window.nobid.refreshLimit !== 'undefined') {
205
214
  if (window.nobid.refreshLimit < window.nobid.refreshCount) return false;
206
215
  }
@@ -227,6 +236,7 @@ function nobidBuildRequests(bids, bidderRequest) {
227
236
  if (bid.mediaType === VIDEO || (videoMediaType && (context === 'instream' || context === 'outstream'))) {
228
237
  adType = 'video';
229
238
  }
239
+ const floor = getFloor(bid);
230
240
 
231
241
  if (siteId) {
232
242
  newAdunit({
@@ -235,7 +245,8 @@ function nobidBuildRequests(bids, bidderRequest) {
235
245
  siteId: siteId,
236
246
  placementId: placementId,
237
247
  ad_type: adType,
238
- params: bid.params
248
+ params: bid.params,
249
+ floor: floor
239
250
  },
240
251
  adunits);
241
252
  }
@@ -4,7 +4,7 @@ title: Nobid
4
4
  description: Prebid Nobid Bidder Adaptor
5
5
  biddercode: nobid
6
6
  hide: true
7
- media_types: banner
7
+ media_types: banner, video
8
8
  gdpr_supported: true
9
9
  usp_supported: true
10
10
  ---
@@ -51,4 +51,4 @@ usp_supported: true
51
51
  ]
52
52
  }
53
53
  ];
54
- ```
54
+ ```
@@ -146,12 +146,17 @@ function updateOrtbConfig(bidder, currConfig, segmentIDs, sspSegmentIDs, transfo
146
146
  .filter(({ id }) => ortb2UserDataTransformations.hasOwnProperty(id))
147
147
  .map(({ id, config }) => ortb2UserDataTransformations[id](permutiveUserData, config))
148
148
 
149
+ const customCohortsUserData = {
150
+ name: PERMUTIVE_CUSTOM_COHORTS_KEYWORD,
151
+ segment: customCohortsData.map(cohortID => ({ id: cohortID })),
152
+ }
153
+
149
154
  const ortbConfig = mergeDeep({}, currConfig)
150
155
  const currentUserData = deepAccess(ortbConfig, 'ortb2.user.data') || []
151
156
 
152
157
  const updatedUserData = currentUserData
153
- .filter(el => el.name !== name)
154
- .concat(permutiveUserData, transformedUserData)
158
+ .filter(el => el.name !== permutiveUserData.name && el.name !== customCohortsUserData.name)
159
+ .concat(permutiveUserData, transformedUserData, customCohortsUserData)
155
160
 
156
161
  deepSetValue(ortbConfig, 'ortb2.user.data', updatedUserData)
157
162
 
@@ -311,6 +316,7 @@ export function getSegments (maxSegs) {
311
316
 
312
317
  const segments = {
313
318
  ac: [..._pcrprs, ..._ppam, ...legacySegs],
319
+ ix: readSegments('_pindexs', []),
314
320
  rubicon: readSegments('_prubicons', []),
315
321
  appnexus: readSegments('_papns', []),
316
322
  gam: readSegments('_pdfps', []),
@@ -1,19 +1,32 @@
1
- import { _each, isStr, deepClone, isArray, deepSetValue, inIframe, logMessage, logInfo, logWarn, logError } from '../src/utils.js';
2
- import { config } from '../src/config.js';
1
+
2
+ import { _each, isBoolean, isEmptyStr, isNumber, isStr, deepClone, isArray, deepSetValue, inIframe, mergeDeep, deepAccess, logMessage, logInfo, logWarn, logError } from '../src/utils.js';
3
3
  import { registerBidder } from '../src/adapters/bidderFactory.js';
4
- import { BANNER, NATIVE } from '../src/mediaTypes.js';
5
- const VERSION = '0.2.0';
4
+ import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js';
5
+ import { config } from '../src/config.js';
6
+ import { convertOrtbRequestToProprietaryNative } from '../src/native.js';
7
+ import { OUTSTREAM, INSTREAM } from '../src/video.js';
8
+
9
+ const VERSION = '0.3.0';
6
10
  const GVLID = 842;
7
11
  const NET_REVENUE = true;
8
12
  const UNDEFINED = undefined;
9
13
  const DEFAULT_CURRENCY = 'USD';
10
14
  const AUCTION_TYPE = 1;
11
15
  const BIDDER_CODE = 'pwbid';
16
+ const LOG_PREFIX = 'PubWise: ';
12
17
  const ENDPOINT_URL = 'https://bid.pubwise.io/prebid';
18
+ // const ENDPOINT_URL = 'https://bid.pubwise.io/prebid'; // testing observable endpoint
13
19
  const DEFAULT_WIDTH = 0;
14
20
  const DEFAULT_HEIGHT = 0;
15
21
  const PREBID_NATIVE_HELP_LINK = 'https://prebid.org/dev-docs/show-native-ads.html';
16
22
  // const USERSYNC_URL = '//127.0.0.1:8080/usersync'
23
+ const MSG_VIDEO_PLACEMENT_MISSING = 'Video.Placement param missing';
24
+
25
+ const MEDIATYPE = [
26
+ BANNER,
27
+ VIDEO,
28
+ NATIVE
29
+ ]
17
30
 
18
31
  const CUSTOM_PARAMS = {
19
32
  'gender': '', // User gender
@@ -22,6 +35,32 @@ const CUSTOM_PARAMS = {
22
35
  'lon': '', // User Location - Longitude
23
36
  };
24
37
 
38
+ const DATA_TYPES = {
39
+ 'NUMBER': 'number',
40
+ 'STRING': 'string',
41
+ 'BOOLEAN': 'boolean',
42
+ 'ARRAY': 'array',
43
+ 'OBJECT': 'object'
44
+ };
45
+
46
+ const VIDEO_CUSTOM_PARAMS = {
47
+ 'mimes': DATA_TYPES.ARRAY,
48
+ 'minduration': DATA_TYPES.NUMBER,
49
+ 'maxduration': DATA_TYPES.NUMBER,
50
+ 'startdelay': DATA_TYPES.NUMBER,
51
+ 'playbackmethod': DATA_TYPES.ARRAY,
52
+ 'api': DATA_TYPES.ARRAY,
53
+ 'protocols': DATA_TYPES.ARRAY,
54
+ 'w': DATA_TYPES.NUMBER,
55
+ 'h': DATA_TYPES.NUMBER,
56
+ 'battr': DATA_TYPES.ARRAY,
57
+ 'linearity': DATA_TYPES.NUMBER,
58
+ 'placement': DATA_TYPES.NUMBER,
59
+ 'minbitrate': DATA_TYPES.NUMBER,
60
+ 'maxbitrate': DATA_TYPES.NUMBER,
61
+ 'skip': DATA_TYPES.NUMBER
62
+ }
63
+
25
64
  // rtb native types are meant to be dynamic and extendable
26
65
  // the extendable data asset types are nicely aligned
27
66
  // in practice we set an ID that is distinct for each real type of return
@@ -88,7 +127,7 @@ _each(NATIVE_ASSETS, anAsset => { NATIVE_ASSET_KEY_TO_ASSET_MAP[anAsset.KEY] = a
88
127
  export const spec = {
89
128
  code: BIDDER_CODE,
90
129
  gvlid: GVLID,
91
- supportedMediaTypes: [BANNER, NATIVE],
130
+ supportedMediaTypes: [BANNER, VIDEO, NATIVE],
92
131
  /**
93
132
  * Determines whether or not the given bid request is valid.
94
133
  *
@@ -96,18 +135,40 @@ export const spec = {
96
135
  * @return boolean True if this is a valid bid, and false otherwise.
97
136
  */
98
137
  isBidRequestValid: function (bid) {
99
- // siteId is required
138
+ // siteId is required for any type
100
139
  if (bid.params && bid.params.siteId) {
101
140
  // it must be a string
102
141
  if (!isStr(bid.params.siteId)) {
103
142
  _logWarn('siteId is required for bid', bid);
104
143
  return false;
105
144
  }
106
- } else {
107
- return false;
145
+
146
+ // video ad validation
147
+ if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) {
148
+ // bid.mediaTypes.video.mimes OR bid.params.video.mimes should be present and must be a non-empty array
149
+ let mediaTypesVideoMimes = deepAccess(bid.mediaTypes, 'video.mimes');
150
+ let paramsVideoMimes = deepAccess(bid, 'params.video.mimes');
151
+ if (_isNonEmptyArray(mediaTypesVideoMimes) === false && _isNonEmptyArray(paramsVideoMimes) === false) {
152
+ _logWarn('Error: For video ads, bid.mediaTypes.video.mimes OR bid.params.video.mimes should be present and must be a non-empty array. Call suppressed:', JSON.stringify(bid));
153
+ return false;
154
+ }
155
+
156
+ if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) {
157
+ _logError(`no context specified in bid. Rejecting bid: `, JSON.stringify(bid));
158
+ return false;
159
+ }
160
+
161
+ if (bid.mediaTypes[VIDEO].context === 'outstream') {
162
+ delete bid.mediaTypes[VIDEO];
163
+ _logWarn(`outstream not currently supported `, JSON.stringify(bid));
164
+ return false;
165
+ }
166
+ }
167
+
168
+ return true;
108
169
  }
109
170
 
110
- return true;
171
+ return false;
111
172
  },
112
173
  /**
113
174
  * Make a server request from the list of BidRequests.
@@ -116,6 +177,7 @@ export const spec = {
116
177
  * @return ServerRequest Info describing the request to the server.
117
178
  */
118
179
  buildRequests: function (validBidRequests, bidderRequest) {
180
+ validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
119
181
  var refererInfo;
120
182
  if (bidderRequest && bidderRequest.refererInfo) {
121
183
  refererInfo = bidderRequest.refererInfo;
@@ -210,7 +272,7 @@ export const spec = {
210
272
 
211
273
  return {
212
274
  method: 'POST',
213
- url: ENDPOINT_URL,
275
+ url: _getEndpointURL(bid),
214
276
  data: payload,
215
277
  options: options,
216
278
  bidderRequest: bidderRequest,
@@ -231,6 +293,7 @@ export const spec = {
231
293
 
232
294
  // try {
233
295
  if (response.body && response.body.seatbid && isArray(response.body.seatbid)) {
296
+ _logInfo('interpretResponse response body', response.body);
234
297
  // Supporting multiple bid responses for same adSize
235
298
  respCur = response.body.cur || respCur;
236
299
  response.body.seatbid.forEach(seatbidder => {
@@ -254,10 +317,24 @@ export const spec = {
254
317
  if (parsedRequest.imp && parsedRequest.imp.length > 0) {
255
318
  parsedRequest.imp.forEach(req => {
256
319
  if (bid.impid === req.id) {
257
- _checkMediaType(bid.adm, newBid);
320
+ _checkMediaType(bid, newBid);
258
321
  switch (newBid.mediaType) {
259
322
  case BANNER:
260
323
  break;
324
+ case VIDEO:
325
+ const videoContext = deepAccess(request, 'mediaTypes.video.context');
326
+ switch (videoContext) {
327
+ case OUTSTREAM:
328
+ // not currently supported
329
+ break;
330
+ case INSTREAM:
331
+ break;
332
+ }
333
+ newBid.width = bid.hasOwnProperty('w') ? bid.w : req.video.w;
334
+ newBid.height = bid.hasOwnProperty('h') ? bid.h : req.video.h;
335
+ newBid.vastXml = bid.adm;
336
+ newBid.vastUrl = bid.vastUrl;
337
+ break;
261
338
  case NATIVE:
262
339
  _parseNativeResponse(bid, newBid);
263
340
  break;
@@ -289,20 +366,31 @@ export const spec = {
289
366
  }
290
367
  }
291
368
 
292
- function _checkMediaType(adm, newBid) {
293
- // Create a regex here to check the strings
294
- var admJSON = '';
295
- if (adm.indexOf('"ver":') >= 0) {
296
- try {
297
- admJSON = JSON.parse(adm.replace(/\\/g, ''));
298
- if (admJSON && admJSON.assets) {
299
- newBid.mediaType = NATIVE;
369
+ function _checkMediaType(bid, newBid) {
370
+ // Check Various ADM Aspects to Determine Media Type
371
+ if (bid.ext && bid.ext['bidtype'] != undefined) {
372
+ // this is the most explicity check
373
+ newBid.mediaType = MEDIATYPE[bid.ext.bidtype];
374
+ } else {
375
+ _logInfo('bid.ext.bidtype does not exist, checking alternatively for mediaType');
376
+ var adm = bid.adm;
377
+ var videoRegex = new RegExp(/VAST\s+version/);
378
+
379
+ if (adm.indexOf('"ver":') >= 0) {
380
+ try {
381
+ var admJSON = '';
382
+ admJSON = JSON.parse(adm.replace(/\\/g, ''));
383
+ if (admJSON && admJSON.assets) {
384
+ newBid.mediaType = NATIVE;
385
+ }
386
+ } catch (e) {
387
+ _logWarn('Error: Cannot parse native reponse for ad response: ', adm);
300
388
  }
301
- } catch (e) {
302
- _logWarn('Error: Cannot parse native reponse for ad response: ' + adm);
389
+ } else if (videoRegex.test(adm)) {
390
+ newBid.mediaType = VIDEO;
391
+ } else {
392
+ newBid.mediaType = BANNER;
303
393
  }
304
- } else {
305
- newBid.mediaType = BANNER;
306
394
  }
307
395
  }
308
396
 
@@ -416,7 +504,8 @@ function _createOrtbTemplate(conf) {
416
504
  dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0,
417
505
  h: screen.height,
418
506
  w: screen.width,
419
- language: navigator.language
507
+ language: navigator.language,
508
+ devicetype: _getDeviceType()
420
509
  },
421
510
  user: {},
422
511
  ext: {
@@ -428,6 +517,7 @@ function _createOrtbTemplate(conf) {
428
517
  function _createImpressionObject(bid, conf) {
429
518
  var impObj = {};
430
519
  var bannerObj;
520
+ var videoObj;
431
521
  var nativeObj = {};
432
522
  var mediaTypes = '';
433
523
 
@@ -459,6 +549,12 @@ function _createImpressionObject(bid, conf) {
459
549
  _logWarn('Error: Error in Native adunit ' + bid.params.adUnit + '. Ignoring the adunit. Refer to ' + PREBID_NATIVE_HELP_LINK + ' for more details.');
460
550
  }
461
551
  break;
552
+ case VIDEO:
553
+ videoObj = _createVideoRequest(bid);
554
+ if (videoObj !== UNDEFINED) {
555
+ impObj.video = videoObj;
556
+ }
557
+ break;
462
558
  }
463
559
  }
464
560
  } else {
@@ -468,7 +564,8 @@ function _createImpressionObject(bid, conf) {
468
564
  _addFloorFromFloorModule(impObj, bid);
469
565
 
470
566
  return impObj.hasOwnProperty(BANNER) ||
471
- impObj.hasOwnProperty(NATIVE) ? impObj : UNDEFINED;
567
+ impObj.hasOwnProperty(NATIVE) ||
568
+ impObj.hasOwnProperty(VIDEO) ? impObj : UNDEFINED;
472
569
  }
473
570
 
474
571
  function _parseSlotParam(paramName, paramValue) {
@@ -492,7 +589,7 @@ function _parseSlotParam(paramName, paramValue) {
492
589
  }
493
590
 
494
591
  function _parseAdSlot(bid) {
495
- _logInfo('parseAdSlot bid', bid)
592
+ _logInfo('parseAdSlot bid', bid);
496
593
  if (bid.adUnitCode) {
497
594
  bid.params.adUnit = bid.adUnitCode;
498
595
  } else {
@@ -504,7 +601,7 @@ function _parseAdSlot(bid) {
504
601
 
505
602
  if (bid.hasOwnProperty('mediaTypes')) {
506
603
  if (bid.mediaTypes.hasOwnProperty(BANNER) &&
507
- bid.mediaTypes.banner.hasOwnProperty('sizes')) { // if its a banner, has mediaTypes and sizes
604
+ bid.mediaTypes.banner.hasOwnProperty('sizes')) { // if its a banner, has mediaTypes and sizes
508
605
  var i = 0;
509
606
  var sizeArray = [];
510
607
  for (;i < bid.mediaTypes.banner.sizes.length; i++) {
@@ -522,7 +619,7 @@ function _parseAdSlot(bid) {
522
619
  }
523
620
  }
524
621
  } else {
525
- _logWarn('MediaTypes are Required for all Adunit Configs', bid)
622
+ _logWarn('MediaTypes are Required for all Adunit Configs', bid);
526
623
  }
527
624
  }
528
625
 
@@ -558,7 +655,7 @@ function _addFloorFromFloorModule(impObj, bid) {
558
655
 
559
656
  // get lowest floor from floorModule
560
657
  if (typeof bid.getFloor === 'function' && !config.getConfig('pubwise.disableFloors')) {
561
- [BANNER, NATIVE].forEach(mediaType => {
658
+ [BANNER, VIDEO, NATIVE].forEach(mediaType => {
562
659
  if (impObj.hasOwnProperty(mediaType)) {
563
660
  let floorInfo = bid.getFloor({ currency: impObj.bidFloorCur, mediaType: mediaType, size: '*' });
564
661
  if (typeof floorInfo === 'object' && floorInfo.currency === impObj.bidFloorCur && !isNaN(parseInt(floorInfo.floor))) {
@@ -746,28 +843,162 @@ function _createBannerRequest(bid) {
746
843
  _logWarn('Error: mediaTypes.banner.size missing for adunit: ' + bid.params.adUnit + '. Ignoring the banner impression in the adunit.');
747
844
  bannerObj = UNDEFINED;
748
845
  }
846
+
749
847
  return bannerObj;
750
848
  }
751
849
 
752
850
  // various error levels are not always used
753
851
  // eslint-disable-next-line no-unused-vars
754
852
  function _logMessage(textValue, objectValue) {
755
- logMessage('PubWise: ' + textValue, objectValue);
853
+ objectValue = objectValue || '';
854
+ logMessage(LOG_PREFIX + textValue, objectValue);
756
855
  }
757
856
 
758
857
  // eslint-disable-next-line no-unused-vars
759
858
  function _logInfo(textValue, objectValue) {
760
- logInfo('PubWise: ' + textValue, objectValue);
859
+ objectValue = objectValue || '';
860
+ logInfo(LOG_PREFIX + textValue, objectValue);
761
861
  }
762
862
 
763
863
  // eslint-disable-next-line no-unused-vars
764
864
  function _logWarn(textValue, objectValue) {
765
- logWarn('PubWise: ' + textValue, objectValue);
865
+ objectValue = objectValue || '';
866
+ logWarn(LOG_PREFIX + textValue, objectValue);
766
867
  }
767
868
 
768
869
  // eslint-disable-next-line no-unused-vars
769
870
  function _logError(textValue, objectValue) {
770
- logError('PubWise: ' + textValue, objectValue);
871
+ objectValue = objectValue || '';
872
+ logError(LOG_PREFIX + textValue, objectValue);
873
+ }
874
+
875
+ function _checkVideoPlacement(videoData, adUnitCode) {
876
+ // Check for video.placement property. If property is missing display log message.
877
+ if (!deepAccess(videoData, 'placement')) {
878
+ _logWarn(`${MSG_VIDEO_PLACEMENT_MISSING} for ${adUnitCode}`, adUnitCode);
879
+ };
880
+ }
881
+
882
+ function _createVideoRequest(bid) {
883
+ var videoData = mergeDeep(deepAccess(bid.mediaTypes, 'video'), bid.params.video);
884
+ var videoObj;
885
+
886
+ if (videoData !== UNDEFINED) {
887
+ videoObj = {};
888
+ _checkVideoPlacement(videoData, bid.adUnitCode);
889
+ for (var key in VIDEO_CUSTOM_PARAMS) {
890
+ if (videoData.hasOwnProperty(key)) {
891
+ videoObj[key] = _checkParamDataType(key, videoData[key], VIDEO_CUSTOM_PARAMS[key]);
892
+ }
893
+ }
894
+ // read playersize and assign to h and w.
895
+ if (isArray(bid.mediaTypes.video.playerSize[0])) {
896
+ videoObj.w = parseInt(bid.mediaTypes.video.playerSize[0][0], 10);
897
+ videoObj.h = parseInt(bid.mediaTypes.video.playerSize[0][1], 10);
898
+ } else if (isNumber(bid.mediaTypes.video.playerSize[0])) {
899
+ videoObj.w = parseInt(bid.mediaTypes.video.playerSize[0], 10);
900
+ videoObj.h = parseInt(bid.mediaTypes.video.playerSize[1], 10);
901
+ }
902
+ } else {
903
+ videoObj = UNDEFINED;
904
+ _logWarn('Error: Video config params missing for adunit: ' + bid.params.adUnit + ' with mediaType set as video. Ignoring video impression in the adunit.', bid.params);
905
+ }
906
+ return videoObj;
907
+ }
908
+
909
+ /**
910
+ * Determines if the array has values
911
+ *
912
+ * @param {object} test
913
+ * @returns {boolean}
914
+ */
915
+ function _isNonEmptyArray(test) {
916
+ if (isArray(test) === true) {
917
+ if (test.length > 0) {
918
+ return true;
919
+ }
920
+ }
921
+ return false;
922
+ }
923
+
924
+ /**
925
+ * Returns the overridden bid endpoint_url if it is set, primarily used for testing
926
+ *
927
+ * @param {object} bid the current bid
928
+ * @returns
929
+ */
930
+ function _getEndpointURL(bid) {
931
+ if (!isEmptyStr(bid?.params?.endpoint_url) && bid?.params?.endpoint_url != UNDEFINED) {
932
+ return bid.params.endpoint_url;
933
+ }
934
+
935
+ return ENDPOINT_URL;
936
+ }
937
+
938
+ /**
939
+ *
940
+ * @param {object} key
941
+ * @param {object}} value
942
+ * @param {object} datatype
943
+ * @returns
944
+ */
945
+ function _checkParamDataType(key, value, datatype) {
946
+ var errMsg = 'Ignoring param key: ' + key + ', expects ' + datatype + ', found ' + typeof value;
947
+ var functionToExecute;
948
+ switch (datatype) {
949
+ case DATA_TYPES.BOOLEAN:
950
+ functionToExecute = isBoolean;
951
+ break;
952
+ case DATA_TYPES.NUMBER:
953
+ functionToExecute = isNumber;
954
+ break;
955
+ case DATA_TYPES.STRING:
956
+ functionToExecute = isStr;
957
+ break;
958
+ case DATA_TYPES.ARRAY:
959
+ functionToExecute = isArray;
960
+ break;
961
+ }
962
+ if (functionToExecute(value)) {
963
+ return value;
964
+ }
965
+ _logWarn(errMsg, key);
966
+ return UNDEFINED;
967
+ }
968
+
969
+ function _isMobile() {
970
+ if (navigator.userAgentData && navigator.userAgentData.mobile) {
971
+ return true;
972
+ } else {
973
+ return (/(mobi)/i).test(navigator.userAgent);
974
+ }
975
+ }
976
+
977
+ function _isConnectedTV() {
978
+ return (/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(navigator.userAgent);
979
+ }
980
+
981
+ function _isTablet() {
982
+ return (/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()));
983
+ }
984
+
985
+ /**
986
+ * Very high level device detection, order matters
987
+ */
988
+ function _getDeviceType() {
989
+ if (_isTablet()) {
990
+ return 5;
991
+ }
992
+
993
+ if (_isMobile()) {
994
+ return 4;
995
+ }
996
+
997
+ if (_isConnectedTV()) {
998
+ return 3;
999
+ }
1000
+
1001
+ return 2;
771
1002
  }
772
1003
 
773
1004
  // function _decorateLog() {
@@ -777,6 +1008,7 @@ function _logError(textValue, objectValue) {
777
1008
 
778
1009
  // these are exported only for testing so maintaining the JS convention of _ to indicate the intent
779
1010
  export {
1011
+ _checkVideoPlacement,
780
1012
  _checkMediaType,
781
1013
  _parseAdSlot
782
1014
  }