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

prebid / Prebid.js / 17552805458

08 Sep 2025 01:40PM UTC coverage: 96.25% (+0.003%) from 96.247%
17552805458

push

github

47e5f4
prebidjs-release
Increment version to 10.11.0-pre

39744 of 48861 branches covered (81.34%)

197557 of 205253 relevant lines covered (96.25%)

124.87 hits per line

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

75.86
/modules/eskimiBidAdapter.js
1
import {ortbConverter} from '../libraries/ortbConverter/converter.js';
1✔
2
import {registerBidder} from '../src/adapters/bidderFactory.js';
3
import {BANNER, VIDEO} from '../src/mediaTypes.js';
4
import * as utils from '../src/utils.js';
5
import {getBidIdParameter, logInfo, mergeDeep} from '../src/utils.js';
6

7
/**
8
 * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest
9
 * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid
10
 * @typedef {import('../src/adapters/bidderFactory.js').validBidRequests} validBidRequests
11
 */
12

13
const BIDDER_CODE = 'eskimi';
1✔
14
const DEFAULT_BID_TTL = 30;
1✔
15
const DEFAULT_CURRENCY = 'USD';
1✔
16
const DEFAULT_NET_REVENUE = true;
1✔
17
const GVLID = 814;
1✔
18

19
const VIDEO_ORTB_PARAMS = [
1✔
20
  'mimes',
21
  'minduration',
22
  'maxduration',
23
  'plcmt',
24
  'protocols',
25
  'startdelay',
26
  'skip',
27
  'skipafter',
28
  'minbitrate',
29
  'maxbitrate',
30
  'delivery',
31
  'playbackmethod',
32
  'api',
33
  'linearity',
34
  'battr'
35
];
36

37
const BANNER_ORTB_PARAMS = [
1✔
38
  'battr'
39
];
40

41
const REGION_SUBDOMAIN_SUFFIX = {
1✔
42
  EU: '',
43
  US: '-us-e',
44
  APAC: '-asia'
45
};
46

47
export const spec = {
1✔
48
  code: BIDDER_CODE,
49
  gvlid: GVLID,
50
  supportedMediaTypes: [BANNER, VIDEO],
51
  isBidRequestValid,
52
  buildRequests,
53
  interpretResponse,
54
  getUserSyncs,
55
  /**
56
   * Register bidder specific code, which will execute if a bid from this bidder won the auction
57
   * @param {Bid} bid The bid that won the auction
58
   */
59
  onBidWon: function (bid) {
60
    logInfo('Bid won: ', bid);
×
61
    if (bid.burl) {
×
62
      utils.triggerPixel(bid.burl);
×
63
    }
64
  },
65
  onTimeout: function (timeoutData) {
66
    logInfo('Timeout: ', timeoutData);
×
67
  },
68
  onBidderError: function ({error, bidderRequest}) {
×
69
    logInfo('Error: ', error, bidderRequest);
×
70
  },
71
}
72

73
registerBidder(spec);
1✔
74

75
const CONVERTER = ortbConverter({
1✔
76
  context: {
77
    netRevenue: DEFAULT_NET_REVENUE,
78
    ttl: DEFAULT_BID_TTL,
79
    currency: DEFAULT_CURRENCY
80
  },
81
  imp(buildImp, bidRequest, context) {
82
    let imp = buildImp(bidRequest, context);
8✔
83
    imp.secure = bidRequest.ortb2Imp?.secure ?? 1;
8✔
84
    if (!imp.bidfloor && bidRequest.params.bidFloor) {
8!
85
      imp.bidfloor = bidRequest.params.bidFloor;
×
86
      imp.bidfloorcur = getBidIdParameter('bidFloorCur', bidRequest.params).toUpperCase() || 'USD'
×
87
    }
88

89
    if (bidRequest.mediaTypes[VIDEO]) {
8✔
90
      imp = buildVideoImp(bidRequest, imp);
2✔
91
    } else if (bidRequest.mediaTypes[BANNER]) {
6✔
92
      imp = buildBannerImp(bidRequest, imp);
6✔
93
    }
94

95
    return imp;
8✔
96
  },
97
  request(buildRequest, imps, bidderRequest, context) {
98
    const req = buildRequest(imps, bidderRequest, context);
8✔
99
    mergeDeep(req, {
8✔
100
      at: 1,
101
      ext: {
102
        pv: '$prebid.version$'
103
      }
104
    })
105
    const bid = context.bidRequests[0];
8✔
106
    if (bid.params.coppa) {
8!
107
      utils.deepSetValue(req, 'regs.coppa', 1);
×
108
    }
109
    if (bid.params.test) {
8!
110
      req.test = 1
×
111
    }
112
    return req;
8✔
113
  },
114
});
115

