mk9-prebid
Version:
Header Bidding Management Library
288 lines (263 loc) • 8.61 kB
JavaScript
import * as utils from '../src/utils.js';
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {BANNER, VIDEO} from '../src/mediaTypes.js';
import {config} from '../src/config.js';
const BIDDER_CODE = 'zeta_global_ssp';
const ENDPOINT_URL = 'https://ssp.disqus.com/bid';
const USER_SYNC_URL_IFRAME = 'https://ssp.disqus.com/sync?type=iframe';
const USER_SYNC_URL_IMAGE = 'https://ssp.disqus.com/sync?type=image';
const DEFAULT_CUR = 'USD';
const TTL = 200;
const NET_REV = true;
const DATA_TYPES = {
'NUMBER': 'number',
'STRING': 'string',
'BOOLEAN': 'boolean',
'ARRAY': 'array',
'OBJECT': 'object'
};
const VIDEO_CUSTOM_PARAMS = {
'mimes': DATA_TYPES.ARRAY,
'minduration': DATA_TYPES.NUMBER,
'maxduration': DATA_TYPES.NUMBER,
'startdelay': DATA_TYPES.NUMBER,
'playbackmethod': DATA_TYPES.ARRAY,
'api': DATA_TYPES.ARRAY,
'protocols': DATA_TYPES.ARRAY,
'w': DATA_TYPES.NUMBER,
'h': DATA_TYPES.NUMBER,
'battr': DATA_TYPES.ARRAY,
'linearity': DATA_TYPES.NUMBER,
'placement': DATA_TYPES.NUMBER,
'minbitrate': DATA_TYPES.NUMBER,
'maxbitrate': DATA_TYPES.NUMBER,
'skip': DATA_TYPES.NUMBER
}
export const spec = {
code: BIDDER_CODE,
supportedMediaTypes: [BANNER, VIDEO],
/**
* Determines whether or not the given bid request is valid.
*
* @param {BidRequest} bid The bid params to validate.
* @return boolean True if this is a valid bid, and false otherwise.
*/
isBidRequestValid: function (bid) {
// check for all required bid fields
if (!(bid &&
bid.bidId &&
bid.params)) {
utils.logWarn('Invalid bid request - missing required bid data');
return false;
}
return true;
},
/**
* Make a server request from the list of BidRequests.
*
* @param {Bids[]} validBidRequests - an array of bidRequest objects
* @param {BidderRequest} bidderRequest - master bidRequest object
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function (validBidRequests, bidderRequest) {
const secure = 1; // treat all requests as secure
const request = validBidRequests[0];
const params = request.params;
const impData = {
id: request.bidId,
secure: secure
};
if (request.mediaTypes) {
for (const mediaType in request.mediaTypes) {
switch (mediaType) {
case BANNER:
impData.banner = buildBanner(request);
break;
case VIDEO:
impData.video = buildVideo(request);
break;
}
}
}
if (!impData.banner && !impData.video) {
impData.banner = buildBanner(request);
}
const fpd = config.getLegacyFpd(config.getConfig('ortb2')) || {};
let payload = {
id: bidderRequest.auctionId,
cur: [DEFAULT_CUR],
imp: [impData],
site: params.site ? params.site : {},
device: {...fpd.device, ...params.device},
user: params.user ? params.user : {},
app: params.app ? params.app : {},
ext: {
tags: params.tags ? params.tags : {},
sid: params.sid ? params.sid : undefined
}
};
const rInfo = bidderRequest.refererInfo;
payload.site.page = config.getConfig('pageUrl') || ((rInfo && rInfo.referer) ? rInfo.referer.trim() : window.location.href);
payload.site.domain = config.getConfig('publisherDomain') || getDomainFromURL(payload.site.page);
payload.device.ua = navigator.userAgent;
payload.device.devicetype = isMobile() ? 1 : isConnectedTV() ? 3 : 2;
payload.site.mobile = payload.device.devicetype === 1 ? 1 : 0;
if (params.test) {
payload.test = params.test;
}
// Attaching GDPR Consent Params
if (bidderRequest && bidderRequest.gdprConsent) {
utils.deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString);
utils.deepSetValue(payload, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0));
}
// CCPA
if (bidderRequest && bidderRequest.uspConsent) {
utils.deepSetValue(payload, 'regs.ext.us_privacy', bidderRequest.uspConsent);
}
provideEids(request, payload);
return {
method: 'POST',
url: ENDPOINT_URL,
data: JSON.stringify(payload),
};
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {ServerResponse} serverResponse A successful response from the server.
* @param bidRequest The payload from the server's response.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function (serverResponse, bidRequest) {
let bidResponses = [];
const response = (serverResponse || {}).body;
if (response && response.seatbid && response.seatbid[0].bid && response.seatbid[0].bid.length) {
response.seatbid.forEach(zetaSeatbid => {
zetaSeatbid.bid.forEach(zetaBid => {
let bid = {
requestId: zetaBid.impid,
cpm: zetaBid.price,
currency: response.cur,
width: zetaBid.w,
height: zetaBid.h,
ad: zetaBid.adm,
ttl: TTL,
creativeId: zetaBid.crid,
netRevenue: NET_REV,
};
if (zetaBid.adomain && zetaBid.adomain.length) {
bid.meta = {
advertiserDomains: zetaBid.adomain
};
}
bidResponses.push(bid);
})
})
}
return bidResponses;
},
/**
* Register User Sync.
*/
getUserSyncs: (syncOptions, responses, gdprConsent, uspConsent) => {
let syncurl = '';
// Attaching GDPR Consent Params in UserSync url
if (gdprConsent) {
syncurl += '&gdpr=' + (gdprConsent.gdprApplies ? 1 : 0);
syncurl += '&gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || '');
}
// CCPA
if (uspConsent) {
syncurl += '&us_privacy=' + encodeURIComponent(uspConsent);
}
// coppa compliance
if (config.getConfig('coppa') === true) {
syncurl += '&coppa=1';
}
if (syncOptions.iframeEnabled) {
return [{
type: 'iframe',
url: USER_SYNC_URL_IFRAME + syncurl
}];
} else {
return [{
type: 'image',
url: USER_SYNC_URL_IMAGE + syncurl
}];
}
}
}
function buildBanner(request) {
let sizes = request.sizes;
if (request.mediaTypes &&
request.mediaTypes.banner &&
request.mediaTypes.banner.sizes) {
sizes = request.mediaTypes.banner.sizes;
}
return {
w: sizes[0][0],
h: sizes[0][1]
};
}
function buildVideo(request) {
let video = {};
const videoParams = utils.deepAccess(request, 'mediaTypes.video', {});
for (const key in VIDEO_CUSTOM_PARAMS) {
if (videoParams.hasOwnProperty(key)) {
video[key] = checkParamDataType(key, videoParams[key], VIDEO_CUSTOM_PARAMS[key]);
}
}
if (videoParams.playerSize) {
if (utils.isArray(videoParams.playerSize[0])) {
video.w = parseInt(videoParams.playerSize[0][0], 10);
video.h = parseInt(videoParams.playerSize[0][1], 10);
} else if (utils.isNumber(videoParams.playerSize[0])) {
video.w = parseInt(videoParams.playerSize[0], 10);
video.h = parseInt(videoParams.playerSize[1], 10);
}
}
return video;
}
function checkParamDataType(key, value, datatype) {
let functionToExecute;
switch (datatype) {
case DATA_TYPES.BOOLEAN:
functionToExecute = utils.isBoolean;
break;
case DATA_TYPES.NUMBER:
functionToExecute = utils.isNumber;
break;
case DATA_TYPES.STRING:
functionToExecute = utils.isStr;
break;
case DATA_TYPES.ARRAY:
functionToExecute = utils.isArray;
break;
}
if (functionToExecute(value)) {
return value;
}
utils.logWarn('Ignoring param key: ' + key + ', expects ' + datatype + ', found ' + typeof value);
return undefined;
}
function provideEids(request, payload) {
if (Array.isArray(request.userIdAsEids) && request.userIdAsEids.length > 0) {
utils.deepSetValue(payload, 'user.ext.eids', request.userIdAsEids);
}
}
function getDomainFromURL(url) {
let anchor = document.createElement('a');
anchor.href = url;
let hostname = anchor.hostname;
if (hostname.indexOf('www.') === 0) {
return hostname.substring(4);
}
return hostname;
}
function isMobile() {
return /(ios|ipod|ipad|iphone|android)/i.test(navigator.userAgent);
}
function isConnectedTV() {
return /(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i.test(navigator.userAgent);
}
registerBidder(spec);