modules/mediasniperBidAdapter.js
import {
deepAccess,
deepClone,
deepSetValue, getBidIdParameter,
inIframe,
isArray,
isEmpty,
isFn,
isNumber,
isStr,
logError,
logMessage,
logWarn,
triggerPixel,
} from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER} from '../src/mediaTypes.js';
const BIDDER_CODE = 'mediasniper';
const DEFAULT_BID_TTL = 360;
const DEFAULT_CURRENCY = 'RUB';
const DEFAULT_NET_REVENUE = true;
const ENDPOINT = 'https://sapi.bumlam.com/prebid/';
export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER],
isBidRequestValid: function (bid) {
logMessage('Hello!! bid: ', JSON.stringify(bid));
if (!bid || isEmpty(bid)) {
return false;
}
if (!bid.params || isEmpty(bid.params)) {
return false;
}
if (!isStr(bid.params.placementId) && !isNumber(bid.params.placementId)) {
return false;
}
const banner = deepAccess(bid, 'mediaTypes.banner', {});
if (!banner || isEmpty(banner)) {
return false;
}
const sizes = deepAccess(bid, 'mediaTypes.banner.sizes', []);
if (!isArray(sizes) || isEmpty(sizes)) {
return false;
}
return true;
},
buildRequests: function (validBidRequests, bidderRequest) {
const payload = createOrtbTemplate();
deepSetValue(payload, 'id', bidderRequest.bidderRequestId);
validBidRequests.forEach((validBid) => {
let bid = deepClone(validBid);
const imp = createImp(bid);
payload.imp.push(imp);
});
// params
const siteId = getBidIdParameter('siteid', validBidRequests[0].params) + '';
deepSetValue(payload, 'site.id', siteId);
// Assign payload.site from refererinfo
if (bidderRequest.refererInfo) {
// TODO: reachedTop is probably not the right check - it may be false when page is available or vice-versa
if (bidderRequest.refererInfo.reachedTop) {
const sitePage = bidderRequest.refererInfo.page;
deepSetValue(payload, 'site.page', sitePage);
deepSetValue(
payload,
'site.domain',
bidderRequest.refererInfo.domain
);
if (bidderRequest.refererInfo?.ref) {
deepSetValue(payload, 'site.ref', bidderRequest.refererInfo.ref);
}
}
}
const request = {
method: 'POST',
url: ENDPOINT,
data: JSON.stringify(payload),
};
return request;
},
interpretResponse(serverResponse, bidRequest) {
const bidResponses = [];
try {
if (
serverResponse.body &&
serverResponse.body.seatbid &&
isArray(serverResponse.body.seatbid)
) {
serverResponse.body.seatbid.forEach((bidderSeat) => {
if (!isArray(bidderSeat.bid) || !bidderSeat.bid.length) {
return;
}
bidderSeat.bid.forEach((bid) => {
const newBid = {
requestId: bid.impid,
cpm: bid.price || 0,
width: bid.w,
height: bid.h,
creativeId: bid.crid || bid.adid || bid.id,
dealId: bid.dealid || null,
currency: serverResponse.body.cur || DEFAULT_CURRENCY,
netRevenue: DEFAULT_NET_REVENUE,
ttl: DEFAULT_BID_TTL, // seconds. https://docs.prebid.org/dev-docs/faq.html#does-prebidjs-cache-bids
ad: bid.adm,
mediaType: BANNER,
burl: bid.nurl,
meta: {
advertiserDomains:
Array.isArray(bid.adomain) && bid.adomain.length
? bid.adomain
: [],
mediaType: BANNER,
},
};
logMessage('answer: ', JSON.stringify(newBid));
bidResponses.push(newBid);
});
});
}
} catch (e) {
logError(BIDDER_CODE, e);
}
return bidResponses;
},
onBidWon: function (bid) {
if (!bid.burl) {
return;
}
const url = bid.burl.replace(/\$\{AUCTION_PRICE\}/, bid.cpm);
triggerPixel(url);
},
};
registerBidder(spec);
/**
* Returns an openRTB 2.5 object.
* This one will be populated at each step of the buildRequest process.
*
* @returns {object}
*/
function createOrtbTemplate() {
return {
id: '',
cur: [DEFAULT_CURRENCY],
imp: [],
site: {},
device: {
ip: '',
js: 1,
ua: navigator.userAgent,
},
user: {},
};
}
/**
* Create the OpenRTB 2.5 imp object.
*
* @param {*} bid Prebid bid object from request
* @returns
*/
function createImp(bid) {
let placementId = '';
if (isStr(bid.params.placementId)) {
placementId = bid.params.placementId;
} else if (isNumber(bid.params.placementId)) {
placementId = bid.params.placementId.toString();
}
const imp = {
id: bid.bidId,
tagid: placementId,
bidfloorcur: DEFAULT_CURRENCY,
secure: 1,
};
// There is no default floor. bidfloor is set only
// if the priceFloors module is activated and returns a valid floor.
const floor = getMinFloor(bid);
if (isNumber(floor)) {
imp.bidfloor = floor;
}
// Only supports proper mediaTypes definition…
for (let mediaType in bid.mediaTypes) {
switch (mediaType) {
case BANNER:
imp.banner = createBannerImp(bid);
break;
}
}
// dealid
const dealId = getBidIdParameter('dealid', bid.params);
if (dealId) {
imp.pmp = {
private_auction: 1,
deals: [
{
id: dealId,
bidfloor: floor || 0,
bidfloorcur: DEFAULT_CURRENCY,
},
],
};
}
return imp;
}
/**
* Returns floor from priceFloors module or MediaKey default value.
*
* @param {*} bid a Prebid.js bid (request) object
* @param {string} mediaType the mediaType or the wildcard '*'
* @param {string|Array} size the size array or the wildcard '*'
* @returns {number|boolean}
*/
function getFloor(bid, mediaType, size = '*') {
if (!isFn(bid.getFloor)) {
return false;
}
if (spec.supportedMediaTypes.indexOf(mediaType) === -1) {
logWarn(
`${BIDDER_CODE}: Unable to detect floor price for unsupported mediaType ${mediaType}. No floor will be used.`
);
return false;
}
const floor = bid.getFloor({
currency: DEFAULT_CURRENCY,
mediaType,
size,
});
return !isNaN(floor.floor) && floor.currency === DEFAULT_CURRENCY
? floor.floor
: false;
}
function getMinFloor(bid) {
const floors = [];
for (let mediaType in bid.mediaTypes) {
const floor = getFloor(bid, mediaType);
if (isNumber(floor)) {
floors.push(floor);
}
}
if (!floors.length) {
return false;
}
return floors.reduce((a, b) => {
return Math.min(a, b);
});
}
/**
* Returns an openRtb 2.5 banner object.
*
* @param {object} bid Prebid bid object from request
* @returns {object}
*/
function createBannerImp(bid) {
let sizes = bid.mediaTypes.banner.sizes;
const params = deepAccess(bid, 'params', {});
const banner = {};
banner.w = parseInt(sizes[0][0], 10);
banner.h = parseInt(sizes[0][1], 10);
const format = [];
sizes.forEach(function (size) {
if (size.length && size.length > 1) {
format.push({ w: size[0], h: size[1] });
}
});
banner.format = format;
banner.topframe = inIframe() ? 0 : 1;
banner.pos = params.pos || 0;
return banner;
}