116
function isBidRequestValid(bidRequest) {
117
  return (isPlacementIdValid(bidRequest) && (isValidBannerRequest(bidRequest) || isValidVideoRequest(bidRequest)));
6✔
118
}
119

120
function isPlacementIdValid(bidRequest) {
121
  return !!parseInt(bidRequest.params.placementId);
6✔
122
}
123

124
function isValidBannerRequest(bidRequest) {
125
  const bannerSizes = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}.sizes`);
5✔
126
  return utils.isArray(bannerSizes) && bannerSizes.length > 0 && bannerSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
5✔
127
}
128

129
function isValidVideoRequest(bidRequest) {
130
  const videoSizes = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}.playerSize`);
3✔
131

132
  return utils.isArray(videoSizes) && videoSizes.length > 0 && videoSizes.every(size => utils.isNumber(size[0]) && utils.isNumber(size[1]));
3✔
133
}
134

135
/**
136
 * Takes an array of valid bid requests, all of which are guaranteed to have passed the isBidRequestValid() test.
137
 * Make a server request from the list of BidRequests.
138
 *
139
 * @param {*} validBidRequests
140
 * @param {*} bidderRequest
141
 * @return ServerRequest Info describing the request to the server.
142
 */
143
function buildRequests(validBidRequests, bidderRequest) {
144
  const videoBids = validBidRequests.filter(bid => isVideoBid(bid));
8✔
145
  const bannerBids = validBidRequests.filter(bid => isBannerBid(bid));
8✔
146
  const requests = [];
8✔
147

148
  bannerBids.forEach(bid => {
8✔
149
    requests.push(createRequest([bid], bidderRequest, BANNER));
6✔
150
  });
151

152
  videoBids.forEach(bid => {
8✔
153
    requests.push(createRequest([bid], bidderRequest, VIDEO));
2✔
154
  });
155

156
  return requests;
8✔
157
}
158

159
function interpretResponse(response, request) {
160
  return CONVERTER.fromORTB({request: request.data, response: response.body}).bids;
3✔
161
}
162

