prebid.js 9.53.2 → 9.53.4

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 (229) hide show
  1. package/dist/33acrossAnalyticsAdapter.js +1 -1
  2. package/dist/33acrossBidAdapter.js +1 -1
  3. package/dist/33acrossIdSystem.js +1 -1
  4. package/dist/BTBidAdapter.js +1 -1
  5. package/dist/adagioAnalyticsAdapter.js +1 -1
  6. package/dist/adagioBidAdapter.js +1 -1
  7. package/dist/adagioRtdProvider.js +1 -1
  8. package/dist/adagioUtils.js +1 -1
  9. package/dist/addefendBidAdapter.js +1 -1
  10. package/dist/adgenerationBidAdapter.js +1 -1
  11. package/dist/adlooxRtdProvider.js +1 -1
  12. package/dist/adqueryBidAdapter.js +1 -1
  13. package/dist/adrelevantisBidAdapter.js +1 -1
  14. package/dist/adstirBidAdapter.js +1 -1
  15. package/dist/adtrgtmeBidAdapter.js +1 -1
  16. package/dist/adxcgAnalyticsAdapter.js +1 -1
  17. package/dist/adxcgBidAdapter.js +1 -1
  18. package/dist/adyoulikeBidAdapter.js +1 -1
  19. package/dist/agmaAnalyticsAdapter.js +1 -1
  20. package/dist/ajaBidAdapter.js +1 -1
  21. package/dist/amxBidAdapter.js +1 -1
  22. package/dist/amxIdSystem.js +1 -1
  23. package/dist/aniviewBidAdapter.js +1 -1
  24. package/dist/appierAnalyticsAdapter.js +1 -1
  25. package/dist/appnexusBidAdapter.js +1 -1
  26. package/dist/asoBidAdapter.js +1 -1
  27. package/dist/axonixBidAdapter.js +1 -1
  28. package/dist/beopBidAdapter.js +1 -1
  29. package/dist/bidderTimeoutUtils.js +1 -0
  30. package/dist/bidglassBidAdapter.js +1 -1
  31. package/dist/big-richmediaBidAdapter.js +1 -1
  32. package/dist/bitmediaBidAdapter.js +1 -1
  33. package/dist/bridBidAdapter.js +1 -1
  34. package/dist/bridgeuppBidAdapter.js +1 -1
  35. package/dist/bridgewellBidAdapter.js +1 -1
  36. package/dist/brightMountainMediaBidAdapter.js +1 -1
  37. package/dist/carodaBidAdapter.js +1 -1
  38. package/dist/chtnwBidAdapter.js +1 -1
  39. package/dist/chunk-core.js +1 -1
  40. package/dist/concertBidAdapter.js +1 -1
  41. package/dist/connectadBidAdapter.js +1 -1
  42. package/dist/consumableBidAdapter.js +1 -1
  43. package/dist/contxtfulBidAdapter.js +1 -1
  44. package/dist/conversantAnalyticsAdapter.js +1 -1
  45. package/dist/conversantBidAdapter.js +1 -1
  46. package/dist/craftBidAdapter.js +1 -1
  47. package/dist/criteoBidAdapter.js +1 -1
  48. package/dist/cwireBidAdapter.js +1 -1
  49. package/dist/dailymotionBidAdapter.js +1 -1
  50. package/dist/debugging-standalone.js +1 -1
  51. package/dist/dependencies.json +10 -1
  52. package/dist/dspxBidAdapter.js +1 -1
  53. package/dist/dxkultureBidAdapter.js +1 -1
  54. package/dist/eplanningBidAdapter.js +1 -1
  55. package/dist/equativBidAdapter.js +1 -1
  56. package/dist/eskimiBidAdapter.js +1 -1
  57. package/dist/euidIdSystem.js +1 -1
  58. package/dist/exadsBidAdapter.js +1 -1
  59. package/dist/excoBidAdapter.js +1 -1
  60. package/dist/feedadBidAdapter.js +1 -1
  61. package/dist/finativeBidAdapter.js +1 -1
  62. package/dist/freewheel-sspBidAdapter.js +1 -1
  63. package/dist/fwsspBidAdapter.js +1 -1
  64. package/dist/gmosspBidAdapter.js +1 -1
  65. package/dist/greenbidsAnalyticsAdapter.js +1 -1
  66. package/dist/greenbidsBidAdapter.js +1 -1
  67. package/dist/greenbidsRtdProvider.js +1 -1
  68. package/dist/gridBidAdapter.js +1 -1
  69. package/dist/gumgumBidAdapter.js +1 -1
  70. package/dist/h12mediaBidAdapter.js +1 -1
  71. package/dist/hypelabBidAdapter.js +1 -1
  72. package/dist/id5AnalyticsAdapter.js +1 -1
  73. package/dist/id5IdSystem.js +1 -1
  74. package/dist/imdsBidAdapter.js +1 -1
  75. package/dist/improvedigitalBidAdapter.js +1 -1
  76. package/dist/inmobiBidAdapter.js +1 -1
  77. package/dist/insticatorBidAdapter.js +1 -1
  78. package/dist/intentIqAnalyticsAdapter.js +1 -1
  79. package/dist/ixBidAdapter.js +1 -1
  80. package/dist/jixieBidAdapter.js +1 -1
  81. package/dist/justpremiumBidAdapter.js +1 -1
  82. package/dist/kargoBidAdapter.js +1 -1
  83. package/dist/kimberliteBidAdapter.js +1 -1
  84. package/dist/konduitAnalyticsAdapter.js +1 -1
  85. package/dist/kueezBidAdapter.js +1 -1
  86. package/dist/lassoBidAdapter.js +1 -1
  87. package/dist/lifestreetBidAdapter.js +1 -1
  88. package/dist/liveIntentId.js +1 -1
  89. package/dist/logicadBidAdapter.js +1 -1
  90. package/dist/loglyliftBidAdapter.js +1 -1
  91. package/dist/luceadBidAdapter.js +1 -1
  92. package/dist/mabidderBidAdapter.js +1 -1
  93. package/dist/madsenseBidAdapter.js +1 -1
  94. package/dist/magniteAnalyticsAdapter.js +1 -1
  95. package/dist/malltvAnalyticsAdapter.js +1 -1
  96. package/dist/marsmediaBidAdapter.js +1 -1
  97. package/dist/mediafuseBidAdapter.js +1 -1
  98. package/dist/medianetBidAdapter.js +1 -1
  99. package/dist/medianetUtils.js +1 -1
  100. package/dist/mediasquareBidAdapter.js +1 -1
  101. package/dist/mgidBidAdapter.js +1 -1
  102. package/dist/missenaBidAdapter.js +1 -1
  103. package/dist/mobilefuseBidAdapter.js +1 -1
  104. package/dist/nextMillenniumBidAdapter.js +1 -1
  105. package/dist/nexx360Utils.js +1 -1
  106. package/dist/nobidAnalyticsAdapter.js +1 -1
  107. package/dist/nobidBidAdapter.js +1 -1
  108. package/dist/nodalsAiRtdProvider.js +1 -1
  109. package/dist/not-for-prod/prebid.js +178 -175
  110. package/dist/objectGuard.js +1 -1
  111. package/dist/oguryBidAdapter.js +1 -1
  112. package/dist/onetagBidAdapter.js +1 -1
  113. package/dist/ooloAnalyticsAdapter.js +1 -1
  114. package/dist/openxBidAdapter.js +1 -1
  115. package/dist/optableRtdProvider.js +1 -1
  116. package/dist/optidigitalBidAdapter.js +1 -1
  117. package/dist/orbidderBidAdapter.js +1 -1
  118. package/dist/outbrainBidAdapter.js +1 -1
  119. package/dist/pixfutureBidAdapter.js +1 -1
  120. package/dist/publinkIdSystem.js +1 -1
  121. package/dist/pubmaticAnalyticsAdapter.js +1 -1
  122. package/dist/pubmaticBidAdapter.js +1 -1
  123. package/dist/pubmaticIdSystem.js +1 -1
  124. package/dist/pubmaticRtdProvider.js +1 -1
  125. package/dist/pubmaticUtils.js +1 -0
  126. package/dist/pubwiseAnalyticsAdapter.js +1 -1
  127. package/dist/pubxaiAnalyticsAdapter.js +1 -1
  128. package/dist/pxyzBidAdapter.js +1 -1
  129. package/dist/quantcastBidAdapter.js +1 -1
  130. package/dist/readpeakBidAdapter.js +1 -1
  131. package/dist/relaidoBidAdapter.js +1 -1
  132. package/dist/retailspotBidAdapter.js +1 -1
  133. package/dist/rhythmoneBidAdapter.js +1 -1
  134. package/dist/riseUtils.js +1 -1
  135. package/dist/rtdModule.js +1 -1
  136. package/dist/rubiconBidAdapter.js +1 -1
  137. package/dist/seedingAllianceBidAdapter.js +1 -1
  138. package/dist/seedtagBidAdapter.js +1 -1
  139. package/dist/sevioBidAdapter.js +1 -0
  140. package/dist/sharethroughAnalyticsAdapter.js +1 -1
  141. package/dist/sharethroughBidAdapter.js +1 -1
  142. package/dist/showheroes-bsBidAdapter.js +1 -1
  143. package/dist/smaatoBidAdapter.js +1 -1
  144. package/dist/smartadserverBidAdapter.js +1 -1
  145. package/dist/smartxBidAdapter.js +1 -1
  146. package/dist/smilewantedBidAdapter.js +1 -1
  147. package/dist/snigelBidAdapter.js +1 -1
  148. package/dist/sonobiBidAdapter.js +1 -1
  149. package/dist/sovrnBidAdapter.js +1 -1
  150. package/dist/sparteoBidAdapter.js +1 -1
  151. package/dist/sspBCBidAdapter.js +1 -1
  152. package/dist/stvBidAdapter.js +1 -1
  153. package/dist/sublimeBidAdapter.js +1 -1
  154. package/dist/taboolaBidAdapter.js +1 -1
  155. package/dist/tappxBidAdapter.js +1 -1
  156. package/dist/targetVideoBidAdapter.js +1 -1
  157. package/dist/teadsBidAdapter.js +1 -1
  158. package/dist/terceptAnalyticsAdapter.js +1 -1
  159. package/dist/themoneytizerBidAdapter.js +1 -1
  160. package/dist/timeoutRtdProvider.js +1 -1
  161. package/dist/trionBidAdapter.js +1 -1
  162. package/dist/tripleliftBidAdapter.js +1 -1
  163. package/dist/ttdBidAdapter.js +1 -1
  164. package/dist/ucfunnelAnalyticsAdapter.js +1 -1
  165. package/dist/uid2IdSystem.js +1 -1
  166. package/dist/underdogmediaBidAdapter.js +1 -1
  167. package/dist/undertoneBidAdapter.js +1 -1
  168. package/dist/unrulyBidAdapter.js +1 -1
  169. package/dist/userId.js +1 -1
  170. package/dist/vidazooUtils.js +1 -1
  171. package/dist/videobyteBidAdapter.js +1 -1
  172. package/dist/visxBidAdapter.js +1 -1
  173. package/dist/vuukleBidAdapter.js +1 -1
  174. package/dist/widespaceBidAdapter.js +1 -1
  175. package/dist/winrBidAdapter.js +1 -1
  176. package/dist/yahooAdsBidAdapter.js +1 -1
  177. package/dist/yandexBidAdapter.js +1 -1
  178. package/dist/yieldmoBidAdapter.js +1 -1
  179. package/dist/yieldoneAnalyticsAdapter.js +1 -1
  180. package/integrationExamples/gpt/pubmaticRtdProvider_Example.html +161 -0
  181. package/libraries/bidderTimeoutUtils/bidderTimeoutUtils.js +119 -0
  182. package/libraries/objectGuard/objectGuard.js +170 -48
  183. package/libraries/objectGuard/ortbGuard.js +33 -43
  184. package/libraries/pubmaticUtils/plugins/dynamicTimeout.js +209 -0
  185. package/libraries/pubmaticUtils/plugins/floorProvider.js +168 -0
  186. package/libraries/pubmaticUtils/plugins/pluginManager.js +106 -0
  187. package/libraries/pubmaticUtils/plugins/unifiedPricingRule.js +375 -0
  188. package/libraries/pubmaticUtils/pubmaticUtils.js +76 -0
  189. package/modules/adagioAnalyticsAdapter.js +6 -1
  190. package/modules/adagioBidAdapter.js +12 -5
  191. package/modules/adagioRtdProvider.js +41 -35
  192. package/modules/fwsspBidAdapter.js +134 -69
  193. package/modules/fwsspBidAdapter.md +121 -26
  194. package/modules/optableRtdProvider.js +33 -12
  195. package/modules/pubmaticAnalyticsAdapter.js +315 -587
  196. package/modules/pubmaticBidAdapter.js +71 -8
  197. package/modules/pubmaticIdSystem.js +4 -4
  198. package/modules/pubmaticRtdProvider.js +105 -613
  199. package/modules/rtdModule/index.js +23 -6
  200. package/modules/sevioBidAdapter.js +413 -0
  201. package/modules/sevioBidAdapter.md +29 -0
  202. package/modules/sparteoBidAdapter.js +122 -10
  203. package/modules/timeoutRtdProvider.js +2 -105
  204. package/modules/ttdBidAdapter.js +0 -5
  205. package/modules/userId/eids.js +1 -1
  206. package/modules/userId/index.js +32 -1
  207. package/package.json +1 -1
  208. package/src/auction.js +3 -0
  209. package/test/spec/activities/objectGuard_spec.js +189 -32
  210. package/test/spec/activities/ortbGuard_spec.js +10 -15
  211. package/test/spec/libraries/bidderTimeoutUtils/bidderTimeoutUtils_spec.js +213 -0
  212. package/test/spec/libraries/pubmaticUtils/plugins/dynamicTimeout_spec.js +746 -0
  213. package/test/spec/libraries/pubmaticUtils/plugins/floorProvider_spec.js +184 -0
  214. package/test/spec/libraries/pubmaticUtils/plugins/pluginManager_spec.js +489 -0
  215. package/test/spec/libraries/pubmaticUtils/plugins/unifiedPricingRule_spec.js +359 -0
  216. package/test/spec/libraries/pubmaticUtils/pubmaticUtils_spec.js +236 -0
  217. package/test/spec/modules/adagioAnalyticsAdapter_spec.js +94 -24
  218. package/test/spec/modules/adagioRtdProvider_spec.js +17 -17
  219. package/test/spec/modules/fwsspBidAdapter_spec.js +513 -78
  220. package/test/spec/modules/optableRtdProvider_spec.js +55 -5
  221. package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +634 -916
  222. package/test/spec/modules/pubmaticBidAdapter_spec.js +260 -1
  223. package/test/spec/modules/pubmaticRtdProvider_spec.js +252 -1505
  224. package/test/spec/modules/realTimeDataModule_spec.js +58 -8
  225. package/test/spec/modules/sevioBidAdapter_spec.js +513 -0
  226. package/test/spec/modules/sparteoBidAdapter_spec.js +528 -43
  227. package/test/spec/modules/timeoutRtdProvider_spec.js +1 -201
  228. package/test/spec/modules/ttdBidAdapter_spec.js +0 -33
  229. package/test/spec/modules/userId_spec.js +115 -1
