mk9-prebid
Version:
Header Bidding Management Library
274 lines (245 loc) • 9.16 kB
JavaScript
import {registerBidder} from '../src/adapters/bidderFactory.js';
import {getStorageManager} from '../src/storageManager.js';
import * as utils from '../src/utils.js';
const BIDDER_CODE = 'teads';
const GVL_ID = 132;
const ENDPOINT_URL = 'https://a.teads.tv/hb/bid-request';
const gdprStatus = {
GDPR_APPLIES_PUBLISHER: 12,
GDPR_APPLIES_GLOBAL: 11,
GDPR_DOESNT_APPLY: 0,
CMP_NOT_FOUND_OR_ERROR: 22
};
const FP_TEADS_ID_COOKIE_NAME = '_tfpvi';
export const storage = getStorageManager(GVL_ID, BIDDER_CODE);
export const spec = {
code: BIDDER_CODE,
gvlid: GVL_ID,
supportedMediaTypes: ['video', 'banner'],
/**
* 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) {
let isValid = false;
if (typeof bid.params !== 'undefined') {
let isValidPlacementId = _validateId(utils.getValue(bid.params, 'placementId'));
let isValidPageId = _validateId(utils.getValue(bid.params, 'pageId'));
isValid = isValidPlacementId && isValidPageId;
}
if (!isValid) {
utils.logError('Teads placementId and pageId parameters are required. Bid aborted.');
}
return isValid;
},
/**
* Make a server request from the list of BidRequests.
*
* @param {validBidRequests[]} an array of bids
* @return ServerRequest Info describing the request to the server.
*/
buildRequests: function(validBidRequests, bidderRequest) {
const bids = validBidRequests.map(buildRequestObject);
const payload = {
referrer: getReferrerInfo(bidderRequest),
pageReferrer: document.referrer,
networkBandwidth: getConnectionDownLink(window.navigator),
timeToFirstByte: getTimeToFirstByte(window),
data: bids,
deviceWidth: screen.width,
hb_version: '$prebid.version$',
...getFLoCParameters(utils.deepAccess(validBidRequests, '0.userId.flocId')),
...getUnifiedId2Parameter(utils.deepAccess(validBidRequests, '0.userId.uid2')),
...getFirstPartyTeadsIdParameter()
};
if (validBidRequests[0].schain) {
payload.schain = validBidRequests[0].schain;
}
let gdpr = bidderRequest.gdprConsent;
if (bidderRequest && gdpr) {
let isCmp = typeof gdpr.gdprApplies === 'boolean';
let isConsentString = typeof gdpr.consentString === 'string';
let status = isCmp
? findGdprStatus(gdpr.gdprApplies, gdpr.vendorData, gdpr.apiVersion)
: gdprStatus.CMP_NOT_FOUND_OR_ERROR;
payload.gdpr_iab = {
consent: isConsentString ? gdpr.consentString : '',
status: status,
apiVersion: gdpr.apiVersion
};
}
if (bidderRequest && bidderRequest.uspConsent) {
payload.us_privacy = bidderRequest.uspConsent;
}
const payloadString = JSON.stringify(payload);
return {
method: 'POST',
url: ENDPOINT_URL,
data: payloadString
};
},
/**
* Unpack the response from the server into a list of bids.
*
* @param {*} serverResponse A successful response from the server.
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: function(serverResponse, bidderRequest) {
const bidResponses = [];
serverResponse = serverResponse.body;
if (serverResponse.responses) {
serverResponse.responses.forEach(function (bid) {
const bidResponse = {
cpm: bid.cpm,
width: bid.width,
height: bid.height,
currency: bid.currency,
netRevenue: true,
ttl: bid.ttl,
meta: {
advertiserDomains: bid && bid.adomain ? bid.adomain : []
},
ad: bid.ad,
requestId: bid.bidId,
creativeId: bid.creativeId,
placementId: bid.placementId
};
if (bid.dealId) {
bidResponse.dealId = bid.dealId
}
bidResponses.push(bidResponse);
});
}
return bidResponses;
}
};
function getReferrerInfo(bidderRequest) {
let ref = '';
if (bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.referer) {
ref = bidderRequest.refererInfo.referer;
}
return ref;
}
function getConnectionDownLink(nav) {
return nav && nav.connection && nav.connection.downlink >= 0 ? nav.connection.downlink.toString() : '';
}
function getTimeToFirstByte(win) {
const performance = win.performance || win.webkitPerformance || win.msPerformance || win.mozPerformance;
const ttfbWithTimingV2 = performance &&
typeof performance.getEntriesByType === 'function' &&
Object.prototype.toString.call(performance.getEntriesByType) === '[object Function]' &&
performance.getEntriesByType('navigation')[0] &&
performance.getEntriesByType('navigation')[0].responseStart &&
performance.getEntriesByType('navigation')[0].requestStart &&
performance.getEntriesByType('navigation')[0].responseStart > 0 &&
performance.getEntriesByType('navigation')[0].requestStart > 0 &&
Math.round(
performance.getEntriesByType('navigation')[0].responseStart - performance.getEntriesByType('navigation')[0].requestStart
);
if (ttfbWithTimingV2) {
return ttfbWithTimingV2.toString();
}
const ttfbWithTimingV1 = performance &&
performance.timing.responseStart &&
performance.timing.requestStart &&
performance.timing.responseStart > 0 &&
performance.timing.requestStart > 0 &&
performance.timing.responseStart - performance.timing.requestStart;
return ttfbWithTimingV1 ? ttfbWithTimingV1.toString() : '';
}
function findGdprStatus(gdprApplies, gdprData, apiVersion) {
let status = gdprStatus.GDPR_APPLIES_PUBLISHER;
if (gdprApplies) {
if (isGlobalConsent(gdprData, apiVersion)) {
status = gdprStatus.GDPR_APPLIES_GLOBAL;
}
} else {
status = gdprStatus.GDPR_DOESNT_APPLY;
}
return status;
}
function isGlobalConsent(gdprData, apiVersion) {
return gdprData && apiVersion === 1
? (gdprData.hasGlobalScope || gdprData.hasGlobalConsent)
: gdprData && apiVersion === 2
? !gdprData.isServiceSpecific
: false;
}
function buildRequestObject(bid) {
const reqObj = {};
let placementId = utils.getValue(bid.params, 'placementId');
let pageId = utils.getValue(bid.params, 'pageId');
reqObj.sizes = getSizes(bid);
reqObj.bidId = utils.getBidIdParameter('bidId', bid);
reqObj.bidderRequestId = utils.getBidIdParameter('bidderRequestId', bid);
reqObj.placementId = parseInt(placementId, 10);
reqObj.pageId = parseInt(pageId, 10);
reqObj.adUnitCode = utils.getBidIdParameter('adUnitCode', bid);
reqObj.auctionId = utils.getBidIdParameter('auctionId', bid);
reqObj.transactionId = utils.getBidIdParameter('transactionId', bid);
return reqObj;
}
function getSizes(bid) {
return utils.parseSizesInput(concatSizes(bid));
}
function concatSizes(bid) {
let playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize');
let videoSizes = utils.deepAccess(bid, 'mediaTypes.video.sizes');
let bannerSizes = utils.deepAccess(bid, 'mediaTypes.banner.sizes');
if (utils.isArray(bannerSizes) || utils.isArray(playerSize) || utils.isArray(videoSizes)) {
let mediaTypesSizes = [bannerSizes, videoSizes, playerSize];
return mediaTypesSizes
.reduce(function(acc, currSize) {
if (utils.isArray(currSize)) {
if (utils.isArray(currSize[0])) {
currSize.forEach(function (childSize) {
acc.push(childSize);
})
} else {
acc.push(currSize);
}
}
return acc;
}, []);
} else {
return bid.sizes;
}
}
function _validateId(id) {
return (parseInt(id) > 0);
}
/**
* Get FLoC parameters to be sent in the bid request.
* @param `{id: string, version: string} | undefined` optionalFlocId FLoC user ID object available if "flocIdSystem" module is enabled.
* @returns `{} | {cohortId: string} | {cohortVersion: string} | {cohortId: string, cohortVersion: string}`
*/
function getFLoCParameters(optionalFlocId) {
if (!optionalFlocId) {
return {};
}
const cohortId = optionalFlocId.id ? { cohortId: optionalFlocId.id } : {};
const cohortVersion = optionalFlocId.version ? { cohortVersion: optionalFlocId.version } : {};
return { ...cohortId, ...cohortVersion };
}
/**
* Get unified ID v2 parameter to be sent in bid request.
* @param `{id: string} | undefined` optionalUid2 uid2 user ID object available if "uid2IdSystem" module is enabled.
* @returns `{} | {unifiedId2: string}`
*/
function getUnifiedId2Parameter(optionalUid2) {
return optionalUid2 ? { unifiedId2: optionalUid2.id } : {};
}
/**
* Get the first-party cookie Teads ID parameter to be sent in bid request.
* @returns `{} | {firstPartyCookieTeadsId: string}`
*/
function getFirstPartyTeadsIdParameter() {
if (!storage.cookiesAreEnabled()) {
return {};
}
const firstPartyTeadsId = storage.getCookie(FP_TEADS_ID_COOKIE_NAME);
return firstPartyTeadsId ? { firstPartyCookieTeadsId: firstPartyTeadsId } : {};
}
registerBidder(spec);