• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

prebid / Prebid.js / 16509128435

24 Jul 2025 10:24PM UTC coverage: 96.27% (+0.004%) from 96.266%
16509128435

push

github

663e0d
prebidjs-release
Increment version to 10.6.0-pre

39403 of 48411 branches covered (81.39%)

194836 of 202385 relevant lines covered (96.27%)

83.38 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.18
/modules/byDataAnalyticsAdapter.js
1
import { deepClone, logInfo, logError, getWinDimensions } from '../src/utils.js';
1✔
2
import Base64 from 'crypto-js/enc-base64';
3
import hmacSHA512 from 'crypto-js/hmac-sha512';
4
import enc from 'crypto-js/enc-utf8';
5
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
6
import { EVENTS, BID_STATUS } from '../src/constants.js';
7
import adapterManager from '../src/adapterManager.js';
8
import {getStorageManager} from '../src/storageManager.js';
9
import { auctionManager } from '../src/auctionManager.js';
10
import { ajax } from '../src/ajax.js';
11
import {MODULE_TYPE_ANALYTICS} from '../src/activities/modules.js';
12
import { getViewportSize } from '../libraries/viewport/viewport.js';
13
import { getOsBrowserInfo } from '../libraries/userAgentUtils/detailed.js';
14

15
const versionCode = '4.4.1'
1✔
16
const secretKey = 'bydata@123456'
1✔
17
const { NO_BID, BID_TIMEOUT, AUCTION_END, AUCTION_INIT, BID_WON } = EVENTS
1✔
18
const DEFAULT_EVENT_URL = 'https://pbjs-stream.bydata.com/topics/prebid'
1✔
19
const analyticsType = 'endpoint'
1✔
20
const isBydata = isKeyInUrl('bydata_debug')
1✔
21
const adunitsMap = {}
1✔
22
const MODULE_CODE = 'bydata';
1✔
23
const storage = getStorageManager({moduleType: MODULE_TYPE_ANALYTICS, moduleName: MODULE_CODE});
1✔
24

25
let initOptions = {}
1✔
26
var payload = {}
1✔
27
var winPayload = {}
1✔
28
var isDataSend = window.asc_data || false
1✔
29
var bdNbTo = { 'to': [], 'nb': [] }
1✔
30

31
/* method used for testing parameters */
32
function isKeyInUrl(name) {
33
  const queryString = window.location.search;
1✔
34
  const urlParams = new URLSearchParams(queryString);
1✔
35
  const param = urlParams.get(name)
1✔
36
  return param
1✔
37
}
38

39
/* return ad unit full path wrt custom ad unit code */
40
function getAdunitName(code) {
41
  var name = code;
3✔
42
  for (const [key, value] of Object.entries(adunitsMap)) {
3✔
43
    if (key === code) { name = value; }
×
44
  }
45
  return name;
3✔
46
}
47

48
/* EVENT: auction init */
49
function onAuctionStart(t) {
50
  /* map of ad unit code - ad unit full path */
51
  t.adUnits && t.adUnits.length && t.adUnits.forEach((adu) => {
×
52
    const { code, adunit } = adu
×
53
    adunitsMap[code] = adunit
×
54
  });
55
}
56

57
/* EVENT: bid timeout */
58
function onBidTimeout(t) {
59
  if (payload['visitor_data'] && t && t.length > 0) {
1✔
60
    bdNbTo['to'] = t
1✔
61
  }
62
}
63

64
/* EVENT: no bid */
65
function onNoBidData(t) {
66
  if (payload['visitor_data'] && t) {
1✔
67
    bdNbTo['nb'].push(t)
1✔
68
  }
69
}
70

71
/* EVENT: bid won */
72
function onBidWon(t) {
73
  const { isCorrectOption } = initOptions
1✔
74
  if (isCorrectOption && (isDataSend || isBydata)) {
1!
75
    ascAdapter.getBidWonData(t)
×
76
    ascAdapter.sendPayload(winPayload)
×
77
  }
78
}
79

80
/* EVENT: auction end */
81
function onAuctionEnd(t) {
82
  const { isCorrectOption } = initOptions;
×
83
  setTimeout(() => {
×
84
    if (isCorrectOption && (isDataSend || isBydata)) {
×
85
      ascAdapter.dataProcess(t);
×
86
      ascAdapter.sendPayload(payload);
×
87
    }
88
  }, 500);
89
}
90