@@ -1,4 +1,4 @@
1
- import { logInfo, logError, logWarn, isArray, isFn, deepAccess, formatQS } from '../src/utils.js';
1
+ import { logInfo, logError, logWarn, isArray, isFn, deepAccess } from '../src/utils.js';
2
2
  import { BANNER, VIDEO } from '../src/mediaTypes.js';
3
3
  import { registerBidder } from '../src/adapters/bidderFactory.js';
4
4
  import { config } from '../src/config.js';
@@ -6,7 +6,8 @@ import { getGlobal } from '../src/prebidGlobal.js';
6
6
 
7
7
  const BIDDER_CODE = 'fwssp';
8
8
  const GVL_ID = 285;
9
- const USER_SYNC_URL = 'https://ads.stickyadstv.com/auto-user-sync';
9
+ const USER_SYNC_URL = 'https://user-sync.fwmrm.net/ad/u?';
10
+ let PRIVACY_VALUES = {};
10
11
 
11
12
  export const spec = {
12
13
  code: BIDDER_CODE,
@@ -21,7 +22,7 @@ export const spec = {
21
22
  * @return boolean True if this is a valid bid, and false otherwise.
22
23
  */
23
24
  isBidRequestValid(bid) {
24
- return !!(bid.params.serverUrl && bid.params.networkId && bid.params.profile && bid.params.siteSectionId && bid.params.videoAssetId);
25
+ return !!(bid.params.serverUrl && bid.params.networkId && bid.params.profile && bid.params.siteSectionId);
25
26
  },
26
27
 
27
28
  /**
@@ -46,9 +47,9 @@ export const spec = {
46
47
  const buildRequest = (currentBidRequest, bidderRequest) => {
47
48
  const globalParams = constructGlobalParams(currentBidRequest);
48
49
  const keyValues = constructKeyValues(currentBidRequest, bidderRequest);
49
-
50
50
  const slotParams = constructSlotParams(currentBidRequest);
51
- const dataString = constructDataString(globalParams, keyValues, slotParams);
51
+ const serializedSChain = constructSupplyChain(currentBidRequest, bidderRequest);
52
+ const dataString = constructDataString(globalParams, keyValues, serializedSChain, slotParams);
52
53
  return {
53
54
  method: 'GET',
54
55
  url: currentBidRequest.params.serverUrl,
@@ -57,6 +58,19 @@ export const spec = {
57
58
  };
58
59
  }
59
60
 
61
+ const constructSupplyChain = (currentBidRequest, bidderRequest) => {
62
+ // Add schain object
63
+ let schain = deepAccess(bidderRequest, 'ortb2.source.schain');
64
+ if (!schain) {
65
+ schain = deepAccess(bidderRequest, 'ortb2.source.ext.schain');
66
+ }
67
+ if (!schain) {
68
+ schain = currentBidRequest.schain;
69
+ }
70
+
71
+ return this.serializeSupplyChain(schain)
72
+ }
73
+
60
74
  const constructGlobalParams = currentBidRequest => {
61
75
  const sdkVersion = getSDKVersion(currentBidRequest);
62
76
  const prebidVersion = getGlobal().version;
@@ -65,7 +79,7 @@ export const spec = {
65
79
  resp: 'vast4',
66
80
  prof: currentBidRequest.params.profile,
67
81
  csid: currentBidRequest.params.siteSectionId,
68
- caid: currentBidRequest.params.videoAssetId,
82
+ caid: currentBidRequest.params.videoAssetId ? currentBidRequest.params.videoAssetId : 0,
69
83
  pvrn: getRandomNumber(),
70
84
  vprn: getRandomNumber(),
71
85
  flag: setFlagParameter(currentBidRequest.params.flags),
@@ -88,9 +102,9 @@ export const spec = {
88
102
  const keyValues = currentBidRequest.params.adRequestKeyValues || {};
89
103
 
90
104
  // Add bidfloor to keyValues
91
- const bidfloor = getBidFloor(currentBidRequest, config);
92
- keyValues._fw_bidfloor = (bidfloor > 0) ? bidfloor : 0;
93
- keyValues._fw_bidfloorcur = (bidfloor > 0) ? getFloorCurrency(config) : '';
105
+ const { floor, currency } = getBidFloor(currentBidRequest, config);
106
+ keyValues._fw_bidfloor = floor;
107
+ keyValues._fw_bidfloorcur = currency;
94
108
 
95
109
  // Add GDPR flag and consent string
96
110
  if (bidderRequest && bidderRequest.gdprConsent) {
@@ -127,16 +141,6 @@ export const spec = {
127
141
  }
128
142
  }
129
143
 
130
- // Add schain object
131
- const schain = currentBidRequest.schain;
132
- if (schain) {
133
- try {
134
- keyValues.schain = JSON.stringify(schain);
135
- } catch (error) {
136
- logWarn('PREBID - ' + BIDDER_CODE + ': Unable to stringify the schain: ' + error);
137
- }
138
- }
139
-
140
144
  // Add 3rd party user ID
141
145
  if (currentBidRequest.userIdAsEids && currentBidRequest.userIdAsEids.length > 0) {
142
146
  try {
@@ -179,7 +183,7 @@ export const spec = {
179
183
  let videoPlacement = currentBidRequest.mediaTypes.video.placement ? currentBidRequest.mediaTypes.video.placement : null;
180
184
  const videoPlcmt = currentBidRequest.mediaTypes.video.plcmt ? currentBidRequest.mediaTypes.video.plcmt : null;
181
185
 
182
- if (currentBidRequest.params.format == 'inbanner') {
186
+ if (currentBidRequest.params.format === 'inbanner') {
183
187
  videoContext = 'In-Banner';
184
188
  videoPlacement = 2;
185
189
  }
@@ -188,6 +192,34 @@ export const spec = {
188
192
  keyValues._fw_placement_type = videoPlacement;
189
193
  keyValues._fw_plcmt_type = videoPlcmt;
190
194
  }
195
+
196
+ const coppa = deepAccess(bidderRequest, 'ortb2.regs.coppa');
197
+ if (typeof coppa === 'number') {
198
+ keyValues._fw_coppa = coppa;
199
+ }
200
+
201
+ const atts = deepAccess(bidderRequest, 'ortb2.device.ext.atts');
202
+ if (typeof atts === 'number') {
203
+ keyValues._fw_atts = atts;
204
+ }
205
+
206
+ const lmt = deepAccess(bidderRequest, 'ortb2.device.lmt');
207
+ if (typeof lmt === 'number') {
208
+ keyValues._fw_is_lat = lmt;
209
+ }
210
+
211
+ PRIVACY_VALUES = {}
212
+ if (keyValues._fw_coppa != null) {
213
+ PRIVACY_VALUES._fw_coppa = keyValues._fw_coppa;
214
+ }
215
+
216
+ if (keyValues._fw_atts != null) {
217
+ PRIVACY_VALUES._fw_atts = keyValues._fw_atts;
218
+ }
219
+ if (keyValues._fw_is_lat != null) {
220
+ PRIVACY_VALUES._fw_is_lat = keyValues._fw_is_lat;
221
+ }
222
+
191
223
  return keyValues;
192
224
  }
193
225
 
@@ -212,28 +244,23 @@ export const spec = {
212
244
  slid: currentBidRequest.params.slid ? currentBidRequest.params.slid : 'Preroll_1',
213
245
  slau: currentBidRequest.params.slau ? currentBidRequest.params.slau : 'preroll',
214
246
  }
215
- if (currentBidRequest.params.minD) {
216
- slotParams.mind = currentBidRequest.params.minD;
247
+ const video = deepAccess(currentBidRequest, 'mediaTypes.video') || {};
248
+ const mind = video.minduration || currentBidRequest.params.minD;
249
+ const maxd = video.maxduration || currentBidRequest.params.maxD;
250
+
251
+ if (mind) {
252
+ slotParams.mind = mind;
217
253
  }
218
- if (currentBidRequest.params.maxD) {
219
- slotParams.maxd = currentBidRequest.params.maxD
254
+ if (maxd) {
255
+ slotParams.maxd = maxd;
220
256
  }
221
257
  return slotParams
222
258
  }
223
259
 
224
- const constructDataString = (globalParams, keyValues, slotParams) => {
225
- // Helper function to append parameters to the data string and to not include the last '&' param before ';
226
- const appendParams = (params) => {
227
- const keys = Object.keys(params);
228
- return keys.map((key, index) => {
229
- const encodedKey = encodeURIComponent(key);
230
- const encodedValue = encodeURIComponent(params[key]);
231
- return `${encodedKey}=${encodedValue}${index < keys.length - 1 ? '&' : ''}`;
232
- }).join('');
233
- };
234
-
260
+ const constructDataString = (globalParams, keyValues, serializedSChain, slotParams) => {
235
261
  const globalParamsString = appendParams(globalParams) + ';';
236
- const keyValuesString = appendParams(keyValues) + ';';
262
+ // serializedSChain requires special encoding logic as outlined in the ORTB spec https://github.com/InteractiveAdvertisingBureau/openrtb/blob/main/supplychainobject.md
263
+ const keyValuesString = appendParams(keyValues) + serializedSChain + ';';
237
264
  const slotParamsString = appendParams(slotParams) + ';';
238
265
 
239
266
  return globalParamsString + keyValuesString + slotParamsString;
@@ -244,6 +271,21 @@ export const spec = {
244
271
  });
245
272
  },
246
273
 
274
+ /**
275
+ * Serialize a supply chain object to a string uri encoded
276
+ *
277
+ * @param {*} schain object
278
+ */
279
+ serializeSupplyChain: function(schain) {
280
+ if (!schain || !schain.nodes) return '';
281
+ const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain'];
282
+ return `&schain=${schain.ver},${schain.complete}!` +
283
+ schain.nodes.map(node => nodesProperties.map(prop =>
284
+ node[prop] ? encodeURIComponent(node[prop]) : '')
285
+ .join(','))
286
+ .join('!');
287
+ },
288
+
247
289
  /**
248
290
  * Unpack the response from the server into a list of bids.
249
291
  *
@@ -269,7 +311,7 @@ export const spec = {
269
311
  playerSize = getBiggerSize(bidrequest.sizes);
270
312
  }
271
313
 
272
- if (typeof serverResponse == 'object' && typeof serverResponse.body == 'string') {
314
+ if (typeof serverResponse === 'object' && typeof serverResponse.body === 'string') {
273
315
  serverResponse = serverResponse.body;
274
316
  }
275
317
 
@@ -323,7 +365,10 @@ export const spec = {
323
365
  },
324
366
 
325
367
  getUserSyncs: function(syncOptions, responses, gdprConsent, uspConsent, gppConsent) {
326
- const params = {};
368
+ const params = {
369
+ mode: 'auto-user-sync',
370
+ ...PRIVACY_VALUES
371
+ };
327
372
 
328
373
  if (gdprConsent) {
329
374
  if (typeof gdprConsent.gdprApplies === 'boolean') {
@@ -347,21 +392,19 @@ export const spec = {
347
392
  }
348
393
  }
349
394
 
350
- let queryString = '';
351
- if (params) {
352
- queryString = '?' + `${formatQS(params)}`;
353
- }
395
+ const url = USER_SYNC_URL + appendParams(params);
354
396
 
355
397
  const syncs = [];
356
398
  if (syncOptions && syncOptions.pixelEnabled) {
357
399
  syncs.push({
358
400
  type: 'image',
359
- url: USER_SYNC_URL + queryString
401
+ url: url
360
402
  });
361
- } else if (syncOptions.iframeEnabled) {
403
+ }
404
+ if (syncOptions && syncOptions.iframeEnabled) {
362
405
  syncs.push({
363
406
  type: 'iframe',
364
- url: USER_SYNC_URL + queryString
407
+ url: url
365
408
  });
366
409
  }
367
410
 
@@ -379,8 +422,8 @@ export function formatAdHTML(bidrequest, size) {
379
422
  const sdkUrl = getSdkUrl(bidrequest);
380
423
  const displayBaseId = 'fwssp_display_base';
381
424
 
382
- const startMuted = typeof bidrequest.params.isMuted == 'boolean' ? bidrequest.params.isMuted : true
383
- const showMuteButton = typeof bidrequest.params.showMuteButton == 'boolean' ? bidrequest.params.showMuteButton : false
425
+ const startMuted = typeof bidrequest.params.isMuted === 'boolean' ? bidrequest.params.isMuted : true
426
+ const showMuteButton = typeof bidrequest.params.showMuteButton === 'boolean' ? bidrequest.params.showMuteButton : false
384
427
 
385
428
  let playerParams = null;
386
429
  try {
@@ -450,7 +493,7 @@ export function formatAdHTML(bidrequest, size) {
450
493
  }
451
494
 
452
495
  function getSdkUrl(bidrequest) {
453
- const isStg = bidrequest.params.env && bidrequest.params.env.toLowerCase() == 'stg';
496
+ const isStg = bidrequest.params.env && bidrequest.params.env.toLowerCase() === 'stg';
454
497
  const host = isStg ? 'adm.stg.fwmrm.net' : 'mssl.fwmrm.net';
455
498
  const sdkVersion = getSDKVersion(bidrequest);
456
499
  return `https://${host}/libs/adm/${sdkVersion}/AdManager-prebid.js`
@@ -463,7 +506,7 @@ function getSdkUrl(bidrequest) {
463
506
  * @returns {string} The SDK version to use, defaults to '7.10.0' if version parsing fails
464
507
  */
465
508
  export function getSDKVersion(bidRequest) {
466
- const DEFAULT = '7.10.0';
509
+ const DEFAULT = '7.11.0';
467
510
 
468
511
  try {
469
512
  const paramVersion = getSdkVersionFromBidRequest(bidRequest);
@@ -519,25 +562,37 @@ function compareVersions(versionA, versionB) {
519
562
  return 0;
520
563
  };
521
564
 
522
- function getBidFloor(bid, config) {
523
- if (!isFn(bid.getFloor)) {
524
- return deepAccess(bid, 'params.bidfloor', 0);
525
- }
565
+ export function getBidFloor(bid, config) {
566
+ logInfo('PREBID -: getBidFloor called with:', bid);
567
+ let floor = deepAccess(bid, 'params.bidfloor', 0); // fallback bid params
568
+ let currency = deepAccess(bid, 'params.bidfloorcur', 'USD'); // fallback bid params
526
569
 
527
- try {
528
- const bidFloor = bid.getFloor({
529
- currency: getFloorCurrency(config),
530
- mediaType: typeof bid.mediaTypes['banner'] == 'object' ? 'banner' : 'video',
531
- size: '*',
532
- });
533
- return bidFloor.floor;
534
- } catch (e) {
535
- return -1;
536
- }
537
- }
570
+ if (isFn(bid.getFloor)) {
571
+ logInfo('PREBID - : getFloor() present and use it to retrieve floor and currency.');
572
+ try {
573
+ const floorInfo = bid.getFloor({
574
+ currency: config.getConfig('floors.data.currency') || 'USD',
575
+ mediaType: bid.mediaTypes.banner ? 'banner' : 'video',
576
+ size: '*',
577
+ }) || {};
578
+
579
+ // Use getFloor's results if valid
580
+ if (typeof floorInfo.floor === 'number') {
581
+ floor = floorInfo.floor;
582
+ }
538
583
 
539
- function getFloorCurrency(config) {
540
- return config.getConfig('floors.data.currency') != null ? config.getConfig('floors.data.currency') : 'USD';
584
+ if (floorInfo.currency) {
585
+ currency = floorInfo.currency;
586
+ }
587
+ logInfo('PREBID - : getFloor() returned floor:', floor, 'currency:', currency);
588
+ } catch (e) {
589
+ // fallback to static bid.params.bidfloor
590
+ floor = deepAccess(bid, 'params.bidfloor', 0);
591
+ currency = deepAccess(bid, 'params.bidfloorcur', 'USD');
592
+ logInfo('PREBID - : getFloor() exception, fallback to static bid.params.bidfloor:', floor, 'currency:', currency);
593
+ }
594
+ }
595
+ return { floor, currency };
541
596
  }
542
597
 
543
598
  function isValidUrl(str) {
@@ -658,13 +713,13 @@ function getValueFromKeyInImpressionNode(xmlNode, key) {
658
713
  let tempValue = '';
659
714
  queries.forEach(item => {
660
715
  const split = item.split('=');
661
- if (split[0] == key) {
716
+ if (split[0] === key) {
662
717
  tempValue = split[1];
663
718
  }
664
- if (split[0] == 'reqType' && split[1] == 'AdsDisplayStarted') {
719
+ if (split[0] === 'reqType' && split[1] === 'AdsDisplayStarted') {
665
720
  isAdsDisplayStartedPresent = true;
666
721
  }
667
- if (split[0] == 'rootViewKey') {
722
+ if (split[0] === 'rootViewKey') {
668
723
  isRootViewKeyPresent = true;
669
724
  }
670
725
  });
@@ -705,4 +760,14 @@ function getTopMostWindow() {
705
760
  return res;
706
761
  }
707
762
 
763
+ // Helper function to append parameters to the data string and to not include the last '&' param before ';
764
+ function appendParams(params) {
765
+ const keys = Object.keys(params);
766
+ return keys.map((key, index) => {
767
+ const encodedKey = encodeURIComponent(key);
768
+ const encodedValue = encodeURIComponent(params[key]);
769
+ return `${encodedKey}=${encodedValue}${index < keys.length - 1 ? '&' : ''}`;
770
+ }).join('');
771
+ }
772
+
708
773
  registerBidder(spec);
@@ -8,31 +8,126 @@ Maintainer: vis@freewheel.com
8
8
 
9
9
  Module that connects to Freewheel MRM's demand sources
10
10
 
11
- # Test Parameters
11
+ # Basic Test Request
12
12
  ```
13
- var adUnits = [
14
- {
15
- bids: [
16
- {
17
- bidder: 'fwssp', // or use alias 'freewheel-mrm'
18
- params: {
19
- serverUrl: 'https://example.com/ad/g/1',
20
- networkId: '42015',
21
- profile: '42015:js_allinone_profile',
22
- siteSectionId: 'js_allinone_demo_site_section',
23
- videoAssetId: '0',
24
- flags: '+play-uapl' // optional: users may include capability if needed
25
- mode: 'live',
26
- minD: 30,
27
- maxD: 60,
28
- adRequestKeyValues: { // optional: users may include adRequestKeyValues if needed
29
- _fw_player_width: '1920',
30
- _fw_player_height: '1080'
31
- },
32
- format: 'inbanner'
33
- }
34
- }
35
- ]
36
- }
37
- ];
13
+ const adUnits = [{
14
+ code: 'adunit-code',
15
+ mediaTypes: {
16
+ video: {
17
+ playerSize: [640, 480],
18
+ minduration: 30,
19
+ maxduration: 60
20
+ }
21
+ },
22
+ bids: [{
23
+ bidder: 'fwssp', // or use alias 'freewheel-mrm'
24
+ params: {
25
+ serverUrl: 'https://example.com/ad/g/1',
26
+ networkId: '42015',
27
+ profile: '42015:js_allinone_profile',
28
+ siteSectionId: 'js_allinone_demo_site_section',
29
+ videoAssetId: '1', // optional: default value of 0 will used if not included
30
+ flags: '+play-uapl' // optional: users may include capability if needed
31
+ mode: 'live',
32
+ adRequestKeyValues: { // optional: users may include adRequestKeyValues if needed
33
+ _fw_player_width: '1920',
34
+ _fw_player_height: '1080'
35
+ },
36
+ format: 'inbanner'
37
+ }
38
+ }]
39
+ }];
38
40
  ```
41
+
42
+ # Example Inbanner Ad Request
43
+ ```
44
+ {
45
+ code: 'adunit-code',
46
+ mediaTypes: {
47
+ banner: {
48
+ 'sizes': [[300, 250], [300, 600]]
49
+ }
50
+ },
51
+ bids: [{
52
+ bidder: 'fwssp',
53
+ schain: {
54
+ ver: '1.0',
55
+ complete: 1,
56
+ nodes: [{
57
+ asi: 'example.com',
58
+ sid: '0',
59
+ hp: 1,
60
+ rid: 'bidrequestid',
61
+ domain: 'example.com'
62
+ }]
63
+ },
64
+ params: {
65
+ bidfloor: 2.00,
66
+ serverUrl: 'https://example.com/ad/g/1',
67
+ networkId: '42015',
68
+ profile: '42015:js_allinone_profile',
69
+ siteSectionId: 'js_allinone_demo_site_section',
70
+ flags: '+play',
71
+ videoAssetId: '1`, // optional: default value of 0 will used if not included
72
+ timePosition: 120,
73
+ adRequestKeyValues: {
74
+ _fw_player_width: '1920',
75
+ _fw_player_height: '1080',
76
+ _fw_content_programmer_brand: 'NEEDS_TO_REPLACE_BY_BRAND_NAME',
77
+ _fw_content_programmer_brand_channel: 'NEEDS_TO_REPLACE_BY_CHANNEL_NAME',
78
+ _fw_content_genre: 'NEEDS_TO_REPLACE_BY_CONTENT_GENRE'
79
+ }
80
+ }
81
+ }]
82
+ }
83
+ ```
84
+
85
+ # Example Instream Ad Request
86
+ ```
87
+ {
88
+ code: 'adunit-code',
89
+ mediaTypes: {
90
+ video: {
91
+ playerSize: [300, 600],
92
+ }
93
+ },
94
+ bids: [{
95
+ bidder: 'fwssp',
96
+ schain: {
97
+ ver: '1.0',
98
+ complete: 1,
99
+ nodes: [{
100
+ asi: 'example.com',
101
+ sid: '0',
102
+ hp: 1,
103
+ rid: 'bidrequestid',
104
+ domain: 'example.com'
105
+ }]
106
+ },
107
+ params: {
108
+ bidfloor: 2.00,
109
+ serverUrl: 'https://example.com/ad/g/1',
110
+ networkId: '42015',
111
+ profile: '42015:js_allinone_profile',
112
+ siteSectionId: 'js_allinone_demo_site_section',
113
+ flags: '+play',
114
+ videoAssetId: '1', // optional: default value of 0 will used if not included
115
+ mode: 'live',
116
+ timePosition: 120,
117
+ tpos: 300,
118
+ slid: 'Midroll',
119
+ slau: 'midroll',
120
+ minD: 30,
121
+ maxD: 60,
122
+ adRequestKeyValues: {
123
+ _fw_player_width: '1920',
124
+ _fw_player_height: '1080',
125
+ _fw_content_progrmmer_brand: 'NEEDS_TO_REPLACE_BY_BRAND_NAME',
126
+ _fw_content_programmer_brand_channel: 'NEEDS_TO_REPLACE_BY_CHANNEL_NAME',
127
+ _fw_content_genre: 'NEEDS_TO_REPLACE_BY_CONTENT_GENRE'
128
+ },
129
+ gdpr_consented_providers: 'test_providers'
130
+ }
131
+ }]
132
+ }
133
+ ```
@@ -15,8 +15,8 @@ const {logMessage, logWarn, logError} = optableLog;
15
15
  */
16
16
  export const parseConfig = (moduleConfig) => {
17
17
  let bundleUrl = deepAccess(moduleConfig, 'params.bundleUrl', null);
18
- let adserverTargeting = deepAccess(moduleConfig, 'params.adserverTargeting', true);
19
- let handleRtd = deepAccess(moduleConfig, 'params.handleRtd', null);
18
+ const adserverTargeting = deepAccess(moduleConfig, 'params.adserverTargeting', true);
19
+ const handleRtd = deepAccess(moduleConfig, 'params.handleRtd', null);
20
20
 
21
21
  // If present, trim the bundle URL
22
22
  if (typeof bundleUrl === 'string') {
@@ -37,6 +37,35 @@ export const parseConfig = (moduleConfig) => {
37
37
  return {bundleUrl, adserverTargeting, handleRtd};
38
38
  }
39
39
 
40
+ /**
41
+ * Wait for Optable SDK event to fire with targeting data
42
+ * @param {string} eventName Name of the event to listen for
43
+ * @returns {Promise<Object|null>} Promise that resolves with targeting data or null
44
+ */
45
+ const waitForOptableEvent = (eventName) => {
46
+ return new Promise((resolve) => {
47
+ const optableBundle = /** @type {Object} */ (window.optable);
48
+ const cachedData = optableBundle?.instance?.targetingFromCache();
49
+
50
+ if (cachedData && cachedData.ortb2) {
51
+ logMessage('Optable SDK already has cached data');
52
+ resolve(cachedData);
53
+ return;
54
+ }
55
+
56
+ const eventListener = (event) => {
57
+ logMessage(`Received ${eventName} event`);
58
+ // Extract targeting data from event detail
59
+ const targetingData = event.detail;
60
+ window.removeEventListener(eventName, eventListener);
61
+ resolve(targetingData);
62
+ };
63
+
64
+ window.addEventListener(eventName, eventListener);
65
+ logMessage(`Waiting for ${eventName} event`);
66
+ });
67
+ };
68
+
40
69
  /**
41
70
  * Default function to handle/enrich RTD data
42
71
  * @param reqBidsConfigObj Bid request configuration object
@@ -45,15 +74,8 @@ export const parseConfig = (moduleConfig) => {
45
74
  * @returns {Promise<void>}
46
75
  */
47
76
  export const defaultHandleRtd = async (reqBidsConfigObj, optableExtraData, mergeFn) => {
48
- const optableBundle = /** @type {Object} */ (window.optable);
49
- // Get targeting data from cache, if available
50
- let targetingData = optableBundle?.instance?.targetingFromCache();
51
- // If no targeting data is found in the cache, call the targeting function
52
- if (!targetingData) {
53
- // Call Optable DCN for targeting data and return the ORTB2 object
54
- targetingData = await optableBundle?.instance?.targeting();
55
- }
56
- logMessage('Original targeting data from targeting(): ', targetingData);
77
+ // Wait for the Optable SDK to dispatch targeting data via event
78
+ let targetingData = await waitForOptableEvent('optable-targeting:change');
57
79
 
58
80
  if (!targetingData || !targetingData.ortb2) {
59
81
  logWarn('No targeting data found');
@@ -92,7 +114,6 @@ export const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, user
92
114
  try {
93
115
  // Extract the bundle URL from the module configuration
94
116
  const {bundleUrl, handleRtd} = parseConfig(moduleConfig);
95
-
96
117
  const handleRtdFn = handleRtd || defaultHandleRtd;
97
118
  const optableExtraData = config.getConfig('optableRtdConfig') || {};
98
119