UNPKG

mk9-prebid

Version:

Header Bidding Management Library

227 lines (185 loc) 6.85 kB
import * as utils from '../src/utils.js' import {Renderer} from '../src/Renderer.js' import {registerBidder} from '../src/adapters/bidderFactory.js' import {VIDEO, BANNER} from '../src/mediaTypes.js' function configureUniversalTag(exchangeRenderer, requestId) { if (!exchangeRenderer.config) throw new Error('UnrulyBidAdapter: Missing renderer config.'); if (!exchangeRenderer.config.siteId) throw new Error('UnrulyBidAdapter: Missing renderer siteId.'); parent.window.unruly = parent.window.unruly || {}; parent.window.unruly['native'] = parent.window.unruly['native'] || {}; parent.window.unruly['native'].siteId = parent.window.unruly['native'].siteId || exchangeRenderer.config.siteId; parent.window.unruly['native'].adSlotId = requestId; parent.window.unruly['native'].supplyMode = 'prebid'; } function configureRendererQueue() { parent.window.unruly['native'].prebid = parent.window.unruly['native'].prebid || {}; parent.window.unruly['native'].prebid.uq = parent.window.unruly['native'].prebid.uq || []; } function notifyRenderer(bidResponseBid) { parent.window.unruly['native'].prebid.uq.push(['render', bidResponseBid]); } const addBidFloorInfo = (validBid) => { Object.keys(validBid.mediaTypes).forEach((key) => { let floor; if (typeof validBid.getFloor === 'function') { floor = validBid.getFloor({ currency: 'USD', mediaType: key, size: '*' }).floor || 0; } else { floor = validBid.params.floor || 0; } validBid.mediaTypes[key].floor = floor; }); }; const RemoveDuplicateSizes = (validBid) => { let bannerMediaType = utils.deepAccess(validBid, 'mediaTypes.banner'); if (bannerMediaType) { let seenSizes = {}; let newSizesArray = []; bannerMediaType.sizes.forEach((size) => { if (!seenSizes[size.toString()]) { seenSizes[size.toString()] = true; newSizesArray.push(size); } }); bannerMediaType.sizes = newSizesArray; } }; const getRequests = (conf, validBidRequests, bidderRequest) => { const {bids, bidderRequestId, auctionId, bidderCode, ...bidderRequestData} = bidderRequest; const invalidBidsCount = bidderRequest.bids.length - validBidRequests.length; let requestBySiteId = {}; validBidRequests.forEach((validBid) => { const currSiteId = validBid.params.siteId; addBidFloorInfo(validBid); RemoveDuplicateSizes(validBid); requestBySiteId[currSiteId] = requestBySiteId[currSiteId] || []; requestBySiteId[currSiteId].push(validBid); }); let request = []; Object.keys(requestBySiteId).forEach((key) => { let data = { bidderRequest: Object.assign({}, {bids: requestBySiteId[key], invalidBidsCount, ...bidderRequestData}) }; request.push(Object.assign({}, {data, ...conf})); }); return request; }; const handleBidResponseByMediaType = (bids) => { let bidResponses = []; bids.forEach((bid) => { let parsedBidResponse; let bidMediaType = utils.deepAccess(bid, 'meta.mediaType'); if (bidMediaType && bidMediaType.toLowerCase() === 'banner') { bid.mediaType = BANNER; parsedBidResponse = handleBannerBid(bid); } else if (bidMediaType && bidMediaType.toLowerCase() === 'video') { let context = utils.deepAccess(bid, 'meta.videoContext'); bid.mediaType = VIDEO; if (context === 'instream') { parsedBidResponse = handleInStreamBid(bid); } else if (context === 'outstream') { parsedBidResponse = handleOutStreamBid(bid); } } if (parsedBidResponse) { bidResponses.push(parsedBidResponse); } }); return bidResponses; }; const handleBannerBid = (bid) => { if (!bid.ad) { utils.logError(new Error('UnrulyBidAdapter: Missing ad config.')); return; } return bid; }; const handleInStreamBid = (bid) => { if (!(bid.vastUrl || bid.vastXml)) { utils.logError(new Error('UnrulyBidAdapter: Missing vastUrl or vastXml config.')); return; } return bid; }; const handleOutStreamBid = (bid) => { const hasConfig = !!utils.deepAccess(bid, 'ext.renderer.config'); const hasSiteId = !!utils.deepAccess(bid, 'ext.renderer.config.siteId'); if (!hasConfig) { utils.logError(new Error('UnrulyBidAdapter: Missing renderer config.')); return; } if (!hasSiteId) { utils.logError(new Error('UnrulyBidAdapter: Missing renderer siteId.')); return; } const exchangeRenderer = utils.deepAccess(bid, 'ext.renderer'); configureUniversalTag(exchangeRenderer, bid.requestId); configureRendererQueue(); const rendererInstance = Renderer.install(Object.assign({}, exchangeRenderer)); const rendererConfig = Object.assign( {}, bid, { renderer: rendererInstance, adUnitCode: utils.deepAccess(bid, 'ext.adUnitCode') } ); rendererInstance.setRender(() => { notifyRenderer(rendererConfig) }); bid.renderer = bid.renderer || rendererInstance; return bid; }; const isMediaTypesValid = (bid) => { const mediaTypeVideoData = utils.deepAccess(bid, 'mediaTypes.video'); const mediaTypeBannerData = utils.deepAccess(bid, 'mediaTypes.banner'); let isValid = !!(mediaTypeVideoData || mediaTypeBannerData); if (isValid && mediaTypeVideoData) { isValid = isVideoMediaTypeValid(mediaTypeVideoData); } if (isValid && mediaTypeBannerData) { isValid = isBannerMediaTypeValid(mediaTypeBannerData); } return isValid; }; const isVideoMediaTypeValid = (mediaTypeVideoData) => { if (!mediaTypeVideoData.context) { return false; } const supportedContexts = ['outstream', 'instream']; return supportedContexts.indexOf(mediaTypeVideoData.context) !== -1; }; const isBannerMediaTypeValid = (mediaTypeBannerData) => { return mediaTypeBannerData.sizes; }; export const adapter = { code: 'unruly', supportedMediaTypes: [VIDEO, BANNER], isBidRequestValid: function (bid) { let siteId = utils.deepAccess(bid, 'params.siteId'); let isBidValid = siteId && isMediaTypesValid(bid); return !!isBidValid; }, buildRequests: function (validBidRequests, bidderRequest) { let endPoint = 'https://targeting.unrulymedia.com/unruly_prebid'; if (validBidRequests[0]) { endPoint = utils.deepAccess(validBidRequests[0], 'params.endpoint') || endPoint; } const url = endPoint; const method = 'POST'; const options = {contentType: 'application/json'}; return getRequests({url, method, options}, validBidRequests, bidderRequest); }, interpretResponse: function (serverResponse = {}) { const serverResponseBody = serverResponse.body; const noBidsResponse = []; const isInvalidResponse = !serverResponseBody || !serverResponseBody.bids; return isInvalidResponse ? noBidsResponse : handleBidResponseByMediaType(serverResponseBody.bids); } }; registerBidder(adapter);