91
const ascAdapter = Object.assign(adapter({ url: DEFAULT_EVENT_URL, analyticsType: analyticsType }), {
1✔
92
  track({ eventType, args }) {
3✔
93
    switch (eventType) {
3!
94
      case AUCTION_INIT:
95
        onAuctionStart(args);
×
96
        break;
×
97
      case NO_BID:
98
        onNoBidData(args);
1✔
99
        break;
1✔
100
      case BID_TIMEOUT:
101
        onBidTimeout(args);
1✔
102
        break;
1✔
103
      case AUCTION_END:
104
        onAuctionEnd(args);
×
105
        break;
×
106
      case BID_WON:
107
        onBidWon(args);
1✔
108
        break;
1✔
109
      default:
110
        break;
×
111
    }
112
  }
113
});
114

115
// save the base class function
116
ascAdapter.originEnableAnalytics = ascAdapter.enableAnalytics;
1✔
117
// override enableAnalytics so we can get access to the config passed in from the page
118
ascAdapter.enableAnalytics = function (config) {
1✔
119
  if (this.initConfig(config)) {
4✔
120
    initOptions.isCorrectOption && ascAdapter.getVisitorData();
2✔
121
    ascAdapter.originEnableAnalytics(config);
2✔
122
  }
123
};
124

125
ascAdapter.initConfig = function (config) {
1✔
126
  let isCorrectOption = true;
4✔
127
  initOptions = {};
4✔
128
  var rndNum = Math.floor(Math.random() * 10000 + 1);
4✔
129
  initOptions.options = deepClone(config.options);
4✔
130
  initOptions.clientId = initOptions.options.clientId || null;
4✔
131
  initOptions.logFrequency = initOptions.options.logFrequency;
4✔
132
  if (!initOptions.clientId) {
4✔
133
    _logError('"options.clientId" should not empty!!');
2✔
134
    isCorrectOption = false;
2✔
135
  }
136
  if (rndNum <= initOptions.logFrequency) { window.asc_data = isDataSend = true; }
4!
137
  initOptions.isCorrectOption = isCorrectOption;
4✔
138
  this.initOptions = initOptions;
4✔
139
  return isCorrectOption;
4✔
140
};
141

142
ascAdapter.getBidWonData = function(t) {
1✔
143
  const { auctionId, adUnitCode, size, requestId, bidder, timeToRespond, currency, mediaType, cpm } = t
1✔
144
  const aun = getAdunitName(adUnitCode)
1✔
145
  winPayload['aid'] = auctionId
1✔
146
  winPayload['as'] = '';
1✔
147
  winPayload['auctionData'] = [];
1✔
148
  var data = {}
1✔
149
  data['au'] = aun
1✔
150
  data['auc'] = adUnitCode
1✔
151
  data['aus'] = size
1✔
152
  data['bid'] = requestId
1✔
153
  data['bidadv'] = bidder
1✔
154
  data['br_pb_mg'] = cpm
1✔
155
  data['br_tr'] = timeToRespond
1✔
156
  data['bradv'] = bidder
1✔
157
  data['brid'] = requestId
1✔
158
  data['brs'] = size
1✔
159
  data['cur'] = currency
1✔
160
  data['inb'] = 0
1✔
161
  data['ito'] = 0
1✔
162
  data['ipwb'] = 1
1✔
163
  data['iwb'] = 1
1✔
164
  data['mt'] = mediaType
1✔
165
  winPayload['auctionData'].push(data)
1✔
166
  return winPayload
1✔
167
}
168