163
function buildVideoImp(bidRequest, imp) {
164
  const videoAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${VIDEO}`, {});
2✔
165
  const videoBidderParams = utils.deepAccess(bidRequest, `params.${VIDEO}`, {});
2✔
166

167
  const videoParams = {...videoAdUnitParams, ...videoBidderParams};
2✔
168

169
  const videoSizes = (videoAdUnitParams && videoAdUnitParams.playerSize) || [];
2!
170

171
  if (videoSizes && videoSizes.length > 0) {
2✔
172
    utils.deepSetValue(imp, 'video.w', videoSizes[0][0]);
2✔
173
    utils.deepSetValue(imp, 'video.h', videoSizes[0][1]);
2✔
174
  }
175

176
  VIDEO_ORTB_PARAMS.forEach((param) => {
2✔
177
    if (videoParams.hasOwnProperty(param)) {
30✔
178
      utils.deepSetValue(imp, `video.${param}`, videoParams[param]);
16✔
179
    }
180
  });
181

182
  if (imp.video && videoParams?.context === 'outstream') {
2✔
183
    imp.video.plcmt = imp.video.plcmt || 4;
2!
184
  }
185

186
  return {...imp};
2✔
187
}
188

189
function buildBannerImp(bidRequest, imp) {
190
  const bannerAdUnitParams = utils.deepAccess(bidRequest, `mediaTypes.${BANNER}`, {});
6✔
191
  const bannerBidderParams = utils.deepAccess(bidRequest, `params.${BANNER}`, {});
6✔
192

193
  const bannerParams = {...bannerAdUnitParams, ...bannerBidderParams};
6✔
194

195
  const sizes = bidRequest.mediaTypes.banner.sizes;
6✔
196

197
  if (sizes) {
6✔
198
    utils.deepSetValue(imp, 'banner.w', sizes[0][0]);
6✔
199
    utils.deepSetValue(imp, 'banner.h', sizes[0][1]);
6✔
200
  }
201

202
  BANNER_ORTB_PARAMS.forEach((param) => {
6✔
203
    if (bannerParams.hasOwnProperty(param)) {
6✔
204
      utils.deepSetValue(imp, `banner.${param}`, bannerParams[param]);
1✔
205
    }
206
  });
207

208
  return {...imp};
6✔
209
}
210

211
function createRequest(bidRequests, bidderRequest, mediaType) {
212
  const data = CONVERTER.toORTB({bidRequests, bidderRequest, context: {mediaType}})
8✔
213

214
  const bid = bidRequests.find((b) => b.params.placementId)
8✔
215
  if (!data.site) data.site = {}
8✔
216
  data.site.ext = {placementId: parseInt(bid.params.placementId)}
8✔
217

218
  if (bidderRequest.gdprConsent) {
8✔
219
    if (!data.user) data.user = {};
1✔
220
    if (!data.user.ext) data.user.ext = {};
1✔
221
    if (!data.regs) data.regs = {};
1✔
222
    if (!data.regs.ext) data.regs.ext = {};
1✔
223
    data.user.ext.consent = bidderRequest.gdprConsent.consentString;
1✔
224
    data.regs.ext.gdpr = bidderRequest.gdprConsent.gdprApplies ? 1 : 0;
1!
225
  }
226

227
  if (bid.params.bcat) data.bcat = bid.params.bcat;
8✔
228
  if (bid.params.badv) data.badv = bid.params.badv;
8✔
229
  if (bid.params.bapp) data.bapp = bid.params.bapp;
8✔
230

231
  return {
8✔
232
    method: 'POST',
233
    url: getBidRequestUrlByRegion(),
234
    data: data,
235
    options: {
236
      withCredentials: true,
237
      contentType: 'application/json;charset=UTF-8',
238
    }
239
  }
240
}
241

242
function isVideoBid(bid) {
243
  return utils.deepAccess(bid, 'mediaTypes.video');
10✔
244
}
245

246
function isBannerBid(bid) {
247
  return utils.deepAccess(bid, 'mediaTypes.banner') || !isVideoBid(bid);
8✔
248
}
249

250
/**
251
 * @param syncOptions
252
 * @param responses
253
 * @param gdprConsent
254
 * @param uspConsent
255
 * @param gppConsent
256
 * @return {{type: (string), url: (*|string)}[]}
257
 */
258
function getUserSyncs(syncOptions, responses, gdprConsent, uspConsent, gppConsent) {
259
  if ((syncOptions.iframeEnabled || syncOptions.pixelEnabled)) {
×
260
    const pixelType = syncOptions.iframeEnabled ? 'iframe' : 'image';
×
261
    const query = [];
×
262
    const syncUrl = getUserSyncUrlByRegion();
×
263
    // GDPR Consent Params in UserSync url
264
    if (gdprConsent) {
×
265
      query.push('gdpr=' + (gdprConsent.gdprApplies & 1));
×
266
      query.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || ''));
×
267
    }
268
    // US Privacy Consent
269
    if (uspConsent) {
×
270
      query.push('us_privacy=' + encodeURIComponent(uspConsent));
×
271
    }
272
    // Global Privacy Platform Consent
273
    if (gppConsent?.gppString && gppConsent?.applicableSections?.length) {
×
274
      query.push('gpp=' + encodeURIComponent(gppConsent.gppString));
×
275
      query.push('gpp_sid=' + encodeURIComponent(gppConsent.applicableSections.join(',')));
×
276
    }
277
    return [{
×
278
      type: pixelType,
279
      url: `${syncUrl}${query.length > 0 ? '&' + query.join('&') : ''}`
×
280
    }];
281
  }
282
}
283

284
/**
285
 * Get Bid Request endpoint url by region
286
 * @return {string}
287
 */
288
function getBidRequestUrlByRegion() {
289
  return `https://ittr${getRegionSubdomainSuffix()}.eskimi.com/prebidjs`;
8✔
290
}
291

292
/**
293
 * Get User Sync endpoint url by region
294
 * @return {string}
295
 */
296
function getUserSyncUrlByRegion() {
297
  return `https://ittpx${getRegionSubdomainSuffix()}.eskimi.com/sync?sp_id=137`;
×
298
}
299

300
/**
301
 * Get subdomain URL suffix by region
302
 * @return {string}
303
 */
304
function getRegionSubdomainSuffix() {
305
  try {
8✔
306
    const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
8✔
307
    const region = timezone.split('/')[0];
8✔
308

309
    switch (region) {
8!
310
      case 'Europe':
311
      case 'Africa':
312
      case 'Atlantic':
313
      case 'Arctic':
314
        return REGION_SUBDOMAIN_SUFFIX['EU'];
×
315
      case 'Asia':
316
      case 'Australia':
317
      case 'Antarctica':
318
      case 'Pacific':
319
      case 'Indian':
320
        return REGION_SUBDOMAIN_SUFFIX['APAC'];
×
321
      case 'America':
322
        return REGION_SUBDOMAIN_SUFFIX['US'];
8✔
323
      default:
324
        return REGION_SUBDOMAIN_SUFFIX['EU'];
×
325
    }
326
  } catch (err) {
327
    return REGION_SUBDOMAIN_SUFFIX['EU'];
×
328
  }
329
}
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