169
ascAdapter.getVisitorData = function (data = {}) {
3✔
170
  var ua = data.uid ? data : {};
3✔
171
  const info = getOsBrowserInfo();
3✔
172

173
  function generateUid() {
174
    try {
1✔
175
      var buffer = new Uint8Array(16);
1✔
176
      crypto.getRandomValues(buffer);
1✔
177
      buffer[6] = (buffer[6] & ~176) | 64;
1✔
178
      buffer[8] = (buffer[8] & ~64) | 128;
1✔
179
      var hex = Array.prototype.map.call(new Uint8Array(buffer), function (x) {
1✔
180
        return ('00' + x.toString(16)).slice(-2);
16✔
181
      }).join('');
182
      return hex.slice(0, 5) + '-' + hex.slice(5, 9) + '-' + hex.slice(9, 13) + '-' + hex.slice(13, 18);
1✔
183
    } catch (e) {
184
      return '';
×
185
    }
186
  }
187
  function base64url(source) {
188
    var encodedSource = Base64.stringify(source);
9✔
189
    encodedSource = encodedSource.replace(/=+$/, '');
9✔
190
    encodedSource = encodedSource.replace(/\+/g, '-');
9✔
191
    encodedSource = encodedSource.replace(/\//g, '_');
9✔
192
    return encodedSource;
9✔
193
  }
194
  function getJWToken(data) {
195
    var header = {
3✔
196
      'alg': 'HS256',
197
      'typ': 'JWT'
198
    };
199
    var stringifiedHeader = enc.parse(JSON.stringify(header));
3✔
200
    var encodedHeader = base64url(stringifiedHeader);
3✔
201
    var stringifiedData = enc.parse(JSON.stringify(data));
3✔
202
    var encodedData = base64url(stringifiedData);
3✔
203
    var token = encodedHeader + '.' + encodedData;
3✔
204
    var signature = hmacSHA512(token, secretKey);
3✔
205
    signature = base64url(signature);
3✔
206
    var signedToken = token + '.' + signature;
3✔
207
    return signedToken;
3✔
208
  }
209
  function detectWidth() {
210
    const {width: viewportWidth} = getViewportSize();
3✔
211
    const windowDimensions = getWinDimensions();
3✔
212
    return windowDimensions.screen.width || (windowDimensions.innerWidth && windowDimensions.document.documentElement.clientWidth) ? Math.min(windowDimensions.innerWidth, windowDimensions.document.documentElement.clientWidth) : viewportWidth;
3!
213
  }
214
  function giveDeviceTypeOnScreenSize() {
215
    var _dWidth = detectWidth();
3✔
216
    return _dWidth > 1024 ? 'Desktop' : (_dWidth <= 1024 && _dWidth >= 768) ? 'Tablet' : 'Mobile';
3!
217
  }
218

219
  const { clientId } = initOptions;
3✔
220
  var userId = storage.getDataFromLocalStorage('userId');
3✔
221
  if (!userId) {
3✔
222
    userId = generateUid();
1✔
223
    storage.setDataInLocalStorage('userId', userId);
1✔
224
  }
225
  var screenSize = { width: window.screen.width, height: window.screen.height };
3✔
226
  var deviceType = giveDeviceTypeOnScreenSize();
3✔
227
  if (!ua['uid']) {
3✔
228
    ua['uid'] = userId;
2✔
229
    ua['cid'] = clientId;
2✔
230
    ua['pid'] = window.location.hostname;
2✔
231
    ua["os"] = info.os.name;
2✔
232
    ua["osv"] = info.os.version;
2✔
233
    ua["br"] = info.browser.name;
2✔
234
    ua["brv"] = info.browser.version;
2✔
235
    ua['ss'] = screenSize;
2✔
236
    ua['de'] = deviceType;
2✔
237
    ua['tz'] = window.Intl.DateTimeFormat().resolvedOptions().timeZone;
2✔
238
  }
239
  var signedToken = getJWToken(ua);
3✔
240
  payload['visitor_data'] = signedToken;
3✔
241
  winPayload['visitor_data'] = signedToken;
3✔
242
  return signedToken;
3✔
243
}
244

245
ascAdapter.dataProcess = function (t) {
1✔
246
  if (isBydata) { payload['bydata_debug'] = 'true'; }
1!
247
  _logInfo('fulldata - ', t);
1✔
248
  payload['aid'] = t.auctionId;
1✔
249
  payload['as'] = t.timestamp;
1✔
250
  payload['auctionData'] = [];
1✔
251
  var bidderRequestsData = []; var bidsReceivedData = [];
1✔
252
  t.bidderRequests && t.bidderRequests.forEach(bidReq => {
1✔
253
    var pObj = {}; pObj['bids'] = [];
1✔
254
    bidReq.bids.forEach(bid => {
1✔
255
      var data = {};
1✔
256
      data['adUnitCode'] = bid.adUnitCode;
1✔
257
      data['sizes'] = bid.sizes;
1✔
258
      data['bidder'] = bid.bidder;
1✔
259
      data['bidId'] = bid.bidId;
1✔
260
      data['mediaTypes'] = [];
1✔
261
      var mt = bid.mediaTypes.banner ? 'display' : 'video';
1!
262
      data['mediaTypes'].push(mt);
1✔
263
      pObj['bids'].push(data);
1✔
264
    })
265
    bidderRequestsData.push(pObj);
1✔
266
  });
267
  t.bidsReceived && t.bidsReceived.forEach(bid => {
1✔
268
    const { requestId, bidder, width, height, cpm, currency, timeToRespond, adUnitCode } = bid;
×
269
    bidsReceivedData.push({ requestId, bidder, width, height, cpm, currency, timeToRespond, adUnitCode });
×
270
  });
271
  bidderRequestsData.length > 0 && bidderRequestsData.forEach(bdObj => {
1✔
272
    var bdsArray = bdObj['bids'];
1✔
273
    bdsArray.forEach(bid => {
1✔
274
      const { adUnitCode, sizes, bidder, bidId, mediaTypes } = bid;
1✔
275
      sizes.forEach(size => {
1✔
276
        var sstr = size[0] + 'x' + size[1]
2✔
277
        payload['auctionData'].push({ au: getAdunitName(adUnitCode), auc: adUnitCode, aus: sstr, mt: mediaTypes[0], bidadv: bidder, bid: bidId, inb: 0, ito: 0, ipwb: 0, iwb: 0 });
2✔
278
      });
279
    });
280
  });
281

282
  bidsReceivedData.length > 0 && bidsReceivedData.forEach(bdRecived => {
1!
283
    const { requestId, bidder, width, height, cpm, currency, timeToRespond } = bdRecived;
×
284
    payload["auctionData"].forEach(rwData => {
×
285
      if (rwData["bid"] === requestId && rwData["aus"] === width + "x" + height) {
×
286
        rwData["brid"] = requestId; rwData["bradv"] = bidder; rwData["br_pb_mg"] = cpm;
×
287
        rwData["cur"] = currency; rwData["br_tr"] = timeToRespond; rwData["brs"] = width + "x" + height;
×
288
      }
289
    });
290
  });
291

292
  var prebidWinningBids = auctionManager.getBidsReceived().filter(bid => bid.status === BID_STATUS.BID_TARGETING_SET);
1✔
293
  prebidWinningBids && prebidWinningBids.length > 0 && prebidWinningBids.forEach(pbbid => {
1!
294
    payload['auctionData'] && payload['auctionData'].forEach(rwData => {
×
295
      if (rwData['bid'] === pbbid.requestId && rwData['brs'] === pbbid.size) {
×
296
        rwData['ipwb'] = 1;
×
297
      }
298
    });
299
  })
300

301
  var winningBids = auctionManager.getAllWinningBids();
1✔
302
  winningBids && winningBids.length > 0 && winningBids.forEach(wBid => {
1!
303
    payload['auctionData'] && payload['auctionData'].forEach(rwData => {
×
304
      if (rwData['bid'] === wBid.requestId && rwData['brs'] === wBid.size) {
×
305
        rwData['iwb'] = 1;
×
306
      }
307
    });
308
  })
309

310
  payload['auctionData'] && payload['auctionData'].length > 0 && payload['auctionData'].forEach(u => {
1✔
311
    bdNbTo['to'].forEach(i => {
2✔
312
      if (u.bid === i.bidId) u.ito = 1;
2!
313
    });
314
    bdNbTo['nb'].forEach(i => {
2✔
315
      if (u.bidadv === i.bidder && u.bid === i.bidId) { u.inb = 1; }
2✔
316
    })
317
  });
318
  return payload;
1✔
319
}
320

321
ascAdapter.sendPayload = function (data) {
1✔
322
  var obj = { 'records': [{ 'value': data }] };
×
323
  const strJSON = JSON.stringify(obj);
×
324
  sendDataOnKf(strJSON);
×
325
}
326

327
function sendDataOnKf(dataObj) {
328
  ajax(DEFAULT_EVENT_URL, {
×
329
    success: function () {
330
      _logInfo('send data success');
×
331
    },
332
    error: function (e) {
333
      _logInfo('send data error', e);
×
334
    }
335
  }, dataObj, {
336
    contentType: 'application/vnd.kafka.json.v2+json',
337
    method: 'POST',
338
    withCredentials: true
339
  });
340
}
341

342
adapterManager.registerAnalyticsAdapter({
1✔
343
  adapter: ascAdapter,
344
  code: MODULE_CODE,
345
});
346

347
function _logInfo(message, meta) {
348
  logInfo(buildLogMessage(message), meta);
1✔
349
}
350

351
function _logError(message) {
352
  logError(buildLogMessage(message));
2✔
353
}
354

355
function buildLogMessage(message) {
356
  return 'Bydata Prebid Analytics ' + versionCode + ':' + message;
3✔
357
}
358

359
export default ascAdapter;
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc