diff --git a/modules/adagioBidAdapter.js b/modules/adagioBidAdapter.js index 798ff499206..6ebcaebff0f 100644 --- a/modules/adagioBidAdapter.js +++ b/modules/adagioBidAdapter.js @@ -1,4 +1,4 @@ -import {find} from '../src/polyfill.js'; +import { find } from "../src/polyfill.js"; import { _map, cleanObj, @@ -20,76 +20,82 @@ import { logInfo, logWarn, mergeDeep, -} from '../src/utils.js'; -import {config} from '../src/config.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {loadExternalScript} from '../src/adloader.js'; -import {verify} from 'criteo-direct-rsa-validate/build/verify.js'; -import {getStorageManager} from '../src/storageManager.js'; -import {getRefererInfo, parseDomain} from '../src/refererDetection.js'; -import {createEidsArray} from './userId/eids.js'; -import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import {Renderer} from '../src/Renderer.js'; -import {OUTSTREAM} from '../src/video.js'; -import { getGlobal } from '../src/prebidGlobal.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; -import { userSync } from '../src/userSync.js'; - -const BIDDER_CODE = 'adagio'; -const LOG_PREFIX = 'Adagio:'; -const FEATURES_VERSION = '1'; -export const ENDPOINT = 'https://mp.4dex.io/prebid'; +} from "../src/utils.js"; +import { config } from "../src/config.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { loadExternalScript } from "../src/adloader.js"; +import { verify } from "criteo-direct-rsa-validate/build/verify.js"; +import { getStorageManager } from "../src/storageManager.js"; +import { getRefererInfo, parseDomain } from "../src/refererDetection.js"; +import { BANNER, NATIVE, VIDEO } from "../src/mediaTypes.js"; +import { Renderer } from "../src/Renderer.js"; +import { OUTSTREAM } from "../src/video.js"; +import { getGlobal } from "../src/prebidGlobal.js"; +import { convertOrtbRequestToProprietaryNative } from "../src/native.js"; +import { userSync } from "../src/userSync.js"; + +const BIDDER_CODE = "adagio"; +const LOG_PREFIX = "Adagio:"; +const FEATURES_VERSION = "1"; +export const ENDPOINT = "https://mp.4dex.io/prebid"; const SUPPORTED_MEDIA_TYPES = [BANNER, NATIVE, VIDEO]; -const ADAGIO_TAG_URL = 'https://script.4dex.io/localstore.js'; -const ADAGIO_LOCALSTORAGE_KEY = 'adagioScript'; +const ADAGIO_TAG_URL = "https://script.4dex.io/localstore.js"; +const ADAGIO_LOCALSTORAGE_KEY = "adagioScript"; const GVLID = 617; -export const storage = getStorageManager({gvlid: GVLID, bidderCode: BIDDER_CODE}); -export const RENDERER_URL = 'https://script.4dex.io/outstream-player.js'; +export const storage = getStorageManager({ + gvlid: GVLID, + bidderCode: BIDDER_CODE, +}); +export const RENDERER_URL = "https://script.4dex.io/outstream-player.js"; const MAX_SESS_DURATION = 30 * 60 * 1000; -const ADAGIO_PUBKEY = 'AL16XT44Sfp+8SHVF1UdC7hydPSMVLMhsYknKDdwqq+0ToDSJrP0+Qh0ki9JJI2uYm/6VEYo8TJED9WfMkiJ4vf02CW3RvSWwc35bif2SK1L8Nn/GfFYr/2/GG/Rm0vUsv+vBHky6nuuYls20Og0HDhMgaOlXoQ/cxMuiy5QSktp'; +const ADAGIO_PUBKEY = + "AL16XT44Sfp+8SHVF1UdC7hydPSMVLMhsYknKDdwqq+0ToDSJrP0+Qh0ki9JJI2uYm/6VEYo8TJED9WfMkiJ4vf02CW3RvSWwc35bif2SK1L8Nn/GfFYr/2/GG/Rm0vUsv+vBHky6nuuYls20Og0HDhMgaOlXoQ/cxMuiy5QSktp"; const ADAGIO_PUBKEY_E = 65537; -const CURRENCY = 'USD'; +const CURRENCY = "USD"; // This provide a whitelist and a basic validation of OpenRTB 2.6 options used by the Adagio SSP. // https://iabtechlab.com/wp-content/uploads/2022/04/OpenRTB-2-6_FINAL.pdf export const ORTB_VIDEO_PARAMS = { - 'mimes': (value) => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'), - 'minduration': (value) => isInteger(value), - 'maxduration': (value) => isInteger(value), - 'protocols': (value) => isArrayOfNums(value), - 'w': (value) => isInteger(value), - 'h': (value) => isInteger(value), - 'startdelay': (value) => isInteger(value), - 'placement': (value) => isInteger(value), - 'linearity': (value) => isInteger(value), - 'skip': (value) => isInteger(value), - 'skipmin': (value) => isInteger(value), - 'skipafter': (value) => isInteger(value), - 'sequence': (value) => isInteger(value), - 'battr': (value) => isArrayOfNums(value), - 'maxextended': (value) => isInteger(value), - 'minbitrate': (value) => isInteger(value), - 'maxbitrate': (value) => isInteger(value), - 'boxingallowed': (value) => isInteger(value), - 'playbackmethod': (value) => isArrayOfNums(value), - 'playbackend': (value) => isInteger(value), - 'delivery': (value) => isInteger(value), - 'pos': (value) => isInteger(value), - 'api': (value) => isArrayOfNums(value) + mimes: (value) => + Array.isArray(value) && + value.length > 0 && + value.every((v) => typeof v === "string"), + minduration: (value) => isInteger(value), + maxduration: (value) => isInteger(value), + protocols: (value) => isArrayOfNums(value), + w: (value) => isInteger(value), + h: (value) => isInteger(value), + startdelay: (value) => isInteger(value), + placement: (value) => isInteger(value), + linearity: (value) => isInteger(value), + skip: (value) => isInteger(value), + skipmin: (value) => isInteger(value), + skipafter: (value) => isInteger(value), + sequence: (value) => isInteger(value), + battr: (value) => isArrayOfNums(value), + maxextended: (value) => isInteger(value), + minbitrate: (value) => isInteger(value), + maxbitrate: (value) => isInteger(value), + boxingallowed: (value) => isInteger(value), + playbackmethod: (value) => isArrayOfNums(value), + playbackend: (value) => isInteger(value), + delivery: (value) => isInteger(value), + pos: (value) => isInteger(value), + api: (value) => isArrayOfNums(value), }; let currentWindow; -export const GlobalExchange = (function() { +export const GlobalExchange = (function () { let features; let exchangeData = {}; return { - clearFeatures: function() { + clearFeatures: function () { features = undefined; }, - clearExchangeData: function() { + clearExchangeData: function () { exchangeData = {}; }, @@ -100,18 +106,18 @@ export const GlobalExchange = (function() { viewport_dimensions: getViewPortDimensions().toString(), user_timestamp: getTimestampUTC().toString(), dom_loading: getDomLoadingDuration().toString(), - } + }; } return features; }, prepareExchangeData(storageValue) { - const adagioStorage = JSON.parse(storageValue, function(name, value) { - if (name.charAt(0) !== '_' || name === '') { + const adagioStorage = JSON.parse(storageValue, function (name, value) { + if (name.charAt(0) !== "_" || name === "") { return value; } }); - let random = deepAccess(adagioStorage, 'session.rnd'); + let random = deepAccess(adagioStorage, "session.rnd"); let newSession = false; if (internal.isNewSession(adagioStorage)) { @@ -122,22 +128,22 @@ export const GlobalExchange = (function() { const data = { session: { new: newSession, - rnd: random - } - } + rnd: random, + }, + }; mergeDeep(exchangeData, adagioStorage, data); internal.enqueue({ - action: 'session', + action: "session", ts: Date.now(), - data: exchangeData + data: exchangeData, }); }, getExchangeData() { - return exchangeData - } + return exchangeData; + }, }; })(); @@ -176,7 +182,7 @@ export function getAdagioScript() { internal.adagioScriptFromLocalStorageCb(ls); }); - storage.localStorageIsEnabled(isValid => { + storage.localStorageIsEnabled((isValid) => { if (isValid) { loadExternalScript(ADAGIO_TAG_URL, BIDDER_CODE); } else { @@ -188,9 +194,11 @@ export function getAdagioScript() { window.localStorage.removeItem(ADAGIO_LOCALSTORAGE_KEY); // Extra data from external script. // This key is removed only if localStorage is not accessible. - window.localStorage.removeItem('adagio'); + window.localStorage.removeItem("adagio"); } catch (e) { - logInfo(`${LOG_PREFIX} unable to clear Adagio scripts from localstorage.`); + logInfo( + `${LOG_PREFIX} unable to clear Adagio scripts from localstorage.` + ); } } }); @@ -217,7 +225,7 @@ function isSafeFrameWindow() { function initAdagio() { if (canAccessTopWindow()) { - currentWindow = (canAccessTopWindow()) ? getWindowTop() : getWindowSelf(); + currentWindow = canAccessTopWindow() ? getWindowTop() : getWindowSelf(); } const w = internal.getCurrentWindow(); @@ -227,10 +235,10 @@ function initAdagio() { w.ADAGIO.pbjsAdUnits = w.ADAGIO.pbjsAdUnits || []; w.ADAGIO.queue = w.ADAGIO.queue || []; w.ADAGIO.versions = w.ADAGIO.versions || {}; - w.ADAGIO.versions.pbjs = '$prebid.version$'; + w.ADAGIO.versions.pbjs = "$prebid.version$"; w.ADAGIO.isSafeFrameWindow = isSafeFrameWindow(); - storage.getDataFromLocalStorage('adagio', (storageData) => { + storage.getDataFromLocalStorage("adagio", (storageData) => { try { GlobalExchange.prepareExchangeData(storageData); } catch (e) { @@ -247,7 +255,7 @@ function enqueue(ob) { w.ADAGIO = w.ADAGIO || {}; w.ADAGIO.queue = w.ADAGIO.queue || []; w.ADAGIO.queue.push(ob); -}; +} function getPageviewId() { const w = internal.getCurrentWindow(); @@ -256,34 +264,34 @@ function getPageviewId() { w.ADAGIO.pageviewId = w.ADAGIO.pageviewId || generateUUID(); return w.ADAGIO.pageviewId; -}; +} function getDevice() { - const language = navigator.language ? 'language' : 'userLanguage'; + const language = navigator.language ? "language" : "userLanguage"; return { userAgent: navigator.userAgent, language: navigator[language], dnt: getDNT() ? 1 : 0, geo: {}, - js: 1 + js: 1, }; -}; +} function getSite(bidderRequest) { const { refererInfo } = bidderRequest; return { - domain: parseDomain(refererInfo.topmostLocation) || '', - page: refererInfo.topmostLocation || '', - referrer: refererInfo.ref || getWindowSelf().document.referrer || '', - top: refererInfo.reachedTop + domain: parseDomain(refererInfo.topmostLocation) || "", + page: refererInfo.topmostLocation || "", + referrer: refererInfo.ref || getWindowSelf().document.referrer || "", + top: refererInfo.reachedTop, }; -}; +} function getElementFromTopWindow(element, currentWindow) { try { if (getWindowTop() === currentWindow) { - if (!element.getAttribute('id')) { - element.setAttribute('id', `adg-${getUniqueIdentifierStr()}`); + if (!element.getAttribute("id")) { + element.setAttribute("id", `adg-${getUniqueIdentifierStr()}`); } return element; } else { @@ -291,7 +299,10 @@ function getElementFromTopWindow(element, currentWindow) { const frameClientRect = frame.getBoundingClientRect(); const elementClientRect = element.getBoundingClientRect(); - if (frameClientRect.width !== elementClientRect.width || frameClientRect.height !== elementClientRect.height) { + if ( + frameClientRect.width !== elementClientRect.width || + frameClientRect.height !== elementClientRect.height + ) { return false; } @@ -301,7 +312,7 @@ function getElementFromTopWindow(element, currentWindow) { logWarn(`${LOG_PREFIX}`, err); return false; } -}; +} function autoDetectAdUnitElementIdFromGpt(adUnitCode) { const autoDetectedAdUnit = getGptSlotInfoForAdUnitCode(adUnitCode); @@ -309,16 +320,24 @@ function autoDetectAdUnitElementIdFromGpt(adUnitCode) { if (autoDetectedAdUnit.divId) { return autoDetectedAdUnit.divId; } -}; +} function isRendererPreferredFromPublisher(bidRequest) { // renderer defined at adUnit level - const adUnitRenderer = deepAccess(bidRequest, 'renderer'); - const hasValidAdUnitRenderer = !!(adUnitRenderer && adUnitRenderer.url && adUnitRenderer.render); + const adUnitRenderer = deepAccess(bidRequest, "renderer"); + const hasValidAdUnitRenderer = !!( + adUnitRenderer && + adUnitRenderer.url && + adUnitRenderer.render + ); // renderer defined at adUnit.mediaTypes level - const mediaTypeRenderer = deepAccess(bidRequest, 'mediaTypes.video.renderer'); - const hasValidMediaTypeRenderer = !!(mediaTypeRenderer && mediaTypeRenderer.url && mediaTypeRenderer.render); + const mediaTypeRenderer = deepAccess(bidRequest, "mediaTypes.video.renderer"); + const hasValidMediaTypeRenderer = !!( + mediaTypeRenderer && + mediaTypeRenderer.url && + mediaTypeRenderer.render + ); return !!( (hasValidAdUnitRenderer && !(adUnitRenderer.backupOnly === true)) || @@ -333,19 +352,27 @@ function isRendererPreferredFromPublisher(bidRequest) { */ function isNewSession(adagioStorage) { const now = Date.now(); - const { lastActivityTime, vwSmplg } = deepAccess(adagioStorage, 'session', {}); + const { lastActivityTime, vwSmplg } = deepAccess( + adagioStorage, + "session", + {} + ); return ( !isNumber(lastActivityTime) || !isNumber(vwSmplg) || - (now - lastActivityTime) > MAX_SESS_DURATION - ) + now - lastActivityTime > MAX_SESS_DURATION + ); } function setPlayerName(bidRequest) { - const playerName = (internal.isRendererPreferredFromPublisher(bidRequest)) ? 'other' : 'adagio'; - - if (playerName === 'other') { - logWarn(`${LOG_PREFIX} renderer.backupOnly has not been set. Adagio recommends to use its own player to get expected behavior.`); + const playerName = internal.isRendererPreferredFromPublisher(bidRequest) + ? "other" + : "adagio"; + + if (playerName === "other") { + logWarn( + `${LOG_PREFIX} renderer.backupOnly has not been set. Adagio recommends to use its own player to get expected behavior.` + ); } return playerName; @@ -362,58 +389,58 @@ export const internal = { getCurrentWindow, canAccessTopWindow, isRendererPreferredFromPublisher, - isNewSession + isNewSession, }; function _getGdprConsent(bidderRequest) { - if (!deepAccess(bidderRequest, 'gdprConsent')) { + if (!deepAccess(bidderRequest, "gdprConsent")) { return false; } - const { - apiVersion, - gdprApplies, - consentString, - allowAuctionWithoutConsent - } = bidderRequest.gdprConsent; + const { apiVersion, gdprApplies, consentString, allowAuctionWithoutConsent } = + bidderRequest.gdprConsent; return cleanObj({ apiVersion, consentString, consentRequired: gdprApplies ? 1 : 0, - allowAuctionWithoutConsent: allowAuctionWithoutConsent ? 1 : 0 + allowAuctionWithoutConsent: allowAuctionWithoutConsent ? 1 : 0, }); } function _getCoppa() { return { - required: config.getConfig('coppa') === true ? 1 : 0 + required: config.getConfig("coppa") === true ? 1 : 0, }; } function _getUspConsent(bidderRequest) { - return (deepAccess(bidderRequest, 'uspConsent')) ? { uspConsent: bidderRequest.uspConsent } : false; + return deepAccess(bidderRequest, "uspConsent") + ? { uspConsent: bidderRequest.uspConsent } + : false; } function _getSchain(bidRequest) { - return deepAccess(bidRequest, 'schain'); + return deepAccess(bidRequest, "schain"); } function _getEids(bidRequest) { - if (deepAccess(bidRequest, 'userId')) { - return createEidsArray(bidRequest.userId); + if (deepAccess(bidRequest, "userIdAsEids")) { + return bidRequest.bid.userIdAsEids; } } function _buildVideoBidRequest(bidRequest) { - const videoAdUnitParams = deepAccess(bidRequest, 'mediaTypes.video', {}); - const videoBidderParams = deepAccess(bidRequest, 'params.video', {}); + const videoAdUnitParams = deepAccess(bidRequest, "mediaTypes.video", {}); + const videoBidderParams = deepAccess(bidRequest, "params.video", {}); const computedParams = {}; // Special case for playerSize. // Eeach props will be overrided if they are defined in config. if (Array.isArray(videoAdUnitParams.playerSize)) { - const tempSize = (Array.isArray(videoAdUnitParams.playerSize[0])) ? videoAdUnitParams.playerSize[0] : videoAdUnitParams.playerSize; + const tempSize = Array.isArray(videoAdUnitParams.playerSize[0]) + ? videoAdUnitParams.playerSize[0] + : videoAdUnitParams.playerSize; computedParams.w = tempSize[0]; computedParams.h = tempSize[1]; } @@ -421,7 +448,7 @@ function _buildVideoBidRequest(bidRequest) { const videoParams = { ...computedParams, ...videoAdUnitParams, - ...videoBidderParams + ...videoBidderParams, }; if (videoParams.context && videoParams.context === OUTSTREAM) { @@ -431,13 +458,15 @@ function _buildVideoBidRequest(bidRequest) { // Only whitelisted OpenRTB options need to be validated. // Other options will still remain in the `mediaTypes.video` object // sent in the ad-request, but will be ignored by the SSP. - Object.keys(ORTB_VIDEO_PARAMS).forEach(paramName => { + Object.keys(ORTB_VIDEO_PARAMS).forEach((paramName) => { if (videoParams.hasOwnProperty(paramName)) { if (ORTB_VIDEO_PARAMS[paramName](videoParams[paramName])) { bidRequest.mediaTypes.video[paramName] = videoParams[paramName]; } else { delete bidRequest.mediaTypes.video[paramName]; - logWarn(`${LOG_PREFIX} The OpenRTB video param ${paramName} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.`); + logWarn( + `${LOG_PREFIX} The OpenRTB video param ${paramName} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.` + ); } } }); @@ -445,7 +474,7 @@ function _buildVideoBidRequest(bidRequest) { function _renderer(bid) { bid.renderer.push(() => { - if (typeof window.ADAGIO.outstreamPlayer === 'function') { + if (typeof window.ADAGIO.outstreamPlayer === "function") { window.ADAGIO.outstreamPlayer(bid); } else { logError(`${LOG_PREFIX} Adagio outstream player is not defined`); @@ -459,48 +488,48 @@ function _parseNativeBidResponse(bid) { return; } - const native = {} + const native = {}; function addAssetDataValue(data) { const map = { - 1: 'sponsoredBy', // sponsored - 2: 'body', // desc - 3: 'rating', - 4: 'likes', - 5: 'downloads', - 6: 'price', - 7: 'salePrice', - 8: 'phone', - 9: 'address', - 10: 'body2', // desc2 - 11: 'displayUrl', - 12: 'cta' - } - if (map.hasOwnProperty(data.type) && typeof data.value === 'string') { + 1: "sponsoredBy", // sponsored + 2: "body", // desc + 3: "rating", + 4: "likes", + 5: "downloads", + 6: "price", + 7: "salePrice", + 8: "phone", + 9: "address", + 10: "body2", // desc2 + 11: "displayUrl", + 12: "cta", + }; + if (map.hasOwnProperty(data.type) && typeof data.value === "string") { native[map[data.type]] = data.value; } } // assets - bid.admNative.assets.forEach(asset => { + bid.admNative.assets.forEach((asset) => { if (asset.title) { - native.title = asset.title.text + native.title = asset.title.text; } else if (asset.data) { - addAssetDataValue(asset.data) + addAssetDataValue(asset.data); } else if (asset.img) { switch (asset.img.type) { case 1: native.icon = { url: asset.img.url, width: asset.img.w, - height: asset.img.h + height: asset.img.h, }; break; default: native.image = { url: asset.img.url, width: asset.img.w, - height: asset.img.h + height: asset.img.h, }; break; } @@ -512,13 +541,13 @@ function _parseNativeBidResponse(bid) { native.clickUrl = bid.admNative.link.url; } if (Array.isArray(bid.admNative.link.clicktrackers)) { - native.clickTrackers = bid.admNative.link.clicktrackers + native.clickTrackers = bid.admNative.link.clicktrackers; } } if (Array.isArray(bid.admNative.eventtrackers)) { native.impressionTrackers = []; - bid.admNative.eventtrackers.forEach(tracker => { + bid.admNative.eventtrackers.forEach((tracker) => { // Only Impression events are supported. Prebid does not support Viewability events yet. if (tracker.event !== 1) { return; @@ -543,7 +572,9 @@ function _parseNativeBidResponse(bid) { } }); } else { - native.impressionTrackers = Array.isArray(bid.admNative.imptrackers) ? bid.admNative.imptrackers : []; + native.impressionTrackers = Array.isArray(bid.admNative.imptrackers) + ? bid.admNative.imptrackers + : []; if (bid.admNative.jstracker) { native.javascriptTrackers = bid.admNative.jstracker; } @@ -554,14 +585,14 @@ function _parseNativeBidResponse(bid) { } if (bid.admNative.ext) { - native.ext = {} + native.ext = {}; if (bid.admNative.ext.bvw) { native.ext.adagio_bvw = bid.admNative.ext.bvw; } } - bid.native = native + bid.native = native; } function _getFloors(bidRequest) { @@ -575,30 +606,41 @@ function _getFloors(bidRequest) { const info = bidRequest.getFloor({ currency: CURRENCY, mediaType, - size + size, }); - floors.push(cleanObj({ - mt: mediaType, - s: isArray(size) ? `${size[0]}x${size[1]}` : undefined, - f: (!isNaN(info.floor) && info.currency === CURRENCY) ? info.floor : undefined - })); - } + floors.push( + cleanObj({ + mt: mediaType, + s: isArray(size) ? `${size[0]}x${size[1]}` : undefined, + f: + !isNaN(info.floor) && info.currency === CURRENCY + ? info.floor + : undefined, + }) + ); + }; - Object.keys(bidRequest.mediaTypes).forEach(mediaType => { + Object.keys(bidRequest.mediaTypes).forEach((mediaType) => { if (SUPPORTED_MEDIA_TYPES.indexOf(mediaType) !== -1) { - const sizeProp = mediaType === VIDEO ? 'playerSize' : 'sizes'; + const sizeProp = mediaType === VIDEO ? "playerSize" : "sizes"; - if (bidRequest.mediaTypes[mediaType][sizeProp] && bidRequest.mediaTypes[mediaType][sizeProp].length) { + if ( + bidRequest.mediaTypes[mediaType][sizeProp] && + bidRequest.mediaTypes[mediaType][sizeProp].length + ) { if (isArray(bidRequest.mediaTypes[mediaType][sizeProp][0])) { - bidRequest.mediaTypes[mediaType][sizeProp].forEach(size => { + bidRequest.mediaTypes[mediaType][sizeProp].forEach((size) => { getAndPush(mediaType, [size[0], size[1]]); }); } else { - getAndPush(mediaType, [bidRequest.mediaTypes[mediaType][sizeProp][0], bidRequest.mediaTypes[mediaType][sizeProp][1]]); + getAndPush(mediaType, [ + bidRequest.mediaTypes[mediaType][sizeProp][0], + bidRequest.mediaTypes[mediaType][sizeProp][1], + ]); } } else { - getAndPush(mediaType, '*'); + getAndPush(mediaType, "*"); } } }); @@ -620,14 +662,16 @@ export function setExtraParam(bid, paramName) { bid.params = bid.params || {}; // eslint-disable-next-line - if (!!(bid.params[paramName])) { + if (!!bid.params[paramName]) { return; } - const adgGlobalConf = config.getConfig('adagio') || {}; + const adgGlobalConf = config.getConfig("adagio") || {}; const ortb2Conf = bid.ortb2; - const detected = adgGlobalConf[paramName] || deepAccess(ortb2Conf, `site.ext.data.${paramName}`, null); + const detected = + adgGlobalConf[paramName] || + deepAccess(ortb2Conf, `site.ext.data.${paramName}`, null); if (detected) { // First Party Data can be an array. // As we consider that params detected from FPD are fallbacks, we just keep the 1st value. @@ -644,62 +688,84 @@ export function setExtraParam(bid, paramName) { function autoFillParams(bid) { // adUnitElementId … - const adgGlobalConf = config.getConfig('adagio') || {}; + const adgGlobalConf = config.getConfig("adagio") || {}; bid.params = bid.params || {}; // adgGlobalConf.siteId is a shortcut to facilitate the integration for publisher. if (adgGlobalConf.siteId) { - bid.params.organizationId = adgGlobalConf.siteId.split(':')[0]; - bid.params.site = adgGlobalConf.siteId.split(':')[1]; + bid.params.organizationId = adgGlobalConf.siteId.split(":")[0]; + bid.params.site = adgGlobalConf.siteId.split(":")[1]; } // Edge case. Useful when Prebid Manager cannot handle properly params setting… - if (adgGlobalConf.useAdUnitCodeAsPlacement === true || bid.params.useAdUnitCodeAsPlacement === true) { + if ( + adgGlobalConf.useAdUnitCodeAsPlacement === true || + bid.params.useAdUnitCodeAsPlacement === true + ) { bid.params.placement = bid.adUnitCode; } - bid.params.adUnitElementId = deepAccess(bid, 'ortb2Imp.ext.data.elementId', null) || bid.params.adUnitElementId; + bid.params.adUnitElementId = + deepAccess(bid, "ortb2Imp.ext.data.elementId", null) || + bid.params.adUnitElementId; if (!bid.params.adUnitElementId) { - if (adgGlobalConf.useAdUnitCodeAsAdUnitElementId === true || bid.params.useAdUnitCodeAsAdUnitElementId === true) { + if ( + adgGlobalConf.useAdUnitCodeAsAdUnitElementId === true || + bid.params.useAdUnitCodeAsAdUnitElementId === true + ) { bid.params.adUnitElementId = bid.adUnitCode; } else { - bid.params.adUnitElementId = autoDetectAdUnitElementIdFromGpt(bid.adUnitCode); + bid.params.adUnitElementId = autoDetectAdUnitElementIdFromGpt( + bid.adUnitCode + ); } } // extra params - setExtraParam(bid, 'pagetype'); - setExtraParam(bid, 'category'); + setExtraParam(bid, "pagetype"); + setExtraParam(bid, "category"); } function getPageDimensions() { if (isSafeFrameWindow() || !canAccessTopWindow()) { - return ''; + return ""; } // the page dimension can be computed on window.top only. const wt = getWindowTop(); - const body = wt.document.querySelector('body'); + const body = wt.document.querySelector("body"); if (!body) { - return ''; + return ""; } const html = wt.document.documentElement; - const pageWidth = Math.max(body.scrollWidth, body.offsetWidth, html.clientWidth, html.scrollWidth, html.offsetWidth); - const pageHeight = Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight); + const pageWidth = Math.max( + body.scrollWidth, + body.offsetWidth, + html.clientWidth, + html.scrollWidth, + html.offsetWidth + ); + const pageHeight = Math.max( + body.scrollHeight, + body.offsetHeight, + html.clientHeight, + html.scrollHeight, + html.offsetHeight + ); return `${pageWidth}x${pageHeight}`; } /** -* @todo Move to prebid Core as Utils. -* @returns -*/ + * @todo Move to prebid Core as Utils. + * @returns + */ function getViewPortDimensions() { if (!isSafeFrameWindow() && !canAccessTopWindow()) { - return ''; + return ""; } const viewportDims = { w: 0, h: 0 }; @@ -707,16 +773,19 @@ function getViewPortDimensions() { if (isSafeFrameWindow()) { const ws = getWindowSelf(); - if (typeof ws.$sf.ext.geom !== 'function') { - logWarn(LOG_PREFIX, 'Unable to compute from safeframe api.'); - return ''; + if (typeof ws.$sf.ext.geom !== "function") { + logWarn(LOG_PREFIX, "Unable to compute from safeframe api."); + return ""; } const sfGeom = ws.$sf.ext.geom(); if (!sfGeom || !sfGeom.win) { - logWarn(LOG_PREFIX, 'Unable to compute from safeframe api. Missing `geom().win` property'); - return ''; + logWarn( + LOG_PREFIX, + "Unable to compute from safeframe api. Missing `geom().win` property" + ); + return ""; } viewportDims.w = Math.round(sfGeom.w); @@ -733,11 +802,11 @@ function getViewPortDimensions() { function getSlotPosition(adUnitElementId) { if (!adUnitElementId) { - return ''; + return ""; } if (!isSafeFrameWindow() && !canAccessTopWindow()) { - return ''; + return ""; } const position = { x: 0, y: 0 }; @@ -745,16 +814,19 @@ function getSlotPosition(adUnitElementId) { if (isSafeFrameWindow()) { const ws = getWindowSelf(); - if (typeof ws.$sf.ext.geom !== 'function') { - logWarn(LOG_PREFIX, 'Unable to compute from safeframe api.'); - return ''; + if (typeof ws.$sf.ext.geom !== "function") { + logWarn(LOG_PREFIX, "Unable to compute from safeframe api."); + return ""; } const sfGeom = ws.$sf.ext.geom(); if (!sfGeom || !sfGeom.self) { - logWarn(LOG_PREFIX, 'Unable to compute from safeframe api. Missing `geom().self` property'); - return ''; + logWarn( + LOG_PREFIX, + "Unable to compute from safeframe api. Missing `geom().self` property" + ); + return ""; } position.x = Math.round(sfGeom.t); @@ -776,7 +848,7 @@ function getSlotPosition(adUnitElementId) { } if (!domElement) { - return ''; + return ""; } let box = domElement.getBoundingClientRect(); @@ -789,13 +861,13 @@ function getSlotPosition(adUnitElementId) { const scrollLeft = wt.pageXOffset || docEl.scrollLeft || body.scrollLeft; const elComputedStyle = wt.getComputedStyle(domElement, null); - const elComputedDisplay = elComputedStyle.display || 'block'; - const mustDisplayElement = elComputedDisplay === 'none'; + const elComputedDisplay = elComputedStyle.display || "block"; + const mustDisplayElement = elComputedDisplay === "none"; if (mustDisplayElement) { domElement.style = domElement.style || {}; const originalDisplay = domElement.style.display; - domElement.style.display = 'block'; + domElement.style.display = "block"; box = domElement.getBoundingClientRect(); domElement.style.display = originalDisplay || null; } @@ -803,10 +875,10 @@ function getSlotPosition(adUnitElementId) { position.y = Math.round(box.top + scrollTop - clientTop); } catch (err) { logError(LOG_PREFIX, err); - return ''; + return ""; } } else { - return ''; + return ""; } return `${position.x}x${position.y}`; @@ -814,28 +886,41 @@ function getSlotPosition(adUnitElementId) { function getTimestampUTC() { // timestamp returned in seconds - return Math.floor(new Date().getTime() / 1000) - new Date().getTimezoneOffset() * 60; + return ( + Math.floor(new Date().getTime() / 1000) - + new Date().getTimezoneOffset() * 60 + ); } function getPrintNumber(adUnitCode, bidderRequest) { if (!bidderRequest.bids || !bidderRequest.bids.length) { return 1; } - const adagioBid = find(bidderRequest.bids, bid => bid.adUnitCode === adUnitCode); + const adagioBid = find( + bidderRequest.bids, + (bid) => bid.adUnitCode === adUnitCode + ); return adagioBid.bidderRequestsCount || 1; } /** - * domLoading feature is computed on window.top if reachable. - */ + * domLoading feature is computed on window.top if reachable. + */ function getDomLoadingDuration() { let domLoadingDuration = -1; let performance; - performance = (canAccessTopWindow()) ? getWindowTop().performance : getWindowSelf().performance; - - if (performance && performance.timing && performance.timing.navigationStart > 0) { - const val = performance.timing.domLoading - performance.timing.navigationStart; + performance = canAccessTopWindow() + ? getWindowTop().performance + : getWindowSelf().performance; + + if ( + performance && + performance.timing && + performance.timing.navigationStart > 0 + ) { + const val = + performance.timing.domLoading - performance.timing.navigationStart; if (val > 0) { domLoadingDuration = val; } @@ -849,28 +934,40 @@ function storeRequestInAdagioNS(bidRequest) { // Store adUnits config. // If an adUnitCode has already been stored, it will be replaced. w.ADAGIO = w.ADAGIO || {}; - w.ADAGIO.pbjsAdUnits = w.ADAGIO.pbjsAdUnits.filter((adUnit) => adUnit.code !== bidRequest.adUnitCode); + w.ADAGIO.pbjsAdUnits = w.ADAGIO.pbjsAdUnits.filter( + (adUnit) => adUnit.code !== bidRequest.adUnitCode + ); - let printNumber + let printNumber; if (bidRequest.features && bidRequest.features.print_number) { printNumber = bidRequest.features.print_number; - } else if (bidRequest.params.features && bidRequest.params.features.print_number) { + } else if ( + bidRequest.params.features && + bidRequest.params.features.print_number + ) { printNumber = bidRequest.params.features.print_number; } w.ADAGIO.pbjsAdUnits.push({ code: bidRequest.adUnitCode, mediaTypes: bidRequest.mediaTypes || {}, - sizes: (bidRequest.mediaTypes && bidRequest.mediaTypes.banner && Array.isArray(bidRequest.mediaTypes.banner.sizes)) ? bidRequest.mediaTypes.banner.sizes : bidRequest.sizes, - bids: [{ - bidder: bidRequest.bidder, - params: bidRequest.params // use the updated bid.params object with auto-detected params - }], + sizes: + bidRequest.mediaTypes && + bidRequest.mediaTypes.banner && + Array.isArray(bidRequest.mediaTypes.banner.sizes) + ? bidRequest.mediaTypes.banner.sizes + : bidRequest.sizes, + bids: [ + { + bidder: bidRequest.bidder, + params: bidRequest.params, // use the updated bid.params object with auto-detected params + }, + ], auctionId: bidRequest.auctionId, pageviewId: internal.getPageviewId(), printNumber, - localPbjs: '$$PREBID_GLOBAL$$', - localPbjsRef: getGlobal() + localPbjs: "$$PREBID_GLOBAL$$", + localPbjsRef: getGlobal(), }); // (legacy) Store internal adUnit information @@ -891,7 +988,9 @@ export const spec = { autoFillParams(bid); - if (!(bid.params.organizationId && bid.params.site && bid.params.placement)) { + if ( + !(bid.params.organizationId && bid.params.site && bid.params.placement) + ) { logWarn(`${LOG_PREFIX} at least one required param is missing.`); // internal.enqueue(debugData()); return false; @@ -904,7 +1003,7 @@ export const spec = { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); - const secure = (location.protocol === 'https:') ? 1 : 0; + const secure = location.protocol === "https:" ? 1 : 0; const device = internal.getDevice(); const site = internal.getSite(bidderRequest); const pageviewId = internal.getPageviewId(); @@ -913,19 +1012,23 @@ export const spec = { const coppa = _getCoppa(); const schain = _getSchain(validBidRequests[0]); const eids = _getEids(validBidRequests[0]) || []; - const syncEnabled = deepAccess(config.getConfig('userSync'), 'syncEnabled') - const usIfr = syncEnabled && userSync.canBidderRegisterSync('iframe', 'adagio') + const syncEnabled = deepAccess(config.getConfig("userSync"), "syncEnabled"); + const usIfr = + syncEnabled && userSync.canBidderRegisterSync("iframe", "adagio"); const adUnits = _map(validBidRequests, (bidRequest) => { const globalFeatures = GlobalExchange.getOrSetGlobalFeatures(); const features = { ...globalFeatures, - print_number: getPrintNumber(bidRequest.adUnitCode, bidderRequest).toString(), - adunit_position: getSlotPosition(bidRequest.params.adUnitElementId) // adUnitElementId à déplacer ??? + print_number: getPrintNumber( + bidRequest.adUnitCode, + bidderRequest + ).toString(), + adunit_position: getSlotPosition(bidRequest.params.adUnitElementId), // adUnitElementId à déplacer ??? }; Object.keys(features).forEach((prop) => { - if (features[prop] === '') { + if (features[prop] === "") { delete features[prop]; } }); @@ -933,57 +1036,78 @@ export const spec = { bidRequest.features = features; internal.enqueue({ - action: 'features', + action: "features", ts: Date.now(), data: { features: bidRequest.features, params: bidRequest.params, - adUnitCode: bidRequest.adUnitCode - } + adUnitCode: bidRequest.adUnitCode, + }, }); // Handle priceFloors module const computedFloors = _getFloors(bidRequest); if (isArray(computedFloors) && computedFloors.length) { - bidRequest.floors = computedFloors + bidRequest.floors = computedFloors; - if (deepAccess(bidRequest, 'mediaTypes.banner')) { - const bannerObj = bidRequest.mediaTypes.banner + if (deepAccess(bidRequest, "mediaTypes.banner")) { + const bannerObj = bidRequest.mediaTypes.banner; const computeNewSizeArray = (sizeArr = []) => { - const size = { size: sizeArr, floor: null } - const bannerFloors = bidRequest.floors.filter(floor => floor.mt === BANNER) - const BannerSizeFloor = bannerFloors.find(floor => floor.s === sizeArr.join('x')) - size.floor = (bannerFloors) ? (BannerSizeFloor) ? BannerSizeFloor.f : bannerFloors[0].f : null - return size - } + const size = { size: sizeArr, floor: null }; + const bannerFloors = bidRequest.floors.filter( + (floor) => floor.mt === BANNER + ); + const BannerSizeFloor = bannerFloors.find( + (floor) => floor.s === sizeArr.join("x") + ); + size.floor = bannerFloors + ? BannerSizeFloor + ? BannerSizeFloor.f + : bannerFloors[0].f + : null; + return size; + }; // `bannerSizes`, internal property name - bidRequest.mediaTypes.banner.bannerSizes = (isArray(bannerObj.sizes[0])) - ? bannerObj.sizes.map(sizeArr => { - return computeNewSizeArray(sizeArr) - }) - : computeNewSizeArray(bannerObj.sizes) + bidRequest.mediaTypes.banner.bannerSizes = isArray(bannerObj.sizes[0]) + ? bannerObj.sizes.map((sizeArr) => { + return computeNewSizeArray(sizeArr); + }) + : computeNewSizeArray(bannerObj.sizes); } - if (deepAccess(bidRequest, 'mediaTypes.video')) { - const videoObj = bidRequest.mediaTypes.video - const videoFloors = bidRequest.floors.filter(floor => floor.mt === VIDEO); - const playerSize = (videoObj.playerSize && isArray(videoObj.playerSize[0])) ? videoObj.playerSize[0] : videoObj.playerSize - const videoSizeFloor = (playerSize) ? videoFloors.find(floor => floor.s === playerSize.join('x')) : undefined - - bidRequest.mediaTypes.video.floor = (videoFloors) ? videoSizeFloor ? videoSizeFloor.f : videoFloors[0].f : null + if (deepAccess(bidRequest, "mediaTypes.video")) { + const videoObj = bidRequest.mediaTypes.video; + const videoFloors = bidRequest.floors.filter( + (floor) => floor.mt === VIDEO + ); + const playerSize = + videoObj.playerSize && isArray(videoObj.playerSize[0]) + ? videoObj.playerSize[0] + : videoObj.playerSize; + const videoSizeFloor = playerSize + ? videoFloors.find((floor) => floor.s === playerSize.join("x")) + : undefined; + + bidRequest.mediaTypes.video.floor = videoFloors + ? videoSizeFloor + ? videoSizeFloor.f + : videoFloors[0].f + : null; } - if (deepAccess(bidRequest, 'mediaTypes.native')) { - const nativeFloors = bidRequest.floors.filter(floor => floor.mt === NATIVE); + if (deepAccess(bidRequest, "mediaTypes.native")) { + const nativeFloors = bidRequest.floors.filter( + (floor) => floor.mt === NATIVE + ); if (nativeFloors.length) { - bidRequest.mediaTypes.native.floor = nativeFloors[0].f + bidRequest.mediaTypes.native.floor = nativeFloors[0].f; } } } - if (deepAccess(bidRequest, 'mediaTypes.video')) { + if (deepAccess(bidRequest, "mediaTypes.video")) { _buildVideoBidRequest(bidRequest); } @@ -995,24 +1119,26 @@ export const spec = { // Group ad units by organizationId const groupedAdUnits = adUnits.reduce((groupedAdUnits, adUnit) => { const adUnitCopy = deepClone(adUnit); - adUnitCopy.params.organizationId = adUnitCopy.params.organizationId.toString(); + adUnitCopy.params.organizationId = + adUnitCopy.params.organizationId.toString(); // remove useless props delete adUnitCopy.floorData; delete adUnitCopy.params.siteId; - delete adUnitCopy.userId - delete adUnitCopy.userIdAsEids + delete adUnitCopy.userId; + delete adUnitCopy.userIdAsEids; - groupedAdUnits[adUnitCopy.params.organizationId] = groupedAdUnits[adUnitCopy.params.organizationId] || []; + groupedAdUnits[adUnitCopy.params.organizationId] = + groupedAdUnits[adUnitCopy.params.organizationId] || []; groupedAdUnits[adUnitCopy.params.organizationId].push(adUnitCopy); return groupedAdUnits; }, {}); // Build one request per organizationId - const requests = _map(Object.keys(groupedAdUnits), organizationId => { + const requests = _map(Object.keys(groupedAdUnits), (organizationId) => { return { - method: 'POST', + method: "POST", url: ENDPOINT, data: { id: generateUUID(), @@ -1026,19 +1152,19 @@ export const spec = { regs: { gdpr: gdprConsent, coppa: coppa, - ccpa: uspConsent + ccpa: uspConsent, }, schain: schain, user: { - eids: eids + eids: eids, }, - prebidVersion: '$prebid.version$', + prebidVersion: "$prebid.version$", featuresVersion: FEATURES_VERSION, - usIfr: usIfr + usIfr: usIfr, }, options: { - contentType: 'text/plain' - } + contentType: "text/plain", + }, }; }); @@ -1052,25 +1178,36 @@ export const spec = { if (response) { if (response.data) { internal.enqueue({ - action: 'ssp-data', + action: "ssp-data", ts: Date.now(), - data: response.data + data: response.data, }); } if (response.bids) { - response.bids.forEach(bidObj => { - const bidReq = (find(bidRequest.data.adUnits, bid => bid.bidId === bidObj.requestId)); + response.bids.forEach((bidObj) => { + const bidReq = find( + bidRequest.data.adUnits, + (bid) => bid.bidId === bidObj.requestId + ); if (bidReq) { - bidObj.meta = deepAccess(bidObj, 'meta', {}); + bidObj.meta = deepAccess(bidObj, "meta", {}); bidObj.meta.mediaType = bidObj.mediaType; - bidObj.meta.advertiserDomains = (Array.isArray(bidObj.aDomain) && bidObj.aDomain.length) ? bidObj.aDomain : []; + bidObj.meta.advertiserDomains = + Array.isArray(bidObj.aDomain) && bidObj.aDomain.length + ? bidObj.aDomain + : []; if (bidObj.mediaType === VIDEO) { - const mediaTypeContext = deepAccess(bidReq, 'mediaTypes.video.context'); + const mediaTypeContext = deepAccess( + bidReq, + "mediaTypes.video.context" + ); // Adagio SSP returns a `vastXml` only. No `vastUrl` nor `videoCacheKey`. if (!bidObj.vastUrl && bidObj.vastXml) { - bidObj.vastUrl = 'data:text/xml;charset=utf-8;base64,' + btoa(bidObj.vastXml.replace(/\\"/g, '"')); + bidObj.vastUrl = + "data:text/xml;charset=utf-8;base64," + + btoa(bidObj.vastXml.replace(/\\"/g, '"')); } if (mediaTypeContext === OUTSTREAM) { @@ -1079,9 +1216,9 @@ export const spec = { adUnitCode: bidObj.adUnitCode, url: bidObj.urlRenderer || RENDERER_URL, config: { - ...deepAccess(bidReq, 'mediaTypes.video'), - ...deepAccess(bidObj, 'outstream', {}) - } + ...deepAccess(bidReq, "mediaTypes.video"), + ...deepAccess(bidObj, "outstream", {}), + }, }); bidObj.renderer.setRender(_renderer); @@ -1108,13 +1245,17 @@ export const spec = { }, getUserSyncs(syncOptions, serverResponses) { - if (!serverResponses.length || serverResponses[0].body === '' || !serverResponses[0].body.userSyncs) { + if ( + !serverResponses.length || + serverResponses[0].body === "" || + !serverResponses[0].body.userSyncs + ) { return false; } - const syncs = serverResponses[0].body.userSyncs.map(sync => ({ - type: sync.t === 'p' ? 'image' : 'iframe', - url: sync.u + const syncs = serverResponses[0].body.userSyncs.map((sync) => ({ + type: sync.t === "p" ? "image" : "iframe", + url: sync.u, })); return syncs; @@ -1130,26 +1271,35 @@ export const spec = { * @returns {object} updated params */ transformBidParams(params, isOrtb, adUnit, bidRequests) { - const adagioBidderRequest = find(bidRequests, bidRequest => bidRequest.bidderCode === 'adagio'); - const adagioBid = find(adagioBidderRequest.bids, bid => bid.adUnitCode === adUnit.code); + const adagioBidderRequest = find( + bidRequests, + (bidRequest) => bidRequest.bidderCode === "adagio" + ); + const adagioBid = find( + adagioBidderRequest.bids, + (bid) => bid.adUnitCode === adUnit.code + ); if (isOrtb) { autoFillParams(adagioBid); - adagioBid.params.auctionId = deepAccess(adagioBidderRequest, 'auctionId'); + adagioBid.params.auctionId = deepAccess(adagioBidderRequest, "auctionId"); const globalFeatures = GlobalExchange.getOrSetGlobalFeatures(); adagioBid.params.features = { ...globalFeatures, - print_number: getPrintNumber(adagioBid.adUnitCode, adagioBidderRequest).toString(), - adunit_position: getSlotPosition(adagioBid.params.adUnitElementId) // adUnitElementId à déplacer ??? + print_number: getPrintNumber( + adagioBid.adUnitCode, + adagioBidderRequest + ).toString(), + adunit_position: getSlotPosition(adagioBid.params.adUnitElementId), // adUnitElementId à déplacer ??? }; adagioBid.params.pageviewId = internal.getPageviewId(); - adagioBid.params.prebidVersion = '$prebid.version$'; + adagioBid.params.prebidVersion = "$prebid.version$"; adagioBid.params.data = GlobalExchange.getExchangeData(); - if (deepAccess(adagioBid, 'mediaTypes.video.context') === OUTSTREAM) { + if (deepAccess(adagioBid, "mediaTypes.video.context") === OUTSTREAM) { adagioBid.params.playerName = setPlayerName(adagioBid); } @@ -1157,7 +1307,7 @@ export const spec = { } return adagioBid.params; - } + }, }; initAdagio(); diff --git a/modules/adyoulikeBidAdapter.js b/modules/adyoulikeBidAdapter.js index e6cdc7698bf..2daee617d4e 100644 --- a/modules/adyoulikeBidAdapter.js +++ b/modules/adyoulikeBidAdapter.js @@ -1,45 +1,44 @@ -import {buildUrl, deepAccess, parseSizesInput} from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {createEidsArray} from './userId/eids.js'; -import {find} from '../src/polyfill.js'; -import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; - -const VERSION = '1.0'; -const BIDDER_CODE = 'adyoulike'; -const DEFAULT_DC = 'hb-api'; -const CURRENCY = 'USD'; +import { buildUrl, deepAccess, parseSizesInput } from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { find } from "../src/polyfill.js"; +import { BANNER, NATIVE, VIDEO } from "../src/mediaTypes.js"; +import { convertOrtbRequestToProprietaryNative } from "../src/native.js"; + +const VERSION = "1.0"; +const BIDDER_CODE = "adyoulike"; +const DEFAULT_DC = "hb-api"; +const CURRENCY = "USD"; const GVLID = 259; const NATIVE_IMAGE = { image: { - required: true + required: true, }, title: { - required: true + required: true, }, sponsoredBy: { - required: true + required: true, }, clickUrl: { - required: true + required: true, }, body: { - required: false + required: false, }, icon: { - required: false + required: false, }, cta: { - required: false - } + required: false, + }, }; export const spec = { code: BIDDER_CODE, gvlid: GVLID, supportedMediaTypes: [BANNER, NATIVE, VIDEO], - aliases: ['ayl'], // short code + aliases: ["ayl"], // short code /** * Determines whether or not the given bid request is valid. * @@ -51,8 +50,11 @@ export const spec = { const sizeValid = sizes.width > 0 && sizes.height > 0; // allows no size for native only - return (bid.params && bid.params.placement && - (sizeValid || (bid.mediaTypes && bid.mediaTypes.native))); + return ( + bid.params && + bid.params.placement && + (sizeValid || (bid.mediaTypes && bid.mediaTypes.native)) + ); }, /** * Make a server request from the list of BidRequests. @@ -75,8 +77,8 @@ export const spec = { accumulator[bidReq.bidId].TransactionID = bidReq.transactionId; accumulator[bidReq.bidId].Width = size.width; accumulator[bidReq.bidId].Height = size.height; - accumulator[bidReq.bidId].AvailableSizes = sizesArray.join(','); - if (typeof bidReq.getFloor === 'function') { + accumulator[bidReq.bidId].AvailableSizes = sizesArray.join(","); + if (typeof bidReq.getFloor === "function") { accumulator[bidReq.bidId].Pricing = getFloor(bidReq, size, mediatype); } if (bidReq.schain) { @@ -84,12 +86,12 @@ export const spec = { } if (mediatype === NATIVE) { let nativeReq = bidReq.mediaTypes.native; - if (nativeReq.type === 'image') { + if (nativeReq.type === "image") { nativeReq = Object.assign({}, NATIVE_IMAGE, nativeReq); } // click url is always mandatory even if not specified by publisher nativeReq.clickUrl = { - required: true + required: true, }; accumulator[bidReq.bidId].Native = nativeReq; } @@ -104,13 +106,16 @@ export const spec = { } return accumulator; }, {}), - PageRefreshed: getPageRefreshed() + PageRefreshed: getPageRefreshed(), }; if (bidderRequest.gdprConsent) { payload.gdprConsent = { consentString: bidderRequest.gdprConsent.consentString, - consentRequired: (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') ? bidderRequest.gdprConsent.gdprApplies : null + consentRequired: + typeof bidderRequest.gdprConsent.gdprApplies === "boolean" + ? bidderRequest.gdprConsent.gdprApplies + : null, }; } @@ -122,22 +127,22 @@ export const spec = { payload.ortb2 = bidderRequest.ortb2; } - if (deepAccess(bidderRequest, 'userId')) { - payload.userId = createEidsArray(bidderRequest.userId); + if (deepAccess(bidderRequest, "userIdAsEids")) { + payload.userId = bidderRequest.bid.userIdAsEids; } - payload.pbjs_version = '$prebid.version$'; + payload.pbjs_version = "$prebid.version$"; const data = JSON.stringify(payload); const options = { - withCredentials: true + withCredentials: true, }; return { - method: 'POST', + method: "POST", url: createEndpoint(bidRequests, bidderRequest, hasVideo), data, - options + options, }; }, /** @@ -157,34 +162,34 @@ export const spec = { } // For this adapter, serverResponse is a list - serverResponse.body.forEach(response => { + serverResponse.body.forEach((response) => { const bid = createBid(response, bidRequests); if (bid) { bidResponses.push(bid); } }); return bidResponses; - } -} + }, +}; /* Get hostname from bids */ function getHostname(bidderRequest) { - let dcHostname = find(bidderRequest, bid => bid.params.DC); + let dcHostname = find(bidderRequest, (bid) => bid.params.DC); if (dcHostname) { - return ('-' + dcHostname.params.DC); + return "-" + dcHostname.params.DC; } - return ''; + return ""; } /* Get mediatype from bidRequest */ function getMediatype(bidRequest) { - if (deepAccess(bidRequest, 'mediaTypes.banner')) { + if (deepAccess(bidRequest, "mediaTypes.banner")) { return BANNER; } - if (deepAccess(bidRequest, 'mediaTypes.video')) { + if (deepAccess(bidRequest, "mediaTypes.video")) { return VIDEO; } - if (deepAccess(bidRequest, 'mediaTypes.native')) { + if (deepAccess(bidRequest, "mediaTypes.native")) { return NATIVE; } } @@ -194,10 +199,10 @@ function getFloor(bidRequest, size, mediaType) { const bidFloors = bidRequest.getFloor({ currency: CURRENCY, mediaType, - size: [ size.width, size.height ] + size: [size.width, size.height], }); - if (!isNaN(bidFloors.floor) && (bidFloors.currency === CURRENCY)) { + if (!isNaN(bidFloors.floor) && bidFloors.currency === CURRENCY) { return bidFloors.floor; } } @@ -208,19 +213,19 @@ function getPageRefreshed() { if (performance && performance.navigation) { return performance.navigation.type === performance.navigation.TYPE_RELOAD; } - } catch (e) { } + } catch (e) {} return false; } /* Create endpoint url */ function createEndpoint(bidRequests, bidderRequest, hasVideo) { let host = getHostname(bidRequests); - const endpoint = hasVideo ? '/hb-api/prebid-video/v1' : '/hb-api/prebid/v1'; + const endpoint = hasVideo ? "/hb-api/prebid-video/v1" : "/hb-api/prebid/v1"; return buildUrl({ - protocol: 'https', + protocol: "https", host: `${DEFAULT_DC}${host}.omnitagjs.com`, pathname: endpoint, - search: createEndpointQS(bidderRequest) + search: createEndpointQS(bidderRequest), }); } @@ -269,7 +274,7 @@ function getSizeArray(bid) { if (bid.params && Array.isArray(bid.params.size)) { inputSize = bid.params.size; if (!Array.isArray(inputSize[0])) { - inputSize = [inputSize] + inputSize = [inputSize]; } } @@ -282,11 +287,11 @@ function getSize(sizesArray) { // the main requested size is the first one const size = sizesArray[0]; - if (typeof size !== 'string') { + if (typeof size !== "string") { return parsed; } - const parsedSize = size.toUpperCase().split('X'); + const parsedSize = size.toUpperCase().split("X"); const width = parseInt(parsedSize[0], 10); if (width) { parsed.width = width; @@ -301,30 +306,37 @@ function getSize(sizesArray) { } function getInternalImgUrl(uid) { - if (!uid) return ''; - return 'https://blobs.omnitagjs.com/blobs/' + uid.substr(16, 2) + '/' + uid.substr(16) + '/' + uid; + if (!uid) return ""; + return ( + "https://blobs.omnitagjs.com/blobs/" + + uid.substr(16, 2) + + "/" + + uid.substr(16) + + "/" + + uid + ); } function getImageUrl(config, resource, width, height) { - let url = ''; + let url = ""; if (resource && resource.Kind) { switch (resource.Kind) { - case 'INTERNAL': + case "INTERNAL": url = getInternalImgUrl(resource.Data.Internal.BlobReference.Uid); break; - case 'EXTERNAL': + case "EXTERNAL": const dynPrefix = config.DynamicPrefix; let extUrl = resource.Data.External.Url; - extUrl = extUrl.replace(/\[height\]/i, '' + height); - extUrl = extUrl.replace(/\[width\]/i, '' + width); + extUrl = extUrl.replace(/\[height\]/i, "" + height); + extUrl = extUrl.replace(/\[width\]/i, "" + width); if (extUrl.indexOf(dynPrefix) >= 0) { - const urlmatch = (/.*url=([^&]*)/gm).exec(extUrl); - url = urlmatch ? urlmatch[1] : ''; + const urlmatch = /.*url=([^&]*)/gm.exec(extUrl); + url = urlmatch ? urlmatch[1] : ""; if (!url) { - url = getInternalImgUrl((/.*key=([^&]*)/gm).exec(extUrl)[1]); + url = getInternalImgUrl(/.*key=([^&]*)/gm.exec(extUrl)[1]); } } else { url = extUrl; @@ -343,8 +355,10 @@ function getTrackers(eventsArray, jsTrackers) { if (!eventsArray) return result; eventsArray.map((item, index) => { - if ((jsTrackers && item.Kind === 'JAVASCRIPT_URL') || - (!jsTrackers && item.Kind === 'PIXEL_URL')) { + if ( + (jsTrackers && item.Kind === "JAVASCRIPT_URL") || + (!jsTrackers && item.Kind === "PIXEL_URL") + ) { result.push(item.Url); } }); @@ -352,34 +366,49 @@ function getTrackers(eventsArray, jsTrackers) { } function getNativeAssets(response, nativeConfig) { - if (typeof response.Native === 'object') { + if (typeof response.Native === "object") { return response.Native; } const native = {}; var adJson = {}; var textsJson = {}; - if (typeof response.Ad === 'string') { - adJson = JSON.parse(response.Ad.match(/\/\*PREBID\*\/(.*)\/\*PREBID\*\//)[1]); + if (typeof response.Ad === "string") { + adJson = JSON.parse( + response.Ad.match(/\/\*PREBID\*\/(.*)\/\*PREBID\*\//)[1] + ); textsJson = adJson.Content.Preview.Text; - var impressionUrl = adJson.TrackingPrefix + - '/pixel?event_kind=IMPRESSION&attempt=' + adJson.Attempt; - var insertionUrl = adJson.TrackingPrefix + - '/pixel?event_kind=INSERTION&attempt=' + adJson.Attempt; + var impressionUrl = + adJson.TrackingPrefix + + "/pixel?event_kind=IMPRESSION&attempt=" + + adJson.Attempt; + var insertionUrl = + adJson.TrackingPrefix + + "/pixel?event_kind=INSERTION&attempt=" + + adJson.Attempt; if (adJson.Campaign) { - impressionUrl += '&campaign=' + adJson.Campaign; - insertionUrl += '&campaign=' + adJson.Campaign; + impressionUrl += "&campaign=" + adJson.Campaign; + insertionUrl += "&campaign=" + adJson.Campaign; } - native.clickUrl = adJson.TrackingPrefix + '/ar?event_kind=CLICK&attempt=' + adJson.Attempt + - '&campaign=' + adJson.Campaign + '&url=' + encodeURIComponent(adJson.Content.Landing.Url); + native.clickUrl = + adJson.TrackingPrefix + + "/ar?event_kind=CLICK&attempt=" + + adJson.Attempt + + "&campaign=" + + adJson.Campaign + + "&url=" + + encodeURIComponent(adJson.Content.Landing.Url); if (adJson.OnEvents) { - native.clickTrackers = getTrackers(adJson.OnEvents['CLICK']); - native.impressionTrackers = getTrackers(adJson.OnEvents['IMPRESSION']); - native.javascriptTrackers = getTrackers(adJson.OnEvents['IMPRESSION'], true); + native.clickTrackers = getTrackers(adJson.OnEvents["CLICK"]); + native.impressionTrackers = getTrackers(adJson.OnEvents["IMPRESSION"]); + native.javascriptTrackers = getTrackers( + adJson.OnEvents["IMPRESSION"], + true + ); } else { native.impressionTrackers = []; } @@ -387,21 +416,21 @@ function getNativeAssets(response, nativeConfig) { native.impressionTrackers.push(impressionUrl, insertionUrl); } - Object.keys(nativeConfig).map(function(key, index) { + Object.keys(nativeConfig).map(function (key, index) { switch (key) { - case 'title': + case "title": native[key] = textsJson.TITLE; break; - case 'body': + case "body": native[key] = textsJson.DESCRIPTION; break; - case 'cta': + case "cta": native[key] = textsJson.CALLTOACTION; break; - case 'sponsoredBy': + case "sponsoredBy": native[key] = adJson.Content.Preview.Sponsor.Name; break; - case 'image': + case "image": // main image requested size const imgSize = nativeConfig.image.sizes || []; if (!imgSize.length) { @@ -409,17 +438,22 @@ function getNativeAssets(response, nativeConfig) { imgSize[1] = response.Height || 250; } - const url = getImageUrl(adJson, deepAccess(adJson, 'Content.Preview.Thumbnail.Image'), imgSize[0], imgSize[1]); + const url = getImageUrl( + adJson, + deepAccess(adJson, "Content.Preview.Thumbnail.Image"), + imgSize[0], + imgSize[1] + ); if (url) { native[key] = { url, width: imgSize[0], - height: imgSize[1] + height: imgSize[1], }; } break; - case 'icon': + case "icon": // icon requested size const iconSize = nativeConfig.icon.sizes || []; if (!iconSize.length) { @@ -427,21 +461,31 @@ function getNativeAssets(response, nativeConfig) { iconSize[1] = 50; } - const icurl = getImageUrl(adJson, deepAccess(adJson, 'Content.Preview.Sponsor.Logo.Resource'), iconSize[0], iconSize[1]); + const icurl = getImageUrl( + adJson, + deepAccess(adJson, "Content.Preview.Sponsor.Logo.Resource"), + iconSize[0], + iconSize[1] + ); if (icurl) { native[key] = { url: icurl, width: iconSize[0], - height: iconSize[1] + height: iconSize[1], }; } break; - case 'privacyIcon': - native[key] = getImageUrl(adJson, deepAccess(adJson, 'Content.Preview.Credit.Logo.Resource'), 25, 25); + case "privacyIcon": + native[key] = getImageUrl( + adJson, + deepAccess(adJson, "Content.Preview.Credit.Logo.Resource"), + 25, + 25 + ); break; - case 'privacyLink': - native[key] = deepAccess(adJson, 'Content.Preview.Credit.Url'); + case "privacyLink": + native[key] = deepAccess(adJson, "Content.Preview.Credit.Url"); break; } }); @@ -459,11 +503,11 @@ function createBid(response, bidRequests) { // In case we don't retreive the size from the adserver, use the given one. if (request) { - if (!response.Width || response.Width === '0') { + if (!response.Width || response.Width === "0") { response.Width = request.Width; } - if (!response.Height || response.Height === '0') { + if (!response.Height || response.Height === "0") { response.Height = request.Height; } } @@ -475,7 +519,7 @@ function createBid(response, bidRequests) { cpm: response.Price, netRevenue: true, currency: CURRENCY, - meta: response.Meta || { advertiserDomains: [] } + meta: response.Meta || { advertiserDomains: [] }, }; // retreive video response if present @@ -484,11 +528,11 @@ function createBid(response, bidRequests) { bid.width = response.Width; bid.height = response.Height; bid.vastXml = window.atob(vast64); - bid.mediaType = 'video'; + bid.mediaType = "video"; } else if (request.Native) { // format Native response if Native was requested bid.native = getNativeAssets(response, request.Native); - bid.mediaType = 'native'; + bid.mediaType = "native"; } else { bid.width = response.Width; bid.height = response.Height; diff --git a/modules/bluebillywigBidAdapter.js b/modules/bluebillywigBidAdapter.js index 27e310177f6..c0fbb16d0e6 100644 --- a/modules/bluebillywigBidAdapter.js +++ b/modules/bluebillywigBidAdapter.js @@ -1,27 +1,59 @@ -import {deepAccess, deepClone, deepSetValue, logError, logWarn} from '../src/utils.js'; -import {find} from '../src/polyfill.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {VIDEO} from '../src/mediaTypes.js'; -import {config} from '../src/config.js'; -import {Renderer} from '../src/Renderer.js'; -import {createEidsArray} from './userId/eids.js'; +import { + deepAccess, + deepClone, + deepSetValue, + logError, + logWarn, +} from "../src/utils.js"; +import { find } from "../src/polyfill.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { VIDEO } from "../src/mediaTypes.js"; +import { config } from "../src/config.js"; +import { Renderer } from "../src/Renderer.js"; const DEV_MODE = window.location.search.match(/bbpbs_debug=true/); // Blue Billywig Constants const BB_CONSTANTS = { - BIDDER_CODE: 'bluebillywig', - AUCTION_URL: '$$URL_STARTpbs.bluebillywig.com/openrtb2/auction?pub=$$PUBLICATION', - SYNC_URL: '$$URL_STARTpbs.bluebillywig.com/static/cookie-sync.html?pub=$$PUBLICATION', - RENDERER_URL: 'https://$$PUBLICATION.bbvms.com/r/$$RENDERER.js', + BIDDER_CODE: "bluebillywig", + AUCTION_URL: + "$$URL_STARTpbs.bluebillywig.com/openrtb2/auction?pub=$$PUBLICATION", + SYNC_URL: + "$$URL_STARTpbs.bluebillywig.com/static/cookie-sync.html?pub=$$PUBLICATION", + RENDERER_URL: "https://$$PUBLICATION.bbvms.com/r/$$RENDERER.js", DEFAULT_TIMEOUT: 5000, DEFAULT_TTL: 300, DEFAULT_WIDTH: 768, DEFAULT_HEIGHT: 432, DEFAULT_NET_REVENUE: true, - VIDEO_PARAMS: ['mimes', 'minduration', 'maxduration', 'protocols', 'w', 'h', 'startdelay', 'placement', 'linearity', 'skip', 'skipmin', - 'skipafter', 'sequence', 'battr', 'maxextended', 'minbitrate', 'maxbitrate', 'boxingallowed', 'playbackmethod', 'playbackend', 'delivery', 'pos', 'companionad', - 'api', 'companiontype', 'ext'] + VIDEO_PARAMS: [ + "mimes", + "minduration", + "maxduration", + "protocols", + "w", + "h", + "startdelay", + "placement", + "linearity", + "skip", + "skipmin", + "skipafter", + "sequence", + "battr", + "maxextended", + "minbitrate", + "maxbitrate", + "boxingallowed", + "playbackmethod", + "playbackend", + "delivery", + "pos", + "companionad", + "api", + "companiontype", + "ext", + ], }; // Aliasing @@ -29,69 +61,85 @@ const getConfig = config.getConfig; // Helper Functions const BB_HELPERS = { - addSiteAppDevice: function(request, pageUrl) { - if (typeof getConfig('app') === 'object') request.app = getConfig('app'); + addSiteAppDevice: function (request, pageUrl) { + if (typeof getConfig("app") === "object") request.app = getConfig("app"); else { request.site = {}; - if (typeof getConfig('site') === 'object') request.site = getConfig('site'); + if (typeof getConfig("site") === "object") + request.site = getConfig("site"); if (pageUrl) request.site.page = pageUrl; } - if (typeof getConfig('device') === 'object') request.device = getConfig('device'); + if (typeof getConfig("device") === "object") + request.device = getConfig("device"); if (!request.device) request.device = {}; if (!request.device.w) request.device.w = window.innerWidth; if (!request.device.h) request.device.h = window.innerHeight; }, - addSchain: function(request, validBidRequests) { - const schain = deepAccess(validBidRequests, '0.schain'); + addSchain: function (request, validBidRequests) { + const schain = deepAccess(validBidRequests, "0.schain"); if (schain) request.source.ext = { schain: schain }; }, - addCurrency: function(request) { - const adServerCur = getConfig('currency.adServerCurrency'); - if (adServerCur && typeof adServerCur === 'string') request.cur = [adServerCur]; - else if (Array.isArray(adServerCur) && adServerCur.length) request.cur = [adServerCur[0]]; + addCurrency: function (request) { + const adServerCur = getConfig("currency.adServerCurrency"); + if (adServerCur && typeof adServerCur === "string") + request.cur = [adServerCur]; + else if (Array.isArray(adServerCur) && adServerCur.length) + request.cur = [adServerCur[0]]; }, - addUserIds: function(request, validBidRequests) { - const bidUserId = deepAccess(validBidRequests, '0.userId'); - const eids = createEidsArray(bidUserId); + addUserIds: function (request, validBidRequests) { + const bidUserId = deepAccess(validBidRequests[0], "userIdAsEids"); + const eids = bidUserId; if (eids.length) { - deepSetValue(request, 'user.ext.eids', eids); + deepSetValue(request, "user.ext.eids", eids); } }, substituteUrl: function (url, publication, renderer) { - return url.replace('$$URL_START', (DEV_MODE) ? 'https://dev.' : 'https://').replace('$$PUBLICATION', publication).replace('$$RENDERER', renderer); + return url + .replace("$$URL_START", DEV_MODE ? "https://dev." : "https://") + .replace("$$PUBLICATION", publication) + .replace("$$RENDERER", renderer); }, - getAuctionUrl: function(publication) { + getAuctionUrl: function (publication) { return BB_HELPERS.substituteUrl(BB_CONSTANTS.AUCTION_URL, publication); }, - getSyncUrl: function(publication) { + getSyncUrl: function (publication) { return BB_HELPERS.substituteUrl(BB_CONSTANTS.SYNC_URL, publication); }, - getRendererUrl: function(publication, renderer) { - return BB_HELPERS.substituteUrl(BB_CONSTANTS.RENDERER_URL, publication, renderer); + getRendererUrl: function (publication, renderer) { + return BB_HELPERS.substituteUrl( + BB_CONSTANTS.RENDERER_URL, + publication, + renderer + ); }, - transformVideoParams: function(videoParams, videoParamsExt) { + transformVideoParams: function (videoParams, videoParamsExt) { videoParams = deepClone(videoParams); - let playerSize = videoParams.playerSize || [BB_CONSTANTS.DEFAULT_WIDTH, BB_CONSTANTS.DEFAULT_HEIGHT]; + let playerSize = videoParams.playerSize || [ + BB_CONSTANTS.DEFAULT_WIDTH, + BB_CONSTANTS.DEFAULT_HEIGHT, + ]; if (Array.isArray(playerSize[0])) playerSize = playerSize[0]; videoParams.w = playerSize[0]; videoParams.h = playerSize[1]; videoParams.placement = 3; - if (videoParamsExt) videoParams = Object.assign(videoParams, videoParamsExt); + if (videoParamsExt) + videoParams = Object.assign(videoParams, videoParamsExt); const videoParamsProperties = Object.keys(videoParams); - videoParamsProperties.forEach(property => { - if (BB_CONSTANTS.VIDEO_PARAMS.indexOf(property) === -1) delete videoParams[property]; + videoParamsProperties.forEach((property) => { + if (BB_CONSTANTS.VIDEO_PARAMS.indexOf(property) === -1) + delete videoParams[property]; }); return videoParams; }, - transformRTBToPrebidProps: function(bid, serverResponse) { + transformRTBToPrebidProps: function (bid, serverResponse) { const bidObject = { cpm: bid.price, currency: serverResponse.cur, @@ -102,16 +150,26 @@ const BB_HELPERS = { mediaType: VIDEO, width: bid.w || BB_CONSTANTS.DEFAULT_WIDTH, height: bid.h || BB_CONSTANTS.DEFAULT_HEIGHT, - ttl: BB_CONSTANTS.DEFAULT_TTL + ttl: BB_CONSTANTS.DEFAULT_TTL, }; - const extPrebidTargeting = deepAccess(bid, 'ext.prebid.targeting'); - const extPrebidCache = deepAccess(bid, 'ext.prebid.cache'); + const extPrebidTargeting = deepAccess(bid, "ext.prebid.targeting"); + const extPrebidCache = deepAccess(bid, "ext.prebid.cache"); - if (extPrebidCache && typeof extPrebidCache.vastXml === 'object' && extPrebidCache.vastXml.cacheId && extPrebidCache.vastXml.url) { + if ( + extPrebidCache && + typeof extPrebidCache.vastXml === "object" && + extPrebidCache.vastXml.cacheId && + extPrebidCache.vastXml.url + ) { bidObject.videoCacheKey = extPrebidCache.vastXml.cacheId; bidObject.vastUrl = extPrebidCache.vastXml.url; - } else if (extPrebidTargeting && extPrebidTargeting.hb_uuid && extPrebidTargeting.hb_cache_host && extPrebidTargeting.hb_cache_path) { + } else if ( + extPrebidTargeting && + extPrebidTargeting.hb_uuid && + extPrebidTargeting.hb_cache_host && + extPrebidTargeting.hb_cache_path + ) { bidObject.videoCacheKey = extPrebidTargeting.hb_uuid; bidObject.vastUrl = `https://${extPrebidTargeting.hb_cache_host}${extPrebidTargeting.hb_cache_path}?uuid=${extPrebidTargeting.hb_uuid}`; } @@ -119,18 +177,21 @@ const BB_HELPERS = { bidObject.ad = bid.adm; bidObject.vastXml = bid.adm; } - if (!bidObject.vastUrl && bid.nurl && !bid.adm) { // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5 + if (!bidObject.vastUrl && bid.nurl && !bid.adm) { + // ad markup is on win notice url, and adm is ommited according to OpenRTB 2.5 bidObject.vastUrl = bid.nurl; } bidObject.meta = bid.meta || {}; - if (bid.adomain) { bidObject.meta.advertiserDomains = bid.adomain; } + if (bid.adomain) { + bidObject.meta.advertiserDomains = bid.adomain; + } return bidObject; }, }; // Renderer Functions const BB_RENDERER = { - bootstrapPlayer: function(bid) { + bootstrapPlayer: function (bid) { const config = { code: bid.adUnitCode, }; @@ -139,43 +200,61 @@ const BB_RENDERER = { else if (bid.vastUrl) config.vastUrl = bid.vastUrl; if (!bid.vastXml && !bid.vastUrl) { - logWarn(`${BB_CONSTANTS.BIDDER_CODE}: No vastXml or vastUrl on bid, bailing...`); + logWarn( + `${BB_CONSTANTS.BIDDER_CODE}: No vastXml or vastUrl on bid, bailing...` + ); return; } if (!(window.bluebillywig && window.bluebillywig.renderers)) { - logWarn(`${BB_CONSTANTS.BIDDER_CODE}: renderer code failed to initialize...`); + logWarn( + `${BB_CONSTANTS.BIDDER_CODE}: renderer code failed to initialize...` + ); return; } - const rendererId = BB_RENDERER.getRendererId(bid.publicationName, bid.rendererCode); + const rendererId = BB_RENDERER.getRendererId( + bid.publicationName, + bid.rendererCode + ); const ele = document.getElementById(bid.adUnitCode); // NB convention - const renderer = find(window.bluebillywig.renderers, r => r._id === rendererId); + const renderer = find( + window.bluebillywig.renderers, + (r) => r._id === rendererId + ); if (renderer) renderer.bootstrap(config, ele, bid.rendererSettings || {}); - else logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}`); + else + logWarn( + `${BB_CONSTANTS.BIDDER_CODE}: Couldn't find a renderer with ${rendererId}` + ); }, - newRenderer: function(rendererUrl, adUnitCode) { + newRenderer: function (rendererUrl, adUnitCode) { const renderer = Renderer.install({ url: rendererUrl, loaded: false, - adUnitCode + adUnitCode, }); try { renderer.setRender(BB_RENDERER.outstreamRender); } catch (err) { - logWarn(`${BB_CONSTANTS.BIDDER_CODE}: Error tying to setRender on renderer`, err); + logWarn( + `${BB_CONSTANTS.BIDDER_CODE}: Error tying to setRender on renderer`, + err + ); } return renderer; }, - outstreamRender: function(bid) { - bid.renderer.push(function() { BB_RENDERER.bootstrapPlayer(bid) }); + outstreamRender: function (bid) { + bid.renderer.push(function () { + BB_RENDERER.bootstrapPlayer(bid); + }); }, - getRendererId: function(pub, renderer) { + getRendererId: function (pub, renderer) { return `${pub}-${renderer}`; // NB convention! - } + }, }; // Spec Functions @@ -183,76 +262,134 @@ const BB_RENDERER = { export const spec = { code: BB_CONSTANTS.BIDDER_CODE, supportedMediaTypes: [VIDEO], - syncStore: { bidders: [], }, + syncStore: { bidders: [] }, isBidRequestValid(bid) { const publicationNameRegex = /^\w+\.?\w+$/; const rendererRegex = /^[\w+_]+$/; if (!bid.params) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no params set on bid. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no params set on bid. Rejecting bid: `, + bid + ); return false; } - if (!bid.params.hasOwnProperty('publicationName') || typeof bid.params.publicationName !== 'string') { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no publicationName specified in bid params, or it's not a string. Rejecting bid: `, bid); + if ( + !bid.params.hasOwnProperty("publicationName") || + typeof bid.params.publicationName !== "string" + ) { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no publicationName specified in bid params, or it's not a string. Rejecting bid: `, + bid + ); return false; } else if (!publicationNameRegex.test(bid.params.publicationName)) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: publicationName must be in format 'publication' or 'publication.environment'. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: publicationName must be in format 'publication' or 'publication.environment'. Rejecting bid: `, + bid + ); return false; } - if ((!bid.params.hasOwnProperty('rendererCode') || typeof bid.params.rendererCode !== 'string')) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no rendererCode was specified in bid params. Rejecting bid: `, bid); + if ( + !bid.params.hasOwnProperty("rendererCode") || + typeof bid.params.rendererCode !== "string" + ) { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no rendererCode was specified in bid params. Rejecting bid: `, + bid + ); return false; } else if (!rendererRegex.test(bid.params.rendererCode)) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: rendererCode must be alphanumeric, including underscores. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: rendererCode must be alphanumeric, including underscores. Rejecting bid: `, + bid + ); return false; } if (!bid.params.accountId) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no accountId specified in bid params. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no accountId specified in bid params. Rejecting bid: `, + bid + ); return false; } - if (bid.params.hasOwnProperty('connections')) { + if (bid.params.hasOwnProperty("connections")) { if (!Array.isArray(bid.params.connections)) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: connections is not of type array. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: connections is not of type array. Rejecting bid: `, + bid + ); return false; } else { for (let i = 0; i < bid.params.connections.length; i++) { if (!bid.params.hasOwnProperty(bid.params.connections[i])) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: connection specified in params.connections, but not configured in params. Rejecting bid: `, + bid + ); return false; } } } } else { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no connections specified in bid. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no connections specified in bid. Rejecting bid: `, + bid + ); return false; } - if (bid.params.hasOwnProperty('video') && (bid.params.video === null || typeof bid.params.video !== 'object')) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: params.video must be of type object. Rejecting bid: `, bid); + if ( + bid.params.hasOwnProperty("video") && + (bid.params.video === null || typeof bid.params.video !== "object") + ) { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: params.video must be of type object. Rejecting bid: `, + bid + ); return false; } - if (bid.params.hasOwnProperty('rendererSettings') && (bid.params.rendererSettings === null || typeof bid.params.rendererSettings !== 'object')) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: params.rendererSettings must be of type object. Rejecting bid: `, bid); + if ( + bid.params.hasOwnProperty("rendererSettings") && + (bid.params.rendererSettings === null || + typeof bid.params.rendererSettings !== "object") + ) { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: params.rendererSettings must be of type object. Rejecting bid: `, + bid + ); return false; } - if (bid.hasOwnProperty('mediaTypes') && bid.mediaTypes.hasOwnProperty(VIDEO)) { - if (!bid.mediaTypes[VIDEO].hasOwnProperty('context')) { - logError(`${BB_CONSTANTS.BIDDER_CODE}: no context specified in bid. Rejecting bid: `, bid); + if ( + bid.hasOwnProperty("mediaTypes") && + bid.mediaTypes.hasOwnProperty(VIDEO) + ) { + if (!bid.mediaTypes[VIDEO].hasOwnProperty("context")) { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: no context specified in bid. Rejecting bid: `, + bid + ); return false; } - if (bid.mediaTypes[VIDEO].context !== 'outstream') { - logError(`${BB_CONSTANTS.BIDDER_CODE}: video.context is invalid, must be "outstream". Rejecting bid: `, bid); + if (bid.mediaTypes[VIDEO].context !== "outstream") { + logError( + `${BB_CONSTANTS.BIDDER_CODE}: video.context is invalid, must be "outstream". Rejecting bid: `, + bid + ); return false; } } else { - logError(`${BB_CONSTANTS.BIDDER_CODE}: mediaTypes or mediaTypes.video is not specified. Rejecting bid: `, bid); + logError( + `${BB_CONSTANTS.BIDDER_CODE}: mediaTypes or mediaTypes.video is not specified. Rejecting bid: `, + bid + ); return false; } @@ -261,84 +398,115 @@ export const spec = { buildRequests(validBidRequests, bidderRequest) { const imps = []; - validBidRequests.forEach(validBidRequest => { - if (!this.syncStore.publicationName) this.syncStore.publicationName = validBidRequest.params.publicationName; - if (!this.syncStore.accountId) this.syncStore.accountId = validBidRequest.params.accountId; - - const ext = validBidRequest.params.connections.reduce((extBuilder, connection) => { - extBuilder[connection] = validBidRequest.params[connection]; - - if (this.syncStore.bidders.indexOf(connection) === -1) this.syncStore.bidders.push(connection); - - return extBuilder; - }, {}); - - const videoParams = BB_HELPERS.transformVideoParams(deepAccess(validBidRequest, 'mediaTypes.video'), deepAccess(validBidRequest, 'params.video')); - imps.push({ id: validBidRequest.bidId, ext, secure: window.location.protocol === 'https' ? 1 : 0, video: videoParams }); + validBidRequests.forEach((validBidRequest) => { + if (!this.syncStore.publicationName) + this.syncStore.publicationName = validBidRequest.params.publicationName; + if (!this.syncStore.accountId) + this.syncStore.accountId = validBidRequest.params.accountId; + + const ext = validBidRequest.params.connections.reduce( + (extBuilder, connection) => { + extBuilder[connection] = validBidRequest.params[connection]; + + if (this.syncStore.bidders.indexOf(connection) === -1) + this.syncStore.bidders.push(connection); + + return extBuilder; + }, + {} + ); + + const videoParams = BB_HELPERS.transformVideoParams( + deepAccess(validBidRequest, "mediaTypes.video"), + deepAccess(validBidRequest, "params.video") + ); + imps.push({ + id: validBidRequest.bidId, + ext, + secure: window.location.protocol === "https" ? 1 : 0, + video: videoParams, + }); }); const request = { id: bidderRequest.auctionId, - source: {tid: bidderRequest.auctionId}, + source: { tid: bidderRequest.auctionId }, tmax: BB_CONSTANTS.DEFAULT_TIMEOUT, imp: imps, test: DEV_MODE ? 1 : 0, ext: { prebid: { - targeting: { includewinners: true, includebidderkeys: false } - } - } + targeting: { includewinners: true, includebidderkeys: false }, + }, + }, }; // handle privacy settings for GDPR/CCPA/COPPA if (bidderRequest.gdprConsent) { let gdprApplies = 0; - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - deepSetValue(request, 'regs.ext.gdpr', gdprApplies); - deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + if (typeof bidderRequest.gdprConsent.gdprApplies === "boolean") + gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + deepSetValue(request, "regs.ext.gdpr", gdprApplies); + deepSetValue( + request, + "user.ext.consent", + bidderRequest.gdprConsent.consentString + ); } if (bidderRequest.uspConsent) { - deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + deepSetValue(request, "regs.ext.us_privacy", bidderRequest.uspConsent); this.syncStore.uspConsent = bidderRequest.uspConsent; } - if (getConfig('coppa') == true) deepSetValue(request, 'regs.coppa', 1); + if (getConfig("coppa") == true) deepSetValue(request, "regs.coppa", 1); // Enrich the request with any external data we may have - BB_HELPERS.addSiteAppDevice(request, bidderRequest.refererInfo && bidderRequest.refererInfo.page); + BB_HELPERS.addSiteAppDevice( + request, + bidderRequest.refererInfo && bidderRequest.refererInfo.page + ); BB_HELPERS.addSchain(request, validBidRequests); BB_HELPERS.addCurrency(request); BB_HELPERS.addUserIds(request, validBidRequests); return { - method: 'POST', + method: "POST", url: BB_HELPERS.getAuctionUrl(validBidRequests[0].params.publicationName), data: JSON.stringify(request), - bidderRequest: bidderRequest + bidderRequest: bidderRequest, }; }, interpretResponse(serverResponse, request) { serverResponse = serverResponse.body || {}; - if (!serverResponse.hasOwnProperty('seatbid') || !Array.isArray(serverResponse.seatbid)) { + if ( + !serverResponse.hasOwnProperty("seatbid") || + !Array.isArray(serverResponse.seatbid) + ) { return []; } const bids = []; - serverResponse.seatbid.forEach(seatbid => { + serverResponse.seatbid.forEach((seatbid) => { if (!seatbid.bid || !Array.isArray(seatbid.bid)) return; - seatbid.bid.forEach(bid => { + seatbid.bid.forEach((bid) => { bid = BB_HELPERS.transformRTBToPrebidProps(bid, serverResponse); - const bidParams = find(request.bidderRequest.bids, bidderRequestBid => bidderRequestBid.bidId === bid.bidId).params; + const bidParams = find( + request.bidderRequest.bids, + (bidderRequestBid) => bidderRequestBid.bidId === bid.bidId + ).params; bid.publicationName = bidParams.publicationName; bid.rendererCode = bidParams.rendererCode; bid.accountId = bidParams.accountId; bid.rendererSettings = bidParams.rendererSettings; - const rendererUrl = BB_HELPERS.getRendererUrl(bid.publicationName, bid.rendererCode); + const rendererUrl = BB_HELPERS.getRendererUrl( + bid.publicationName, + bid.rendererCode + ); bid.renderer = BB_RENDERER.newRenderer(rendererUrl, bid.adUnitCode); bids.push(bid); @@ -353,24 +521,32 @@ export const spec = { const queryString = []; if (gdpr.gdprApplies) queryString.push(`gdpr=${gdpr.gdprApplies ? 1 : 0}`); - if (gdpr.gdprApplies && gdpr.consentString) queryString.push(`gdpr_consent=${gdpr.consentString}`); + if (gdpr.gdprApplies && gdpr.consentString) + queryString.push(`gdpr_consent=${gdpr.consentString}`); - if (this.syncStore.uspConsent) queryString.push(`usp_consent=${this.syncStore.uspConsent}`); + if (this.syncStore.uspConsent) + queryString.push(`usp_consent=${this.syncStore.uspConsent}`); queryString.push(`accountId=${this.syncStore.accountId}`); queryString.push(`bidders=${btoa(JSON.stringify(this.syncStore.bidders))}`); - queryString.push(`cb=${Date.now()}-${Math.random().toString().replace('.', '')}`); + queryString.push( + `cb=${Date.now()}-${Math.random().toString().replace(".", "")}` + ); - if (DEV_MODE) queryString.push('bbpbs_debug=true'); + if (DEV_MODE) queryString.push("bbpbs_debug=true"); // NB syncUrl by default starts with ?pub=$$PUBLICATION - const syncUrl = `${BB_HELPERS.getSyncUrl(this.syncStore.publicationName)}&${queryString.join('&')}`; - - return [{ - type: 'iframe', - url: syncUrl - }]; - } + const syncUrl = `${BB_HELPERS.getSyncUrl( + this.syncStore.publicationName + )}&${queryString.join("&")}`; + + return [ + { + type: "iframe", + url: syncUrl, + }, + ]; + }, }; registerBidder(spec); diff --git a/modules/connectadBidAdapter.js b/modules/connectadBidAdapter.js index 5185308eab0..da4cc40e11c 100644 --- a/modules/connectadBidAdapter.js +++ b/modules/connectadBidAdapter.js @@ -1,30 +1,34 @@ -import { deepSetValue, convertTypes, tryAppendQueryString, logWarn } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js' -import {config} from '../src/config.js'; -import {createEidsArray} from './userId/eids.js'; - -const BIDDER_CODE = 'connectad'; -const BIDDER_CODE_ALIAS = 'connectadrealtime'; -const ENDPOINT_URL = 'https://i.connectad.io/api/v2'; +import { + deepSetValue, + convertTypes, + tryAppendQueryString, + logWarn, +} from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { BANNER } from "../src/mediaTypes.js"; +import { config } from "../src/config.js"; + +const BIDDER_CODE = "connectad"; +const BIDDER_CODE_ALIAS = "connectadrealtime"; +const ENDPOINT_URL = "https://i.connectad.io/api/v2"; const SUPPORTED_MEDIA_TYPES = [BANNER]; export const spec = { code: BIDDER_CODE, gvlid: 138, - aliases: [ BIDDER_CODE_ALIAS ], + aliases: [BIDDER_CODE_ALIAS], supportedMediaTypes: SUPPORTED_MEDIA_TYPES, - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { return !!(bid.params.networkId && bid.params.siteId); }, - buildRequests: function(validBidRequests, bidderRequest) { + buildRequests: function (validBidRequests, bidderRequest) { let ret = { - method: 'POST', - url: '', - data: '', - bidRequest: [] + method: "POST", + url: "", + data: "", + bidRequest: [], }; if (validBidRequests.length < 1) { @@ -41,43 +45,52 @@ export const spec = { // TODO: please do not send internal data structures over the network referrer_info: bidderRequest.refererInfo?.legacy, screensize: getScreenSize(), - dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, + dnt: + navigator.doNotTrack == "yes" || + navigator.doNotTrack == "1" || + navigator.msDoNotTrack == "1" + ? 1 + : 0, language: navigator.language, ua: navigator.userAgent, - pversion: '$prebid.version$' + pversion: "$prebid.version$", }); // coppa compliance - if (config.getConfig('coppa') === true) { - deepSetValue(data, 'user.coppa', 1); + if (config.getConfig("coppa") === true) { + deepSetValue(data, "user.coppa", 1); } // adding schain object if (validBidRequests[0].schain) { - deepSetValue(data, 'source.ext.schain', validBidRequests[0].schain); + deepSetValue(data, "source.ext.schain", validBidRequests[0].schain); } // Attaching GDPR Consent Params if (bidderRequest.gdprConsent) { let gdprApplies; - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { + if (typeof bidderRequest.gdprConsent.gdprApplies === "boolean") { gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; } - deepSetValue(data, 'user.ext.gdpr', gdprApplies); - deepSetValue(data, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + deepSetValue(data, "user.ext.gdpr", gdprApplies); + deepSetValue( + data, + "user.ext.consent", + bidderRequest.gdprConsent.consentString + ); } // CCPA if (bidderRequest.uspConsent) { - deepSetValue(data, 'user.ext.us_privacy', bidderRequest.uspConsent); + deepSetValue(data, "user.ext.us_privacy", bidderRequest.uspConsent); } // EIDS Support - if (validBidRequests[0].userId) { - deepSetValue(data, 'user.ext.eids', createEidsArray(validBidRequests[0].userId)); + if (validBidRequests[0].userIdAsEids) { + deepSetValue(data, "user.ext.eids", validBidRequests[0].userIdAsEids); } - validBidRequests.map(bid => { + validBidRequests.map((bid) => { const placement = Object.assign({ id: bid.transactionId, divName: bid.bidId, @@ -86,7 +99,7 @@ export const spec = { adTypes: getSize(bid.mediaTypes.banner.sizes || bid.sizes), bidfloor: getBidFloor(bid), siteId: bid.params.siteId, - networkId: bid.params.networkId + networkId: bid.params.networkId, }); if (placement.networkId && placement.siteId) { @@ -101,7 +114,7 @@ export const spec = { return ret; }, - interpretResponse: function(serverResponse, bidRequest, bidderRequest) { + interpretResponse: function (serverResponse, bidRequest, bidderRequest) { let bid; let bids; let bidId; @@ -117,8 +130,10 @@ export const spec = { bidId = bidObj.bidId; if (serverResponse) { - const decision = serverResponse.decisions && serverResponse.decisions[bidId]; - const price = decision && decision.pricing && decision.pricing.clearPrice; + const decision = + serverResponse.decisions && serverResponse.decisions[bidId]; + const price = + decision && decision.pricing && decision.pricing.clearPrice; if (decision && price) { bid.requestId = bidId; @@ -126,9 +141,12 @@ export const spec = { bid.width = decision.width; bid.height = decision.height; bid.dealid = decision.dealid || null; - bid.meta = { advertiserDomains: decision && decision.adomain ? decision.adomain : [] }; + bid.meta = { + advertiserDomains: + decision && decision.adomain ? decision.adomain : [], + }; bid.ad = retrieveAd(decision); - bid.currency = 'USD'; + bid.currency = "USD"; bid.creativeId = decision.adId; bid.ttl = 360; bid.netRevenue = true; @@ -141,114 +159,140 @@ export const spec = { }, transformBidParams: function (params, isOpenRtb) { - return convertTypes({ - 'siteId': 'number', - 'networkId': 'number' - }, params); + return convertTypes( + { + siteId: "number", + networkId: "number", + }, + params + ); }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { - let syncEndpoint = 'https://cdn.connectad.io/connectmyusers.php?'; + getUserSyncs: function ( + syncOptions, + serverResponses, + gdprConsent, + uspConsent + ) { + let syncEndpoint = "https://cdn.connectad.io/connectmyusers.php?"; if (gdprConsent) { - syncEndpoint = tryAppendQueryString(syncEndpoint, 'gdpr', (gdprConsent.gdprApplies ? 1 : 0)); + syncEndpoint = tryAppendQueryString( + syncEndpoint, + "gdpr", + gdprConsent.gdprApplies ? 1 : 0 + ); } - if (gdprConsent && typeof gdprConsent.consentString === 'string') { - syncEndpoint = tryAppendQueryString(syncEndpoint, 'gdpr_consent', gdprConsent.consentString); + if (gdprConsent && typeof gdprConsent.consentString === "string") { + syncEndpoint = tryAppendQueryString( + syncEndpoint, + "gdpr_consent", + gdprConsent.consentString + ); } if (uspConsent) { - syncEndpoint = tryAppendQueryString(syncEndpoint, 'us_privacy', uspConsent); + syncEndpoint = tryAppendQueryString( + syncEndpoint, + "us_privacy", + uspConsent + ); } - if (config.getConfig('coppa') === true) { - syncEndpoint = tryAppendQueryString(syncEndpoint, 'coppa', 1); + if (config.getConfig("coppa") === true) { + syncEndpoint = tryAppendQueryString(syncEndpoint, "coppa", 1); } if (syncOptions.iframeEnabled) { - return [{ - type: 'iframe', - url: syncEndpoint - }]; + return [ + { + type: "iframe", + url: syncEndpoint, + }, + ]; } else { - logWarn('Bidder ConnectAd: Please activate iFrame Sync'); + logWarn("Bidder ConnectAd: Please activate iFrame Sync"); } - } + }, }; const sizeMap = [ null, - '120x90', - '200x200', - '468x60', - '728x90', - '300x250', - '160x600', - '120x600', - '300x100', - '180x150', - '336x280', - '240x400', - '234x60', - '88x31', - '120x60', - '120x240', - '125x125', - '220x250', - '250x250', - '250x90', - '0x0', - '200x90', - '300x50', - '320x50', - '320x480', - '185x185', - '620x45', - '300x125', - '800x250', - '980x120', - '980x150', - '320x150', - '300x300', - '200x600', - '320x500', - '320x320' + "120x90", + "200x200", + "468x60", + "728x90", + "300x250", + "160x600", + "120x600", + "300x100", + "180x150", + "336x280", + "240x400", + "234x60", + "88x31", + "120x60", + "120x240", + "125x125", + "220x250", + "250x250", + "250x90", + "0x0", + "200x90", + "300x50", + "320x50", + "320x480", + "185x185", + "620x45", + "300x125", + "800x250", + "980x120", + "980x150", + "320x150", + "300x300", + "200x600", + "320x500", + "320x320", ]; -sizeMap[77] = '970x90'; -sizeMap[123] = '970x250'; -sizeMap[43] = '300x600'; -sizeMap[286] = '970x66'; -sizeMap[3230] = '970x280'; -sizeMap[429] = '486x60'; -sizeMap[374] = '700x500'; -sizeMap[934] = '300x1050'; -sizeMap[1578] = '320x100'; -sizeMap[331] = '320x250'; -sizeMap[3301] = '320x267'; -sizeMap[2730] = '728x250'; +sizeMap[77] = "970x90"; +sizeMap[123] = "970x250"; +sizeMap[43] = "300x600"; +sizeMap[286] = "970x66"; +sizeMap[3230] = "970x280"; +sizeMap[429] = "486x60"; +sizeMap[374] = "700x500"; +sizeMap[934] = "300x1050"; +sizeMap[1578] = "320x100"; +sizeMap[331] = "320x250"; +sizeMap[3301] = "320x267"; +sizeMap[2730] = "728x250"; function getBidFloor(bidRequest) { let floorInfo = {}; - if (typeof bidRequest.getFloor === 'function') { + if (typeof bidRequest.getFloor === "function") { floorInfo = bidRequest.getFloor({ - currency: 'USD', - mediaType: 'banner', - size: '*' + currency: "USD", + mediaType: "banner", + size: "*", }); } - let floor = floorInfo.floor || bidRequest.params.bidfloor || bidRequest.params.floorprice || 0; + let floor = + floorInfo.floor || + bidRequest.params.bidfloor || + bidRequest.params.floorprice || + 0; return floor; } function getSize(sizes) { const result = []; - sizes.forEach(function(size) { - const index = sizeMap.indexOf(size[0] + 'x' + size[1]); + sizes.forEach(function (size) { + const index = sizeMap.indexOf(size[0] + "x" + size[1]); if (index >= 0) { result.push(index); } @@ -261,7 +305,7 @@ function retrieveAd(decision) { } function getScreenSize() { - return [window.screen.width, window.screen.height].join('x'); + return [window.screen.width, window.screen.height].join("x"); } registerBidder(spec); diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js index 04f34bdc7d9..2f2ebfd63f8 100644 --- a/modules/impactifyBidAdapter.js +++ b/modules/impactifyBidAdapter.js @@ -1,27 +1,34 @@ -import { deepAccess, deepSetValue, generateUUID } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { config } from '../src/config.js'; -import { ajax } from '../src/ajax.js'; -import { createEidsArray } from './userId/eids.js'; - -const BIDDER_CODE = 'impactify'; -const BIDDER_ALIAS = ['imp']; -const DEFAULT_CURRENCY = 'USD'; +import { deepAccess, deepSetValue, generateUUID } from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { config } from "../src/config.js"; +import { ajax } from "../src/ajax.js"; + +const BIDDER_CODE = "impactify"; +const BIDDER_ALIAS = ["imp"]; +const DEFAULT_CURRENCY = "USD"; const DEFAULT_VIDEO_WIDTH = 640; const DEFAULT_VIDEO_HEIGHT = 360; -const ORIGIN = 'https://sonic.impactify.media'; -const LOGGER_URI = 'https://logger.impactify.media'; -const AUCTIONURI = '/bidder'; -const COOKIESYNCURI = '/static/cookie_sync.html'; +const ORIGIN = "https://sonic.impactify.media"; +const LOGGER_URI = "https://logger.impactify.media"; +const AUCTIONURI = "/bidder"; +const COOKIESYNCURI = "/static/cookie_sync.html"; const GVLID = 606; const GETCONFIG = config.getConfig; const getDeviceType = () => { // OpenRTB Device type - if ((/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()))) { + if ( + /ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test( + navigator.userAgent.toLowerCase() + ) + ) { return 5; } - if ((/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(navigator.userAgent.toLowerCase()))) { + if ( + /iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test( + navigator.userAgent.toLowerCase() + ) + ) { return 4; } return 2; @@ -30,14 +37,18 @@ const getDeviceType = () => { const getFloor = (bid) => { const floorInfo = bid.getFloor({ currency: DEFAULT_CURRENCY, - mediaType: '*', - size: '*' + mediaType: "*", + size: "*", }); - if (typeof floorInfo === 'object' && floorInfo.currency === DEFAULT_CURRENCY && !isNaN(parseFloat(floorInfo.floor))) { + if ( + typeof floorInfo === "object" && + floorInfo.currency === DEFAULT_CURRENCY && + !isNaN(parseFloat(floorInfo.floor)) + ) { return parseFloat(floorInfo.floor); } return null; -} +}; const createOpenRtbRequest = (validBidRequests, bidderRequest) => { // Create request and set imp bids inside @@ -46,27 +57,27 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { validBidRequests, cur: [DEFAULT_CURRENCY], imp: [], - source: {tid: bidderRequest.auctionId} + source: { tid: bidderRequest.auctionId }, }; // Get the url parameters const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); - const checkPrebid = urlParams.get('_checkPrebid'); + const checkPrebid = urlParams.get("_checkPrebid"); // Force impactify debugging parameter if (checkPrebid != null) { request.test = Number(checkPrebid); } // Set Schain in request - let schain = deepAccess(validBidRequests, '0.schain'); + let schain = deepAccess(validBidRequests, "0.schain"); if (schain) request.source.ext = { schain: schain }; // Set eids - let bidUserId = deepAccess(validBidRequests, '0.userId'); - let eids = createEidsArray(bidUserId); + let bidUserId = deepAccess(validBidRequests[0], "userIdAsEids"); + let eids = bidUserId; if (eids.length) { - deepSetValue(request, 'user.ext.eids', eids); + deepSetValue(request, "user.ext.eids", eids); } // Set device/user/site @@ -78,32 +89,44 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { devicetype: getDeviceType(), ua: navigator.userAgent, js: 1, - dnt: (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0, - language: ((navigator.language || navigator.userLanguage || '').split('-'))[0] || 'en', + dnt: + navigator.doNotTrack == "yes" || + navigator.doNotTrack == "1" || + navigator.msDoNotTrack == "1" + ? 1 + : 0, + language: + (navigator.language || navigator.userLanguage || "").split("-")[0] || + "en", }; - request.site = {page: bidderRequest.refererInfo.page}; + request.site = { page: bidderRequest.refererInfo.page }; // Handle privacy settings for GDPR/CCPA/COPPA let gdprApplies = 0; if (bidderRequest.gdprConsent) { - if (typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; - deepSetValue(request, 'user.ext.consent', bidderRequest.gdprConsent.consentString); + if (typeof bidderRequest.gdprConsent.gdprApplies === "boolean") + gdprApplies = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; + deepSetValue( + request, + "user.ext.consent", + bidderRequest.gdprConsent.consentString + ); } - deepSetValue(request, 'regs.ext.gdpr', gdprApplies); + deepSetValue(request, "regs.ext.gdpr", gdprApplies); if (bidderRequest.uspConsent) { - deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + deepSetValue(request, "regs.ext.us_privacy", bidderRequest.uspConsent); this.syncStore.uspConsent = bidderRequest.uspConsent; } - if (GETCONFIG('coppa') == true) deepSetValue(request, 'regs.coppa', 1); + if (GETCONFIG("coppa") == true) deepSetValue(request, "regs.coppa", 1); if (bidderRequest.uspConsent) { - deepSetValue(request, 'regs.ext.us_privacy', bidderRequest.uspConsent); + deepSetValue(request, "regs.ext.us_privacy", bidderRequest.uspConsent); } // Set buyer uid - deepSetValue(request, 'user.buyeruid', generateUUID()); + deepSetValue(request, "user.buyeruid", generateUUID()); // Create imps with bids validBidRequests.forEach((bid) => { @@ -114,19 +137,19 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { impactify: { appId: bid.params.appId, format: bid.params.format, - style: bid.params.style + style: bid.params.style, }, }, video: { playerSize: [DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT], - context: 'outstream', - mimes: ['video/mp4'], + context: "outstream", + mimes: ["video/mp4"], }, }; if (bid.params.container) { imp.ext.impactify.container = bid.params.container; } - if (typeof bid.getFloor === 'function') { + if (typeof bid.getFloor === "function") { const floor = getFloor(bid); if (floor) { imp.bidfloor = floor; @@ -141,7 +164,7 @@ const createOpenRtbRequest = (validBidRequests, bidderRequest) => { export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: ['video', 'banner'], + supportedMediaTypes: ["video", "banner"], aliases: BIDDER_ALIAS, /** @@ -151,13 +174,24 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - if (!bid.params.appId || typeof bid.params.appId != 'string' || !bid.params.format || typeof bid.params.format != 'string' || !bid.params.style || typeof bid.params.style != 'string') { + if ( + !bid.params.appId || + typeof bid.params.appId != "string" || + !bid.params.format || + typeof bid.params.format != "string" || + !bid.params.style || + typeof bid.params.style != "string" + ) { return false; } - if (bid.params.format != 'screen' && bid.params.format != 'display') { + if (bid.params.format != "screen" && bid.params.format != "display") { return false; } - if (bid.params.style != 'inline' && bid.params.style != 'impact' && bid.params.style != 'static') { + if ( + bid.params.style != "inline" && + bid.params.style != "impact" && + bid.params.style != "static" + ) { return false; } @@ -176,7 +210,7 @@ export const spec = { let request = createOpenRtbRequest(validBidRequests, bidderRequest); return { - method: 'POST', + method: "POST", url: ORIGIN + AUCTIONURI, data: JSON.stringify(request), }; @@ -220,8 +254,9 @@ export const spec = { hash: bid.hash, expiry: bid.expiry, meta: { - advertiserDomains: bid.adomain && bid.adomain.length ? bid.adomain : [] - } + advertiserDomains: + bid.adomain && bid.adomain.length ? bid.adomain : [], + }, })), ]; } @@ -251,35 +286,42 @@ export const spec = { return []; } - let params = ''; - if (gdprConsent && typeof gdprConsent.consentString === 'string') { - if (typeof gdprConsent.gdprApplies === 'boolean') { - params += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; + let params = ""; + if (gdprConsent && typeof gdprConsent.consentString === "string") { + if (typeof gdprConsent.gdprApplies === "boolean") { + params += `?gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${ + gdprConsent.consentString + }`; } else { params += `?gdpr_consent=${gdprConsent.consentString}`; } } if (uspConsent) { - params += `${params ? '&' : '?'}us_privacy=${encodeURIComponent(uspConsent)}`; + params += `${params ? "&" : "?"}us_privacy=${encodeURIComponent( + uspConsent + )}`; } - if (document.location.search.match(/pbs_debug=true/)) params += `&pbs_debug=true`; + if (document.location.search.match(/pbs_debug=true/)) + params += `&pbs_debug=true`; - return [{ - type: 'iframe', - url: ORIGIN + COOKIESYNCURI + params - }]; + return [ + { + type: "iframe", + url: ORIGIN + COOKIESYNCURI + params, + }, + ]; }, /** * Register bidder specific code, which will execute if a bid from this bidder won the auction * @param {Bid} The bid that won the auction - */ - onBidWon: function(bid) { + */ + onBidWon: function (bid) { ajax(`${LOGGER_URI}/log/bidder/won`, null, JSON.stringify(bid), { - method: 'POST', - contentType: 'application/json' + method: "POST", + contentType: "application/json", }); return true; @@ -288,14 +330,14 @@ export const spec = { /** * Register bidder specific code, which will execute if bidder timed out after an auction * @param {data} Containing timeout specific data - */ - onTimeout: function(data) { + */ + onTimeout: function (data) { ajax(`${LOGGER_URI}/log/bidder/timeout`, null, JSON.stringify(data[0]), { - method: 'POST', - contentType: 'application/json' + method: "POST", + contentType: "application/json", }); return true; - } + }, }; registerBidder(spec); diff --git a/modules/mediakeysBidAdapter.js b/modules/mediakeysBidAdapter.js index 60ced650329..28d60353a27 100644 --- a/modules/mediakeysBidAdapter.js +++ b/modules/mediakeysBidAdapter.js @@ -1,4 +1,4 @@ -import {arrayFrom, find} from '../src/polyfill.js'; +import { arrayFrom, find } from '../src/polyfill.js'; import { cleanObj, deepAccess, @@ -15,12 +15,11 @@ import { logError, logWarn, mergeDeep, - triggerPixel + triggerPixel, } from '../src/utils.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {config} from '../src/config.js'; -import {BANNER, NATIVE, VIDEO} from '../src/mediaTypes.js'; -import {createEidsArray} from './userId/eids.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { config } from '../src/config.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; const AUCTION_TYPE = 1; @@ -52,36 +51,49 @@ const NATIVE_ASSETS_MAPPING = [ // This provide a whitelist and a basic validation of OpenRTB native 1.2 options. // https://www.iab.com/wp-content/uploads/2018/03/OpenRTB-Native-Ads-Specification-Final-1.2.pdf const ORTB_NATIVE_PARAMS = { - context: value => [1, 2, 3].indexOf(value) !== -1, - plcmttype: value => [1, 2, 3, 4].indexOf(value) !== -1 + context: (value) => [1, 2, 3].indexOf(value) !== -1, + plcmttype: (value) => [1, 2, 3, 4].indexOf(value) !== -1, }; // This provide a whitelist and a basic validation of OpenRTB 2.5 video options. // https://www.iab.com/wp-content/uploads/2016/03/OpenRTB-API-Specification-Version-2-5-FINAL.pdf const ORTB_VIDEO_PARAMS = { - mimes: value => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'), - minduration: value => isInteger(value), - maxduration: value => isInteger(value), - protocols: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].indexOf(v) !== -1), - w: value => isInteger(value), - h: value => isInteger(value), - startdelay: value => isInteger(value), - placement: value => [1, 2, 3, 4, 5].indexOf(value) !== -1, - linearity: value => [1, 2].indexOf(value) !== -1, - skip: value => [0, 1].indexOf(value) !== -1, - skipmin: value => isInteger(value), - skipafter: value => isInteger(value), - sequence: value => isInteger(value), - battr: value => Array.isArray(value) && value.every(v => arrayFrom({length: 17}, (_, i) => i + 1).indexOf(v) !== -1), - maxextended: value => isInteger(value), - minbitrate: value => isInteger(value), - maxbitrate: value => isInteger(value), - boxingallowed: value => [0, 1].indexOf(value) !== -1, - playbackmethod: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), - playbackend: value => [1, 2, 3].indexOf(value) !== -1, - delivery: value => [1, 2, 3].indexOf(value) !== -1, - pos: value => [0, 1, 2, 3, 4, 5, 6, 7].indexOf(value) !== -1, - api: value => Array.isArray(value) && value.every(v => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), + mimes: (value) => + Array.isArray(value) && + value.length > 0 && + value.every((v) => typeof v === 'string'), + minduration: (value) => isInteger(value), + maxduration: (value) => isInteger(value), + protocols: (value) => + Array.isArray(value) && + value.every((v) => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].indexOf(v) !== -1), + w: (value) => isInteger(value), + h: (value) => isInteger(value), + startdelay: (value) => isInteger(value), + placement: (value) => [1, 2, 3, 4, 5].indexOf(value) !== -1, + linearity: (value) => [1, 2].indexOf(value) !== -1, + skip: (value) => [0, 1].indexOf(value) !== -1, + skipmin: (value) => isInteger(value), + skipafter: (value) => isInteger(value), + sequence: (value) => isInteger(value), + battr: (value) => + Array.isArray(value) && + value.every( + (v) => arrayFrom({ length: 17 }, (_, i) => i + 1).indexOf(v) !== -1 + ), + maxextended: (value) => isInteger(value), + minbitrate: (value) => isInteger(value), + maxbitrate: (value) => isInteger(value), + boxingallowed: (value) => [0, 1].indexOf(value) !== -1, + playbackmethod: (value) => + Array.isArray(value) && + value.every((v) => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), + playbackend: (value) => [1, 2, 3].indexOf(value) !== -1, + delivery: (value) => [1, 2, 3].indexOf(value) !== -1, + pos: (value) => [0, 1, 2, 3, 4, 5, 6, 7].indexOf(value) !== -1, + api: (value) => + Array.isArray(value) && + value.every((v) => [1, 2, 3, 4, 5, 6].indexOf(v) !== -1), }; /** @@ -91,10 +103,18 @@ const ORTB_VIDEO_PARAMS = { * @returns {number} */ function getDeviceType() { - if ((/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()))) { + if ( + /ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test( + navigator.userAgent.toLowerCase() + ) + ) { return 5; } - if ((/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(navigator.userAgent.toLowerCase()))) { + if ( + /iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test( + navigator.userAgent.toLowerCase() + ) + ) { return 4; } return 2; @@ -129,17 +149,21 @@ function getFloor(bid, mediaType, size = '*') { } if (SUPPORTED_MEDIA_TYPES.indexOf(mediaType) === -1) { - logWarn(`${BIDDER_CODE}: Unable to detect floor price for unsupported mediaType ${mediaType}. No floor will be used.`); + 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 - }) + size, + }); - return (!isNaN(floor.floor) && floor.currency === DEFAULT_CURRENCY) ? floor.floor : false + return !isNaN(floor.floor) && floor.currency === DEFAULT_CURRENCY + ? floor.floor + : false; } /** @@ -192,17 +216,17 @@ function createOrtbTemplate() { h: screen.height, w: screen.width, language: navigator.language, - make: navigator.vendor ? navigator.vendor : '' + make: navigator.vendor ? navigator.vendor : '', }, user: {}, regs: { ext: { - gdpr: 0 // not applied by default - } + gdpr: 0, // not applied by default + }, }, ext: { - is_secure: 1 - } + is_secure: 1, + }, }; } @@ -217,7 +241,9 @@ function createBannerImp(bid) { const params = deepAccess(bid, 'params', {}); if (!isArray(sizes) || !sizes.length) { - logWarn(`${BIDDER_CODE}: mediaTypes.banner.size missing for adunit: ${bid.params.adUnit}. Ignoring the banner impression in the adunit.`); + logWarn( + `${BIDDER_CODE}: mediaTypes.banner.size missing for adunit: ${bid.params.adUnit}. Ignoring the banner impression in the adunit.` + ); } else { const banner = {}; @@ -227,7 +253,7 @@ function createBannerImp(bid) { const format = []; sizes.forEach(function (size) { if (size.length && size.length > 1) { - format.push({w: size[0], h: size[1]}); + format.push({ w: size[0], h: size[1] }); } }); banner.format = format; @@ -248,7 +274,7 @@ function createBannerImp(bid) { function createNativeImp(bid) { if (!bid.nativeParams) { logWarn(`${BIDDER_CODE}: bid.nativeParams object has not been found.`); - return + return; } const nativeParams = deepClone(bid.nativeParams); @@ -258,28 +284,30 @@ function createNativeImp(bid) { const extraParams = { ...nativeAdUnitParams, - ...nativeBidderParams + ...nativeBidderParams, }; const nativeObject = { ver: '1.2', context: 1, // overwrited later if needed plcmttype: 1, // overwrited later if needed - assets: [] - } + assets: [], + }; - Object.keys(ORTB_NATIVE_PARAMS).forEach(name => { + Object.keys(ORTB_NATIVE_PARAMS).forEach((name) => { if (extraParams.hasOwnProperty(name)) { if (ORTB_NATIVE_PARAMS[name](extraParams[name])) { nativeObject[name] = extraParams[name]; } else { - logWarn(`${BIDDER_CODE}: the OpenRTB native param ${name} has been skipped due to misformating. Please refer to OpenRTB Native spec.`); + logWarn( + `${BIDDER_CODE}: the OpenRTB native param ${name} has been skipped due to misformating. Please refer to OpenRTB Native spec.` + ); } } }); // just a helper function - const setImageAssetSizes = function(asset, param) { + const setImageAssetSizes = function (asset, param) { if (param.sizes && param.sizes.length) { asset.img.w = param.sizes ? param.sizes[0] : undefined; asset.img.h = param.sizes ? param.sizes[1] : undefined; @@ -292,7 +320,7 @@ function createNativeImp(bid) { if (!asset.img.h) { asset.img.hmin = 0; } - } + }; // Prebid.js "image" type support. // Add some defaults to support special type provided by Prebid.js `mediaTypes.native.type: "image"` @@ -304,9 +332,14 @@ function createNativeImp(bid) { for (let key in nativeParams) { if (nativeParams.hasOwnProperty(key)) { - const internalNativeAsset = find(NATIVE_ASSETS_MAPPING, ref => ref.name === key); + const internalNativeAsset = find( + NATIVE_ASSETS_MAPPING, + (ref) => ref.name === key + ); if (!internalNativeAsset) { - logWarn(`${BIDDER_CODE}: the asset "${key}" has not been found in Prebid assets map. Skipped for request.`); + logWarn( + `${BIDDER_CODE}: the asset "${key}" has not been found in Prebid assets map. Skipped for request.` + ); continue; } @@ -314,18 +347,20 @@ function createNativeImp(bid) { const asset = { id: internalNativeAsset.id, - required: param.required ? 1 : 0 - } + required: param.required ? 1 : 0, + }; switch (key) { case 'title': if (param.len || param.length) { asset.title = { len: param.len || param.length, - ext: param.ext - } + ext: param.ext, + }; } else { - logWarn(`${BIDDER_CODE}: "title.length" property for native asset is required. Skipped for request.`) + logWarn( + `${BIDDER_CODE}: "title.length" property for native asset is required. Skipped for request.` + ); continue; } break; @@ -335,7 +370,7 @@ function createNativeImp(bid) { type: internalNativeAsset.type, mimes: param.mimes, ext: param.ext, - } + }; setImageAssetSizes(asset, param); @@ -345,7 +380,7 @@ function createNativeImp(bid) { type: internalNativeAsset.type, mimes: param.mimes, ext: param.ext, - } + }; setImageAssetSizes(asset, param); break; @@ -366,8 +401,8 @@ function createNativeImp(bid) { asset.data = { type: internalNativeAsset.type, len: param.len, - ext: param.ext - } + ext: param.ext, + }; break; } @@ -377,8 +412,8 @@ function createNativeImp(bid) { if (nativeObject.assets.length) { return { - request: nativeObject - } + request: nativeObject, + }; } } @@ -396,7 +431,9 @@ function createVideoImp(bid) { // Special case for playerSize. // Eeach props will be overrided if they are defined in config. if (Array.isArray(videoAdUnitParams.playerSize)) { - const tempSize = (Array.isArray(videoAdUnitParams.playerSize[0])) ? videoAdUnitParams.playerSize[0] : videoAdUnitParams.playerSize; + const tempSize = Array.isArray(videoAdUnitParams.playerSize[0]) + ? videoAdUnitParams.playerSize[0] + : videoAdUnitParams.playerSize; computedParams.w = tempSize[0]; computedParams.h = tempSize[1]; } @@ -404,18 +441,20 @@ function createVideoImp(bid) { const videoParams = { ...computedParams, ...videoAdUnitParams, - ...videoBidderParams + ...videoBidderParams, }; const video = {}; // Only whitelisted OpenRTB options need to be validated. - Object.keys(ORTB_VIDEO_PARAMS).forEach(name => { + Object.keys(ORTB_VIDEO_PARAMS).forEach((name) => { if (videoParams.hasOwnProperty(name)) { if (ORTB_VIDEO_PARAMS[name](videoParams[name])) { video[name] = videoParams[name]; } else { - logWarn(`${BIDDER_CODE}: the OpenRTB video param ${name} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.`); + logWarn( + `${BIDDER_CODE}: the OpenRTB video param ${name} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.` + ); } } }); @@ -510,9 +549,9 @@ function nativeBidResponseHandler(bid) { return; } - const native = {} + const native = {}; - nativeAdm.assets.forEach(asset => { + nativeAdm.assets.forEach((asset) => { if (asset.title) { native.title = asset.title.text; return; @@ -524,14 +563,14 @@ function nativeBidResponseHandler(bid) { native.icon = { url: asset.img.url, width: asset.img.w, - height: asset.img.h + height: asset.img.h, }; break; default: native.image = { url: asset.img.url, width: asset.img.w, - height: asset.img.h + height: asset.img.h, }; break; } @@ -539,7 +578,10 @@ function nativeBidResponseHandler(bid) { } if (asset.data) { - const internalNativeAsset = find(NATIVE_ASSETS_MAPPING, ref => ref.id === asset.id); + const internalNativeAsset = find( + NATIVE_ASSETS_MAPPING, + (ref) => ref.id === asset.id + ); if (internalNativeAsset) { native[internalNativeAsset.name] = asset.data.value; } @@ -551,13 +593,13 @@ function nativeBidResponseHandler(bid) { native.clickUrl = nativeAdm.link.url; } if (Array.isArray(nativeAdm.link.clicktrackers)) { - native.clickTrackers = nativeAdm.link.clicktrackers + native.clickTrackers = nativeAdm.link.clicktrackers; } } if (Array.isArray(nativeAdm.eventtrackers)) { native.impressionTrackers = []; - nativeAdm.eventtrackers.forEach(tracker => { + nativeAdm.eventtrackers.forEach((tracker) => { // Only Impression events are supported. Prebid does not support Viewability events yet. if (tracker.event !== 1) { return; @@ -597,11 +639,11 @@ export const spec = { supportedMediaTypes: SUPPORTED_MEDIA_TYPES, - isBidRequestValid: function(bid) { + isBidRequestValid: function (bid) { return !!(bid && !isEmpty(bid)); }, - buildRequests: function(validBidRequests, bidderRequest) { + buildRequests: function (validBidRequests, bidderRequest) { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); @@ -612,7 +654,7 @@ export const spec = { deepSetValue(payload, 'id', bidderRequest.auctionId); deepSetValue(payload, 'source.tid', bidderRequest.auctionId); - validBidRequests.forEach(validBid => { + validBidRequests.forEach((validBid) => { let bid = deepClone(validBid); // No additional params atm. @@ -626,8 +668,16 @@ export const spec = { } if (bidderRequest && bidderRequest.gdprConsent) { - deepSetValue(payload, 'user.ext.consent', bidderRequest.gdprConsent.consentString); - deepSetValue(payload, 'regs.ext.gdpr', (bidderRequest.gdprConsent.gdprApplies ? 1 : 0)); + deepSetValue( + payload, + 'user.ext.consent', + bidderRequest.gdprConsent.consentString + ); + deepSetValue( + payload, + 'regs.ext.gdpr', + bidderRequest.gdprConsent.gdprApplies ? 1 : 0 + ); } if (bidderRequest && bidderRequest.uspConsent) { @@ -638,8 +688,8 @@ export const spec = { deepSetValue(payload, 'regs.coppa', 1); } - if (deepAccess(validBidRequests[0], 'userId')) { - deepSetValue(payload, 'user.ext.eids', createEidsArray(validBidRequests[0].userId)); + if (deepAccess(validBidRequests[0], 'userIdAsEids')) { + deepSetValue(payload, 'user.ext.eids', validBidRequests[0].userIdAsEids); } // Assign payload.site from refererinfo @@ -647,7 +697,7 @@ export const spec = { // TODO: reachedTop is probably not the right check here - it may be false when page is available or vice-versa if (bidderRequest.refererInfo.reachedTop) { deepSetValue(payload, 'site.page', bidderRequest.refererInfo.page); - deepSetValue(payload, 'site.domain', bidderRequest.refererInfo.domain) + deepSetValue(payload, 'site.domain', bidderRequest.refererInfo.domain); if (bidderRequest.refererInfo.ref) { deepSetValue(payload, 'site.ref', bidderRequest.refererInfo.ref); } @@ -668,9 +718,9 @@ export const spec = { url: ENDPOINT, data: payload, options: { - withCredentials: false - } - } + withCredentials: false, + }, + }; return request; }, @@ -679,16 +729,21 @@ export const spec = { const bidResponses = []; try { - if (serverResponse.body && serverResponse.body.seatbid && isArray(serverResponse.body.seatbid)) { + if ( + serverResponse.body && + serverResponse.body.seatbid && + isArray(serverResponse.body.seatbid) + ) { const currency = serverResponse.body.cur || DEFAULT_CURRENCY; - const referrer = bidRequest.site && bidRequest.site.ref ? bidRequest.site.ref : ''; + const referrer = + bidRequest.site && bidRequest.site.ref ? bidRequest.site.ref : ''; - serverResponse.body.seatbid.forEach(bidderSeat => { + serverResponse.body.seatbid.forEach((bidderSeat) => { if (!isArray(bidderSeat.bid) || !bidderSeat.bid.length) { return; } - bidderSeat.bid.forEach(bid => { + bidderSeat.bid.forEach((bid) => { let mediaType; // Actually only BANNER is supported, but other types will be added soon. switch (deepAccess(bid, 'ext.prebid.type')) { @@ -703,16 +758,19 @@ export const spec = { } const meta = { - advertiserDomains: (Array.isArray(bid.adomain) && bid.adomain.length) ? bid.adomain : [], + advertiserDomains: + Array.isArray(bid.adomain) && bid.adomain.length + ? bid.adomain + : [], advertiserName: deepAccess(bid, 'ext.advertiser_name', null), agencyName: deepAccess(bid, 'ext.agency_name', null), primaryCatId: getPrimaryCatFromResponse(bid.cat), - mediaType + mediaType, }; const newBid = { requestId: bid.impid, - cpm: (parseFloat(bid.price) || 0), + cpm: parseFloat(bid.price) || 0, width: bid.w, height: bid.h, creativeId: bid.crid || bid.id, @@ -724,7 +782,7 @@ export const spec = { ad: bid.adm, mediaType, burl: bid.burl, - meta: cleanObj(meta) + meta: cleanObj(meta), }; if (mediaType === NATIVE) { @@ -769,7 +827,7 @@ export const spec = { const url = bid.burl.replace(/\$\{AUCTION_PRICE\}/, bid.cpm); triggerPixel(url); - } -} + }, +}; -registerBidder(spec) +registerBidder(spec); diff --git a/modules/onetagBidAdapter.js b/modules/onetagBidAdapter.js index 70238294c38..8587774330e 100644 --- a/modules/onetagBidAdapter.js +++ b/modules/onetagBidAdapter.js @@ -22,14 +22,21 @@ const storage = getStorageManager({ gvlid: GVLID, bidderCode: BIDDER_CODE }); * @return boolean True if this is a valid bid, and false otherwise. */ function isBidRequestValid(bid) { - if (typeof bid === 'undefined' || typeof bid.params === 'undefined' || typeof bid.params.pubId !== 'string') { + if ( + typeof bid === 'undefined' || + typeof bid.params === 'undefined' || + typeof bid.params.pubId !== 'string' + ) { return false; } return isValid(BANNER, bid) || isValid(VIDEO, bid); } export function hasTypeVideo(bid) { - return typeof bid.mediaTypes !== 'undefined' && typeof bid.mediaTypes.video !== 'undefined'; + return ( + typeof bid.mediaTypes !== 'undefined' && + typeof bid.mediaTypes.video !== 'undefined' + ); } export function isValid(type, bid) { @@ -53,42 +60,53 @@ export function isValid(type, bid) { function buildRequests(validBidRequests, bidderRequest) { const payload = { bids: requestsToBids(validBidRequests), - ...getPageInfo(bidderRequest) + ...getPageInfo(bidderRequest), }; if (bidderRequest && bidderRequest.gdprConsent) { payload.gdprConsent = { consentString: bidderRequest.gdprConsent.consentString, - consentRequired: bidderRequest.gdprConsent.gdprApplies + consentRequired: bidderRequest.gdprConsent.gdprApplies, }; } if (bidderRequest && bidderRequest.gppConsent) { payload.gppConsent = { consentString: bidderRequest.gppConsent.gppString, - applicableSections: bidderRequest.gppConsent.applicableSections - } + applicableSections: bidderRequest.gppConsent.applicableSections, + }; } if (bidderRequest && bidderRequest.uspConsent) { payload.usPrivacy = bidderRequest.uspConsent; } - if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].userIdAsEids) { + if ( + validBidRequests && + validBidRequests.length !== 0 && + validBidRequests[0].userIdAsEids + ) { payload.userId = validBidRequests[0].userIdAsEids; } - if (validBidRequests && validBidRequests.length !== 0 && validBidRequests[0].schain && isSchainValid(validBidRequests[0].schain)) { + if ( + validBidRequests && + validBidRequests.length !== 0 && + validBidRequests[0].schain && + isSchainValid(validBidRequests[0].schain) + ) { payload.schain = validBidRequests[0].schain; } try { if (storage.hasLocalStorage()) { payload.onetagSid = storage.getDataFromLocalStorage('onetag_sid'); } - } catch (e) { } + } catch (e) {} const connection = navigator.connection || navigator.webkitConnection; - payload.networkConnectionType = (connection && connection.type) ? connection.type : null; - payload.networkEffectiveConnectionType = (connection && connection.effectiveType) ? connection.effectiveType : null; + payload.networkConnectionType = + connection && connection.type ? connection.type : null; + payload.networkEffectiveConnectionType = + connection && connection.effectiveType ? connection.effectiveType : null; return { method: 'POST', url: ENDPOINT, - data: JSON.stringify(payload) - } + data: JSON.stringify(payload), + }; } function interpretResponse(serverResponse, bidderRequest) { @@ -101,7 +119,7 @@ function interpretResponse(serverResponse, bidderRequest) { if (!body.bids || !Array.isArray(body.bids) || body.bids.length === 0) { return bids; } - body.bids.forEach(bid => { + body.bids.forEach((bid) => { const responseBid = { requestId: bid.requestId, cpm: bid.cpm, @@ -114,16 +132,16 @@ function interpretResponse(serverResponse, bidderRequest) { mediaType: bid.mediaType, meta: { mediaType: bid.mediaType, - advertiserDomains: bid.adomain + advertiserDomains: bid.adomain, }, - ttl: bid.ttl || 300 + ttl: bid.ttl || 300, }; if (bid.mediaType === BANNER) { responseBid.ad = bid.ad; } else if (bid.mediaType === VIDEO) { - const { context, adUnitCode } = find(requestData.bids, (item) => - item.bidId === bid.requestId && - item.type === VIDEO + const { context, adUnitCode } = find( + requestData.bids, + (item) => item.bidId === bid.requestId && item.type === VIDEO ); if (context === INSTREAM) { responseBid.vastUrl = bid.vastUrl; @@ -147,7 +165,7 @@ function createRenderer(bid, rendererOptions = {}) { url: bid.rendererUrl, config: rendererOptions, adUnitCode: bid.adUnitCode, - loaded: false + loaded: false, }); try { renderer.setRender(({ renderer, width, height, vastXml, adUnitCode }) => { @@ -158,13 +176,11 @@ function createRenderer(bid, rendererOptions = {}) { height, vastXml, nodeId: adUnitCode, - config: renderer.getConfig() + config: renderer.getConfig(), }); }); }); - } catch (e) { - - } + } catch (e) {} return renderer; } @@ -178,7 +194,7 @@ function getFrameNesting() { parent.location.href; topmostFrame = topmostFrame.parent; } - } catch (e) { } + } catch (e) {} return topmostFrame; } @@ -217,45 +233,65 @@ function getPageInfo(bidderRequest) { sHeight: topmostFrame.screen.height, aWidth: topmostFrame.screen.availWidth, aHeight: topmostFrame.screen.availHeight, - sLeft: 'screenLeft' in topmostFrame ? topmostFrame.screenLeft : topmostFrame.screenX, - sTop: 'screenTop' in topmostFrame ? topmostFrame.screenTop : topmostFrame.screenY, + sLeft: + 'screenLeft' in topmostFrame + ? topmostFrame.screenLeft + : topmostFrame.screenX, + sTop: + 'screenTop' in topmostFrame + ? topmostFrame.screenTop + : topmostFrame.screenY, xOffset: topmostFrame.pageXOffset, yOffset: topmostFrame.pageYOffset, docHidden: getDocumentVisibility(topmostFrame), - docHeight: topmostFrame.document.body ? topmostFrame.document.body.scrollHeight : null, + docHeight: topmostFrame.document.body + ? topmostFrame.document.body.scrollHeight + : null, hLength: history.length, timing: getTiming(), version: { prebid: '$prebid.version$', - adapter: '1.1.1' - } + adapter: '1.1.1', + }, }; } function requestsToBids(bidRequests) { - const videoBidRequests = bidRequests.filter(bidRequest => hasTypeVideo(bidRequest)).map(bidRequest => { - const videoObj = {}; - setGeneralInfo.call(videoObj, bidRequest); - // Pass parameters - // Context: instream - outstream - adpod - videoObj['context'] = bidRequest.mediaTypes.video.context; - // Sizes - videoObj['playerSize'] = parseVideoSize(bidRequest); - // Other params - videoObj['mediaTypeInfo'] = deepClone(bidRequest.mediaTypes.video); - videoObj['type'] = VIDEO; - videoObj['priceFloors'] = getBidFloor(bidRequest, VIDEO, videoObj['playerSize']); - return videoObj; - }); - const bannerBidRequests = bidRequests.filter(bidRequest => isValid(BANNER, bidRequest)).map(bidRequest => { - const bannerObj = {}; - setGeneralInfo.call(bannerObj, bidRequest); - bannerObj['sizes'] = parseSizes(bidRequest); - bannerObj['type'] = BANNER; - bannerObj['mediaTypeInfo'] = deepClone(bidRequest.mediaTypes.banner); - bannerObj['priceFloors'] = getBidFloor(bidRequest, BANNER, bannerObj['sizes']); - return bannerObj; - }); + const videoBidRequests = bidRequests + .filter((bidRequest) => hasTypeVideo(bidRequest)) + .map((bidRequest) => { + const videoObj = {}; + setGeneralInfo.call(videoObj, bidRequest); + // Pass parameters + // Context: instream - outstream - adpod + videoObj['context'] = bidRequest.mediaTypes.video.context; + // Sizes + videoObj['playerSize'] = parseVideoSize(bidRequest); + // Other params + videoObj['mediaTypeInfo'] = deepClone(bidRequest.mediaTypes.video); + videoObj['type'] = VIDEO; + videoObj['priceFloors'] = getBidFloor( + bidRequest, + VIDEO, + videoObj['playerSize'] + ); + return videoObj; + }); + const bannerBidRequests = bidRequests + .filter((bidRequest) => isValid(BANNER, bidRequest)) + .map((bidRequest) => { + const bannerObj = {}; + setGeneralInfo.call(bannerObj, bidRequest); + bannerObj['sizes'] = parseSizes(bidRequest); + bannerObj['type'] = BANNER; + bannerObj['mediaTypeInfo'] = deepClone(bidRequest.mediaTypes.banner); + bannerObj['priceFloors'] = getBidFloor( + bidRequest, + BANNER, + bannerObj['sizes'] + ); + return bannerObj; + }); return videoBidRequests.concat(bannerBidRequests); } @@ -266,7 +302,9 @@ function setGeneralInfo(bidRequest) { this['bidderRequestId'] = bidRequest.bidderRequestId; this['auctionId'] = bidRequest.auctionId; this['transactionId'] = bidRequest.transactionId; - this['gpid'] = deepAccess(bidRequest, 'ortb2Imp.ext.gpid') || deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot'); + this['gpid'] = + deepAccess(bidRequest, 'ortb2Imp.ext.gpid') || + deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot'); this['pubId'] = params.pubId; this['ext'] = params.ext; if (params.pubClick) { @@ -286,7 +324,12 @@ function getSpaceCoords(id) { try { const { top, left, width, height } = space.getBoundingClientRect(); let window = space.ownerDocument.defaultView; - const coords = { top: top + window.pageYOffset, left: left + window.pageXOffset, width, height }; + const coords = { + top: top + window.pageYOffset, + left: left + window.pageXOffset, + width, + height, + }; let frame = window.frameElement; while (frame != null) { const { top, left } = frame.getBoundingClientRect(); @@ -319,16 +362,26 @@ function getTiming() { function parseVideoSize(bid) { const playerSize = bid.mediaTypes.video.playerSize; - if (typeof playerSize !== 'undefined' && Array.isArray(playerSize) && playerSize.length > 0) { - return getSizes(playerSize) + if ( + typeof playerSize !== 'undefined' && + Array.isArray(playerSize) && + playerSize.length > 0 + ) { + return getSizes(playerSize); } return []; } function parseSizes(bid) { let ret = []; - if (typeof bid.mediaTypes !== 'undefined' && typeof bid.mediaTypes.banner !== 'undefined' && typeof bid.mediaTypes.banner.sizes !== 'undefined' && Array.isArray(bid.mediaTypes.banner.sizes) && bid.mediaTypes.banner.sizes.length > 0) { - return getSizes(bid.mediaTypes.banner.sizes) + if ( + typeof bid.mediaTypes !== 'undefined' && + typeof bid.mediaTypes.banner !== 'undefined' && + typeof bid.mediaTypes.banner.sizes !== 'undefined' && + Array.isArray(bid.mediaTypes.banner.sizes) && + bid.mediaTypes.banner.sizes.length > 0 + ) { + return getSizes(bid.mediaTypes.banner.sizes); } const isVideoBidRequest = hasTypeVideo(bid); if (!isVideoBidRequest && bid.sizes && Array.isArray(bid.sizes)) { @@ -341,12 +394,18 @@ function getSizes(sizes) { const ret = []; for (let i = 0; i < sizes.length; i++) { const size = sizes[i]; - ret.push({ width: size[0], height: size[1] }) + ret.push({ width: size[0], height: size[1] }); } return ret; } -function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { +function getUserSyncs( + syncOptions, + serverResponses, + gdprConsent, + uspConsent, + gppConsent +) { let syncs = []; let params = ''; if (gdprConsent) { @@ -368,13 +427,13 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gpp if (syncOptions.iframeEnabled) { syncs.push({ type: 'iframe', - url: USER_SYNC_ENDPOINT + '?cb=' + new Date().getTime() + params + url: USER_SYNC_ENDPOINT + '?cb=' + new Date().getTime() + params, }); } if (syncOptions.pixelEnabled) { syncs.push({ type: 'image', - url: USER_SYNC_ENDPOINT + '?tag=img' + params + url: USER_SYNC_ENDPOINT + '?tag=img' + params, }); } return syncs; @@ -383,14 +442,16 @@ function getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gpp function getBidFloor(bidRequest, mediaType, sizes) { const priceFloors = []; if (typeof bidRequest.getFloor === 'function') { - sizes.forEach(size => { + sizes.forEach((size) => { const floor = bidRequest.getFloor({ currency: 'EUR', mediaType: mediaType || '*', - size: [size.width, size.height] + size: [size.width, size.height], }); floor.size = deepClone(size); - if (!floor.floor) { floor.floor = null; } + if (!floor.floor) { + floor.floor = null; + } priceFloors.push(floor); }); } @@ -403,7 +464,7 @@ export function isSchainValid(schain) { if (!schain || !schain.nodes) return isValid; isValid = schain.nodes.reduce((status, node) => { if (!status) return status; - return requiredFields.every(field => node.hasOwnProperty(field)); + return requiredFields.every((field) => node.hasOwnProperty(field)); }, true); if (!isValid) { logError('OneTag: required schain params missing'); @@ -418,8 +479,7 @@ export const spec = { isBidRequestValid: isBidRequestValid, buildRequests: buildRequests, interpretResponse: interpretResponse, - getUserSyncs: getUserSyncs - + getUserSyncs: getUserSyncs, }; registerBidder(spec); diff --git a/modules/sharethroughBidAdapter.js b/modules/sharethroughBidAdapter.js index 0c8b84fd0c5..d2bd80b402f 100644 --- a/modules/sharethroughBidAdapter.js +++ b/modules/sharethroughBidAdapter.js @@ -1,12 +1,11 @@ -import { deepAccess, generateUUID, inIframe } from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { config } from '../src/config.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { createEidsArray } from './userId/eids.js'; +import { deepAccess, generateUUID, inIframe } from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { config } from "../src/config.js"; +import { BANNER, VIDEO } from "../src/mediaTypes.js"; -const VERSION = '4.3.0'; -const BIDDER_CODE = 'sharethrough'; -const SUPPLY_ID = 'WYu2BXv1'; +const VERSION = "4.3.0"; +const BIDDER_CODE = "sharethrough"; +const SUPPLY_ID = "WYu2BXv1"; const STR_ENDPOINT = `https://btlr.sharethrough.com/universal/v1?supply_id=${SUPPLY_ID}`; @@ -19,54 +18,69 @@ export const sharethroughAdapterSpec = { code: BIDDER_CODE, supportedMediaTypes: [VIDEO, BANNER], gvlid: 80, - isBidRequestValid: bid => !!bid.params.pkey && bid.bidder === BIDDER_CODE, + isBidRequestValid: (bid) => !!bid.params.pkey && bid.bidder === BIDDER_CODE, buildRequests: (bidRequests, bidderRequest) => { - const timeout = config.getConfig('bidderTimeout'); + const timeout = config.getConfig("bidderTimeout"); const firstPartyData = bidderRequest.ortb2 || {}; - const nonHttp = sharethroughInternal.getProtocol().indexOf('http') < 0; - const secure = nonHttp || (sharethroughInternal.getProtocol().indexOf('https') > -1); + const nonHttp = sharethroughInternal.getProtocol().indexOf("http") < 0; + const secure = + nonHttp || sharethroughInternal.getProtocol().indexOf("https") > -1; const req = { id: generateUUID(), at: 1, - cur: ['USD'], + cur: ["USD"], tmax: timeout, site: { - domain: deepAccess(bidderRequest, 'refererInfo.domain', window.location.hostname), - page: deepAccess(bidderRequest, 'refererInfo.page', window.location.href), - ref: deepAccess(bidderRequest, 'refererInfo.ref'), + domain: deepAccess( + bidderRequest, + "refererInfo.domain", + window.location.hostname + ), + page: deepAccess( + bidderRequest, + "refererInfo.page", + window.location.href + ), + ref: deepAccess(bidderRequest, "refererInfo.ref"), ...firstPartyData.site, }, device: { ua: navigator.userAgent, language: navigator.language, js: 1, - dnt: navigator.doNotTrack === '1' ? 1 : 0, + dnt: navigator.doNotTrack === "1" ? 1 : 0, h: window.screen.height, w: window.screen.width, }, regs: { - coppa: config.getConfig('coppa') === true ? 1 : 0, + coppa: config.getConfig("coppa") === true ? 1 : 0, ext: {}, }, source: { tid: bidderRequest.auctionId, ext: { - version: '$prebid.version$', + version: "$prebid.version$", str: VERSION, schain: bidRequests[0].schain, }, }, - bcat: deepAccess(bidderRequest.ortb2, 'bcat') || bidRequests[0].params.bcat || [], - badv: deepAccess(bidderRequest.ortb2, 'badv') || bidRequests[0].params.badv || [], + bcat: + deepAccess(bidderRequest.ortb2, "bcat") || + bidRequests[0].params.bcat || + [], + badv: + deepAccess(bidderRequest.ortb2, "badv") || + bidRequests[0].params.badv || + [], test: 0, }; req.user = nullish(firstPartyData.user, {}); if (!req.user.ext) req.user.ext = {}; - req.user.ext.eids = createEidsArray(deepAccess(bidRequests[0], 'userId')) || []; + req.user.ext.eids = deepAccess(bidRequests[0], "userIdAsEids") || []; if (bidderRequest.gdprConsent) { const gdprApplies = bidderRequest.gdprConsent.gdprApplies === true; @@ -80,66 +94,82 @@ export const sharethroughAdapterSpec = { req.regs.ext.us_privacy = bidderRequest.uspConsent; } - const imps = bidRequests.map(bidReq => { - const impression = { ext: {} }; - - // mergeDeep(impression, bidReq.ortb2Imp); // leaving this out for now as we may want to leave stuff out on purpose - const tid = deepAccess(bidReq, 'ortb2Imp.ext.tid'); - if (tid) impression.ext.tid = tid; - const gpid = deepAccess(bidReq, 'ortb2Imp.ext.gpid', deepAccess(bidReq, 'ortb2Imp.ext.data.pbadslot')); - if (gpid) impression.ext.gpid = gpid; - - const videoRequest = deepAccess(bidReq, 'mediaTypes.video'); - - if (videoRequest) { - // default playerSize, only change this if we know width and height are properly defined in the request - let [w, h] = [640, 360]; - if (videoRequest.playerSize && videoRequest.playerSize[0] && videoRequest.playerSize[1]) { - [w, h] = videoRequest.playerSize; + const imps = bidRequests + .map((bidReq) => { + const impression = { ext: {} }; + + // mergeDeep(impression, bidReq.ortb2Imp); // leaving this out for now as we may want to leave stuff out on purpose + const tid = deepAccess(bidReq, "ortb2Imp.ext.tid"); + if (tid) impression.ext.tid = tid; + const gpid = deepAccess( + bidReq, + "ortb2Imp.ext.gpid", + deepAccess(bidReq, "ortb2Imp.ext.data.pbadslot") + ); + if (gpid) impression.ext.gpid = gpid; + + const videoRequest = deepAccess(bidReq, "mediaTypes.video"); + + if (videoRequest) { + // default playerSize, only change this if we know width and height are properly defined in the request + let [w, h] = [640, 360]; + if ( + videoRequest.playerSize && + videoRequest.playerSize[0] && + videoRequest.playerSize[1] + ) { + [w, h] = videoRequest.playerSize; + } + + impression.video = { + pos: nullish(videoRequest.pos, 0), + topframe: inIframe() ? 0 : 1, + skip: nullish(videoRequest.skip, 0), + linearity: nullish(videoRequest.linearity, 1), + minduration: nullish(videoRequest.minduration, 5), + maxduration: nullish(videoRequest.maxduration, 60), + playbackmethod: videoRequest.playbackmethod || [2], + api: getVideoApi(videoRequest), + mimes: videoRequest.mimes || ["video/mp4"], + protocols: getVideoProtocols(videoRequest), + w, + h, + startdelay: nullish(videoRequest.startdelay, 0), + skipmin: nullish(videoRequest.skipmin, 0), + skipafter: nullish(videoRequest.skipafter, 0), + placement: + videoRequest.context === "instream" + ? 1 + : +deepAccess(videoRequest, "placement", 4), + }; + + if (videoRequest.delivery) + impression.video.delivery = videoRequest.delivery; + if (videoRequest.companiontype) + impression.video.companiontype = videoRequest.companiontype; + if (videoRequest.companionad) + impression.video.companionad = videoRequest.companionad; + } else { + impression.banner = { + pos: deepAccess(bidReq, "mediaTypes.banner.pos", 0), + topframe: inIframe() ? 0 : 1, + format: bidReq.sizes.map((size) => ({ w: +size[0], h: +size[1] })), + }; } - impression.video = { - pos: nullish(videoRequest.pos, 0), - topframe: inIframe() ? 0 : 1, - skip: nullish(videoRequest.skip, 0), - linearity: nullish(videoRequest.linearity, 1), - minduration: nullish(videoRequest.minduration, 5), - maxduration: nullish(videoRequest.maxduration, 60), - playbackmethod: videoRequest.playbackmethod || [2], - api: getVideoApi(videoRequest), - mimes: videoRequest.mimes || ['video/mp4'], - protocols: getVideoProtocols(videoRequest), - w, - h, - startdelay: nullish(videoRequest.startdelay, 0), - skipmin: nullish(videoRequest.skipmin, 0), - skipafter: nullish(videoRequest.skipafter, 0), - placement: videoRequest.context === 'instream' ? 1 : +deepAccess(videoRequest, 'placement', 4), + return { + id: bidReq.bidId, + tagid: String(bidReq.params.pkey), + secure: secure ? 1 : 0, + bidfloor: getBidRequestFloor(bidReq), + ...impression, }; + }) + .filter((imp) => !!imp); - if (videoRequest.delivery) impression.video.delivery = videoRequest.delivery; - if (videoRequest.companiontype) impression.video.companiontype = videoRequest.companiontype; - if (videoRequest.companionad) impression.video.companionad = videoRequest.companionad; - } else { - impression.banner = { - pos: deepAccess(bidReq, 'mediaTypes.banner.pos', 0), - topframe: inIframe() ? 0 : 1, - format: bidReq.sizes.map(size => ({ w: +size[0], h: +size[1] })), - }; - } - + return imps.map((impression) => { return { - id: bidReq.bidId, - tagid: String(bidReq.params.pkey), - secure: secure ? 1 : 0, - bidfloor: getBidRequestFloor(bidReq), - ...impression, - }; - }).filter(imp => !!imp); - - return imps.map(impression => { - return { - method: 'POST', + method: "POST", url: STR_ENDPOINT, data: { ...req, @@ -150,11 +180,17 @@ export const sharethroughAdapterSpec = { }, interpretResponse: ({ body }, req) => { - if (!body || !body.seatbid || body.seatbid.length === 0 || !body.seatbid[0].bid || body.seatbid[0].bid.length === 0) { + if ( + !body || + !body.seatbid || + body.seatbid.length === 0 || + !body.seatbid[0].bid || + body.seatbid[0].bid.length === 0 + ) { return []; } - return body.seatbid[0].bid.map(bid => { + return body.seatbid[0].bid.map((bid) => { const response = { requestId: bid.impid, width: +bid.w, @@ -163,7 +199,7 @@ export const sharethroughAdapterSpec = { creativeId: bid.crid, dealId: bid.dealid || null, mediaType: req.data.imp[0].video ? VIDEO : BANNER, - currency: body.cur || 'USD', + currency: body.cur || "USD", netRevenue: true, ttl: 360, ad: bid.adm, @@ -183,24 +219,26 @@ export const sharethroughAdapterSpec = { }, getUserSyncs: (syncOptions, serverResponses) => { - const shouldCookieSync = syncOptions.pixelEnabled && deepAccess(serverResponses, '0.body.cookieSyncUrls') !== undefined; + const shouldCookieSync = + syncOptions.pixelEnabled && + deepAccess(serverResponses, "0.body.cookieSyncUrls") !== undefined; return shouldCookieSync - ? serverResponses[0].body.cookieSyncUrls.map(url => ({ type: 'image', url: url })) + ? serverResponses[0].body.cookieSyncUrls.map((url) => ({ + type: "image", + url: url, + })) : []; }, // Empty implementation for prebid core to be able to find it - onTimeout: (data) => { - }, + onTimeout: (data) => {}, // Empty implementation for prebid core to be able to find it - onBidWon: (bid) => { - }, + onBidWon: (bid) => {}, // Empty implementation for prebid core to be able to find it - onSetTargeting: (bid) => { - }, + onSetTargeting: (bid) => {}, }; function getVideoApi({ api }) { @@ -223,13 +261,17 @@ function getVideoProtocols({ protocols }) { function getBidRequestFloor(bid) { let floor = null; - if (typeof bid.getFloor === 'function') { + if (typeof bid.getFloor === "function") { const floorInfo = bid.getFloor({ - currency: 'USD', - mediaType: bid.mediaTypes && bid.mediaTypes.video ? 'video' : 'banner', - size: bid.sizes.map(size => ({ w: size[0], h: size[1] })), + currency: "USD", + mediaType: bid.mediaTypes && bid.mediaTypes.video ? "video" : "banner", + size: bid.sizes.map((size) => ({ w: size[0], h: size[1] })), }); - if (typeof floorInfo === 'object' && floorInfo.currency === 'USD' && !isNaN(parseFloat(floorInfo.floor))) { + if ( + typeof floorInfo === "object" && + floorInfo.currency === "USD" && + !isNaN(parseFloat(floorInfo.floor)) + ) { floor = parseFloat(floorInfo.floor); } } diff --git a/modules/smartadserverBidAdapter.js b/modules/smartadserverBidAdapter.js index c07b2abe933..1aa513aaaca 100644 --- a/modules/smartadserverBidAdapter.js +++ b/modules/smartadserverBidAdapter.js @@ -1,17 +1,22 @@ -import { deepAccess, deepClone, logError, isFn, isPlainObject } from '../src/utils.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; -import { createEidsArray } from './userId/eids.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { + deepAccess, + deepClone, + logError, + isFn, + isPlainObject, +} from "../src/utils.js"; +import { BANNER, VIDEO } from "../src/mediaTypes.js"; +import { config } from "../src/config.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; -const BIDDER_CODE = 'smartadserver'; +const BIDDER_CODE = "smartadserver"; const GVL_ID = 45; const DEFAULT_FLOOR = 0.0; export const spec = { code: BIDDER_CODE, gvlid: GVL_ID, - aliases: ['smart'], // short code + aliases: ["smart"], // short code supportedMediaTypes: [BANNER, VIDEO], /** @@ -21,7 +26,12 @@ export const spec = { * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: function (bid) { - return !!(bid.params && bid.params.siteId && bid.params.pageId && bid.params.formatId); + return !!( + bid.params && + bid.params.siteId && + bid.params.pageId && + bid.params.formatId + ); }, /** @@ -29,14 +39,19 @@ export const spec = { * * @param {*} schain object */ - serializeSupplyChain: function(schain) { + serializeSupplyChain: function (schain) { if (!schain || !schain.nodes) return null; - const nodesProperties = ['asi', 'sid', 'hp', 'rid', 'name', 'domain']; - return `${schain.ver},${schain.complete}!` + - schain.nodes.map(node => nodesProperties.map(prop => - node[prop] ? encodeURIComponent(node[prop]) : '') - .join(',')) - .join('!'); + const nodesProperties = ["asi", "sid", "hp", "rid", "name", "domain"]; + return ( + `${schain.ver},${schain.complete}!` + + schain.nodes + .map((node) => + nodesProperties + .map((prop) => (node[prop] ? encodeURIComponent(node[prop]) : "")) + .join(",") + ) + .join("!") + ); }, /** @@ -45,10 +60,10 @@ export const spec = { * @param {*} bannerSizes Array of size array (ex. [[300, 250]]). * @returns */ - adaptBannerSizes: function(bannerSizes) { - return bannerSizes.map(size => ({ + adaptBannerSizes: function (bannerSizes) { + return bannerSizes.map((size) => ({ w: size[0], - h: size[1] + h: size[1], })); }, @@ -58,15 +73,25 @@ export const spec = { * @param {*} payload Payload that will be sent in the ServerRequest * @param {*} videoMediaType Video media type. */ - fillPayloadForVideoBidRequest: function(payload, videoMediaType, videoParams) { + fillPayloadForVideoBidRequest: function ( + payload, + videoMediaType, + videoParams + ) { const playerSize = videoMediaType.playerSize[0]; - payload.isVideo = videoMediaType.context === 'instream'; + payload.isVideo = videoMediaType.context === "instream"; payload.mediaType = VIDEO; payload.videoData = { - videoProtocol: this.getProtocolForVideoBidRequest(videoMediaType, videoParams), + videoProtocol: this.getProtocolForVideoBidRequest( + videoMediaType, + videoParams + ), playerWidth: playerSize[0], playerHeight: playerSize[1], - adBreak: this.getStartDelayForVideoBidRequest(videoMediaType, videoParams) + adBreak: this.getStartDelayForVideoBidRequest( + videoMediaType, + videoParams + ), }; }, @@ -76,7 +101,7 @@ export const spec = { * @param {*} videoParams * @returns protocol from either videoMediaType or videoParams */ - getProtocolForVideoBidRequest: function(videoMediaType, videoParams) { + getProtocolForVideoBidRequest: function (videoMediaType, videoParams) { if (videoParams !== undefined && videoParams.protocol) { return videoParams.protocol; } else if (videoMediaType !== undefined) { @@ -93,7 +118,7 @@ export const spec = { * @param {*} videoParams * @returns positive integer value of startdelay */ - getStartDelayForVideoBidRequest: function(videoMediaType, videoParams) { + getStartDelayForVideoBidRequest: function (videoMediaType, videoParams) { if (videoParams !== undefined && videoParams.startDelay) { return videoParams.startDelay; } else if (videoMediaType !== undefined) { @@ -105,7 +130,7 @@ export const spec = { return 3; } } - return 2;// Default value for all exotic cases set to bid.params.video.startDelay midroll hence 2. + return 2; // Default value for all exotic cases set to bid.params.video.startDelay midroll hence 2. }, /** @@ -115,10 +140,12 @@ export const spec = { * @param {string} domain Endpoint domain . * @returns {ServerRequest} Info describing the request to the server. */ - createServerRequest: function(payload, domain) { + createServerRequest: function (payload, domain) { return { - method: 'POST', - url: (domain !== undefined ? domain : 'https://prg.smartadserver.com') + '/prebid/v1', + method: "POST", + url: + (domain !== undefined ? domain : "https://prg.smartadserver.com") + + "/prebid/v1", data: JSON.stringify(payload), }; }, @@ -132,9 +159,17 @@ export const spec = { */ buildRequests: function (validBidRequests, bidderRequest) { // use bidderRequest.bids[] to get bidder-dependent request info - const adServerCurrency = config.getConfig('currency.adServerCurrency'); - const sellerDefinedAudience = deepAccess(bidderRequest, 'ortb2.user.data', config.getAnyConfig('ortb2.user.data')); - const sellerDefinedContext = deepAccess(bidderRequest, 'ortb2.site.content.data', config.getAnyConfig('ortb2.site.content.data')); + const adServerCurrency = config.getConfig("currency.adServerCurrency"); + const sellerDefinedAudience = deepAccess( + bidderRequest, + "ortb2.user.data", + config.getAnyConfig("ortb2.user.data") + ); + const sellerDefinedContext = deepAccess( + bidderRequest, + "ortb2.site.content.data", + config.getAnyConfig("ortb2.site.content.data") + ); // pull requested transaction ID from bidderRequest.bids[].transactionId return validBidRequests.reduce((bidRequests, bid) => { @@ -144,20 +179,34 @@ export const spec = { pageid: bid.params.pageId, formatid: bid.params.formatId, currencyCode: adServerCurrency, - targeting: bid.params.target && bid.params.target !== '' ? bid.params.target : undefined, - buid: bid.params.buId && bid.params.buId !== '' ? bid.params.buId : undefined, - appname: bid.params.appName && bid.params.appName !== '' ? bid.params.appName : undefined, + targeting: + bid.params.target && bid.params.target !== "" + ? bid.params.target + : undefined, + buid: + bid.params.buId && bid.params.buId !== "" + ? bid.params.buId + : undefined, + appname: + bid.params.appName && bid.params.appName !== "" + ? bid.params.appName + : undefined, ckid: bid.params.ckId || 0, tagId: bid.adUnitCode, // TODO: is 'page' the right value here? - pageDomain: bidderRequest && bidderRequest.refererInfo && bidderRequest.refererInfo.page ? bidderRequest.refererInfo.page : undefined, + pageDomain: + bidderRequest && + bidderRequest.refererInfo && + bidderRequest.refererInfo.page + ? bidderRequest.refererInfo.page + : undefined, transactionId: bid.transactionId, - timeout: config.getConfig('bidderTimeout'), + timeout: config.getConfig("bidderTimeout"), bidId: bid.bidId, - prebidVersion: '$prebid.version$', + prebidVersion: "$prebid.version$", schain: spec.serializeSupplyChain(bid.schain), sda: sellerDefinedAudience, - sdc: sellerDefinedContext + sdc: sellerDefinedContext, }; if (bidderRequest) { @@ -177,17 +226,20 @@ export const spec = { } } - if (bid && bid.userId) { - payload.eids = createEidsArray(bid.userId); + if (bid && bid.userIdAsEids) { + payload.eids = bid.userIdAsEids; } if (bidderRequest && bidderRequest.uspConsent) { payload.us_privacy = bidderRequest.uspConsent; } - const bannerMediaType = deepAccess(bid, 'mediaTypes.banner'); - const videoMediaType = deepAccess(bid, 'mediaTypes.video'); - const isSupportedVideoContext = videoMediaType && (videoMediaType.context === 'instream' || videoMediaType.context === 'outstream'); + const bannerMediaType = deepAccess(bid, "mediaTypes.banner"); + const videoMediaType = deepAccess(bid, "mediaTypes.video"); + const isSupportedVideoContext = + videoMediaType && + (videoMediaType.context === "instream" || + videoMediaType.context === "outstream"); if (bannerMediaType || isSupportedVideoContext) { let type; @@ -197,16 +249,29 @@ export const spec = { if (isSupportedVideoContext) { let videoPayload = deepClone(payload); - spec.fillPayloadForVideoBidRequest(videoPayload, videoMediaType, bid.params.video); - videoPayload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, VIDEO); - bidRequests.push(spec.createServerRequest(videoPayload, bid.params.domain)); + spec.fillPayloadForVideoBidRequest( + videoPayload, + videoMediaType, + bid.params.video + ); + videoPayload.bidfloor = + bid.params.bidfloor || + spec.getBidFloor(bid, adServerCurrency, VIDEO); + bidRequests.push( + spec.createServerRequest(videoPayload, bid.params.domain) + ); } } else { type = VIDEO; - spec.fillPayloadForVideoBidRequest(payload, videoMediaType, bid.params.video); + spec.fillPayloadForVideoBidRequest( + payload, + videoMediaType, + bid.params.video + ); } - payload.bidfloor = bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type); + payload.bidfloor = + bid.params.bidfloor || spec.getBidFloor(bid, adServerCurrency, type); bidRequests.push(spec.createServerRequest(payload, bid.params.domain)); } else { bidRequests.push({}); @@ -241,7 +306,7 @@ export const spec = { netRevenue: response.isNetCpm, ttl: response.ttl, dspPixels: response.dspPixels, - meta: { advertiserDomains: response.adomain ? response.adomain : [] } + meta: { advertiserDomains: response.adomain ? response.adomain : [] }, }; if (bidRequest.mediaType === VIDEO) { @@ -257,7 +322,7 @@ export const spec = { bidResponses.push(bidResponse); } } catch (error) { - logError('Error while parsing smart server response', error); + logError("Error while parsing smart server response", error); } return bidResponses; }, @@ -276,12 +341,14 @@ export const spec = { } const floor = bid.getFloor({ - currency: currency || 'USD', + currency: currency || "USD", mediaType, - size: '*' + size: "*", }); - return isPlainObject(floor) && !isNaN(floor.floor) ? floor.floor : DEFAULT_FLOOR; + return isPlainObject(floor) && !isNaN(floor.floor) + ? floor.floor + : DEFAULT_FLOOR; }, /** @@ -293,21 +360,29 @@ export const spec = { */ getUserSyncs: function (syncOptions, serverResponses) { const syncs = []; - if (syncOptions.iframeEnabled && serverResponses.length > 0 && serverResponses[0].body.cSyncUrl != null) { + if ( + syncOptions.iframeEnabled && + serverResponses.length > 0 && + serverResponses[0].body.cSyncUrl != null + ) { syncs.push({ - type: 'iframe', - url: serverResponses[0].body.cSyncUrl + type: "iframe", + url: serverResponses[0].body.cSyncUrl, }); - } else if (syncOptions.pixelEnabled && serverResponses.length > 0 && serverResponses[0].body.dspPixels !== undefined) { - serverResponses[0].body.dspPixels.forEach(function(pixel) { + } else if ( + syncOptions.pixelEnabled && + serverResponses.length > 0 && + serverResponses[0].body.dspPixels !== undefined + ) { + serverResponses[0].body.dspPixels.forEach(function (pixel) { syncs.push({ - type: 'image', - url: pixel + type: "image", + url: pixel, }); }); } return syncs; - } + }, }; registerBidder(spec); diff --git a/modules/sovrnBidAdapter.js b/modules/sovrnBidAdapter.js index ab8abb7e2b4..4f2cf43423a 100644 --- a/modules/sovrnBidAdapter.js +++ b/modules/sovrnBidAdapter.js @@ -7,52 +7,54 @@ import { logError, deepAccess, isInteger, - logWarn -} from '../src/utils.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js' -import { - ADPOD, - BANNER, - VIDEO -} from '../src/mediaTypes.js' -import {createEidsArray} from './userId/eids.js'; + logWarn, +} from "../src/utils.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { ADPOD, BANNER, VIDEO } from "../src/mediaTypes.js"; const ORTB_VIDEO_PARAMS = { - 'mimes': (value) => Array.isArray(value) && value.length > 0 && value.every(v => typeof v === 'string'), - 'minduration': (value) => isInteger(value), - 'maxduration': (value) => isInteger(value), - 'protocols': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 10), - 'w': (value) => isInteger(value), - 'h': (value) => isInteger(value), - 'startdelay': (value) => isInteger(value), - 'placement': (value) => isInteger(value) && value >= 1 && value <= 5, - 'linearity': (value) => [1, 2].indexOf(value) !== -1, - 'skip': (value) => [0, 1].indexOf(value) !== -1, - 'skipmin': (value) => isInteger(value), - 'skipafter': (value) => isInteger(value), - 'sequence': (value) => isInteger(value), - 'battr': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 17), - 'maxextended': (value) => isInteger(value), - 'minbitrate': (value) => isInteger(value), - 'maxbitrate': (value) => isInteger(value), - 'boxingallowed': (value) => [0, 1].indexOf(value) !== -1, - 'playbackmethod': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 6), - 'playbackend': (value) => [1, 2, 3].indexOf(value) !== -1, - 'delivery': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 3), - 'pos': (value) => isInteger(value) && value >= 1 && value <= 7, - 'api': (value) => Array.isArray(value) && value.every(v => v >= 1 && v <= 6) -} + mimes: (value) => + Array.isArray(value) && + value.length > 0 && + value.every((v) => typeof v === "string"), + minduration: (value) => isInteger(value), + maxduration: (value) => isInteger(value), + protocols: (value) => + Array.isArray(value) && value.every((v) => v >= 1 && v <= 10), + w: (value) => isInteger(value), + h: (value) => isInteger(value), + startdelay: (value) => isInteger(value), + placement: (value) => isInteger(value) && value >= 1 && value <= 5, + linearity: (value) => [1, 2].indexOf(value) !== -1, + skip: (value) => [0, 1].indexOf(value) !== -1, + skipmin: (value) => isInteger(value), + skipafter: (value) => isInteger(value), + sequence: (value) => isInteger(value), + battr: (value) => + Array.isArray(value) && value.every((v) => v >= 1 && v <= 17), + maxextended: (value) => isInteger(value), + minbitrate: (value) => isInteger(value), + maxbitrate: (value) => isInteger(value), + boxingallowed: (value) => [0, 1].indexOf(value) !== -1, + playbackmethod: (value) => + Array.isArray(value) && value.every((v) => v >= 1 && v <= 6), + playbackend: (value) => [1, 2, 3].indexOf(value) !== -1, + delivery: (value) => + Array.isArray(value) && value.every((v) => v >= 1 && v <= 3), + pos: (value) => isInteger(value) && value >= 1 && value <= 7, + api: (value) => Array.isArray(value) && value.every((v) => v >= 1 && v <= 6), +}; const REQUIRED_VIDEO_PARAMS = { context: (value) => value !== ADPOD, mimes: ORTB_VIDEO_PARAMS.mimes, minduration: ORTB_VIDEO_PARAMS.minduration, maxduration: ORTB_VIDEO_PARAMS.maxduration, - protocols: ORTB_VIDEO_PARAMS.protocols -} + protocols: ORTB_VIDEO_PARAMS.protocols, +}; export const spec = { - code: 'sovrn', + code: "sovrn", supportedMediaTypes: [BANNER, VIDEO], gvlid: 13, @@ -62,17 +64,16 @@ export const spec = { * @return boolean for whether or not a bid is valid */ isBidRequestValid: function (bid) { - const video = bid?.mediaTypes?.video + const video = bid?.mediaTypes?.video; return !!( bid.params.tagid && !isNaN(parseFloat(bid.params.tagid)) && - isFinite(bid.params.tagid) && ( - !video || ( - Object.keys(REQUIRED_VIDEO_PARAMS) - .every(key => REQUIRED_VIDEO_PARAMS[key](video[key])) - ) - ) - ) + isFinite(bid.params.tagid) && + (!video || + Object.keys(REQUIRED_VIDEO_PARAMS).every((key) => + REQUIRED_VIDEO_PARAMS[key](video[key]) + )) + ); }, /** @@ -81,7 +82,7 @@ export const spec = { * @param bidReqs * @param bidderRequest */ - buildRequests: function(bidReqs, bidderRequest) { + buildRequests: function (bidReqs, bidderRequest) { try { let sovrnImps = []; let iv; @@ -90,41 +91,51 @@ export const spec = { let criteoId; _each(bidReqs, function (bid) { - if (!eids && bid.userId) { - eids = createEidsArray(bid.userId) + if (!eids && bid.userIdAsEids) { + eids = bid.userIdAsEids; eids.forEach(function (id) { if (id.uids && id.uids[0]) { - if (id.source === 'criteo.com') { - criteoId = id.uids[0].id + if (id.source === "criteo.com") { + criteoId = id.uids[0].id; } } - }) + }); } if (bid.schain) { - schain = schain || bid.schain + schain = schain || bid.schain; } - iv = iv || getBidIdParameter('iv', bid.params) - - const floorInfo = (bid.getFloor && typeof bid.getFloor === 'function') ? bid.getFloor({ - currency: 'USD', - mediaType: bid.mediaTypes && bid.mediaTypes.banner ? 'banner' : 'video', - size: '*' - }) : {} - floorInfo.floor = floorInfo.floor || getBidIdParameter('bidfloor', bid.params) + iv = iv || getBidIdParameter("iv", bid.params); + + const floorInfo = + bid.getFloor && typeof bid.getFloor === "function" + ? bid.getFloor({ + currency: "USD", + mediaType: + bid.mediaTypes && bid.mediaTypes.banner ? "banner" : "video", + size: "*", + }) + : {}; + floorInfo.floor = + floorInfo.floor || getBidIdParameter("bidfloor", bid.params); const imp = { adunitcode: bid.adUnitCode, id: bid.bidId, - tagid: String(getBidIdParameter('tagid', bid.params)), - bidfloor: floorInfo.floor - } + tagid: String(getBidIdParameter("tagid", bid.params)), + bidfloor: floorInfo.floor, + }; - if (deepAccess(bid, 'mediaTypes.banner')) { - let bidSizes = deepAccess(bid, 'mediaTypes.banner.sizes') || bid.sizes - bidSizes = (isArray(bidSizes) && isArray(bidSizes[0])) ? bidSizes : [bidSizes] - bidSizes = bidSizes.filter(size => isArray(size)) - const processedSizes = bidSizes.map(size => ({w: parseInt(size[0], 10), h: parseInt(size[1], 10)})) + if (deepAccess(bid, "mediaTypes.banner")) { + let bidSizes = + deepAccess(bid, "mediaTypes.banner.sizes") || bid.sizes; + bidSizes = + isArray(bidSizes) && isArray(bidSizes[0]) ? bidSizes : [bidSizes]; + bidSizes = bidSizes.filter((size) => isArray(size)); + const processedSizes = bidSizes.map((size) => ({ + w: parseInt(size[0], 10), + h: parseInt(size[1], 10), + })); imp.banner = { format: processedSizes, @@ -132,53 +143,65 @@ export const spec = { h: 1, }; } - if (deepAccess(bid, 'mediaTypes.video')) { + if (deepAccess(bid, "mediaTypes.video")) { imp.video = _buildVideoRequestObj(bid); } - imp.ext = getBidIdParameter('ext', bid.ortb2Imp) || undefined + imp.ext = getBidIdParameter("ext", bid.ortb2Imp) || undefined; - const segmentsString = getBidIdParameter('segments', bid.params) + const segmentsString = getBidIdParameter("segments", bid.params); if (segmentsString) { - imp.ext = imp.ext || {} - imp.ext.deals = segmentsString.split(',').map(deal => deal.trim()) + imp.ext = imp.ext || {}; + imp.ext.deals = segmentsString.split(",").map((deal) => deal.trim()); } - sovrnImps.push(imp) - }) + sovrnImps.push(imp); + }); const fpd = bidderRequest.ortb2 || {}; - const site = fpd.site || {} - site.page = bidderRequest.refererInfo.page - site.domain = bidderRequest.refererInfo.domain + const site = fpd.site || {}; + site.page = bidderRequest.refererInfo.page; + site.domain = bidderRequest.refererInfo.domain; const sovrnBidReq = { id: getUniqueIdentifierStr(), imp: sovrnImps, site: site, - user: fpd.user || {} - } + user: fpd.user || {}, + }; if (schain) { sovrnBidReq.source = { ext: { - schain - } + schain, + }, }; } if (bidderRequest.gdprConsent) { - deepSetValue(sovrnBidReq, 'regs.ext.gdpr', +bidderRequest.gdprConsent.gdprApplies); - deepSetValue(sovrnBidReq, 'user.ext.consent', bidderRequest.gdprConsent.consentString) + deepSetValue( + sovrnBidReq, + "regs.ext.gdpr", + +bidderRequest.gdprConsent.gdprApplies + ); + deepSetValue( + sovrnBidReq, + "user.ext.consent", + bidderRequest.gdprConsent.consentString + ); } if (bidderRequest.uspConsent) { - deepSetValue(sovrnBidReq, 'regs.ext.us_privacy', bidderRequest.uspConsent); + deepSetValue( + sovrnBidReq, + "regs.ext.us_privacy", + bidderRequest.uspConsent + ); } if (eids) { - deepSetValue(sovrnBidReq, 'user.ext.eids', eids) + deepSetValue(sovrnBidReq, "user.ext.eids", eids); if (criteoId) { - deepSetValue(sovrnBidReq, 'user.ext.prebid_criteoid', criteoId) + deepSetValue(sovrnBidReq, "user.ext.prebid_criteoid", criteoId); } } @@ -186,13 +209,13 @@ export const spec = { if (iv) url += `&iv=${iv}`; return { - method: 'POST', + method: "POST", url: url, data: JSON.stringify(sovrnBidReq), - options: {contentType: 'text/plain'} - } + options: { contentType: "text/plain" }, + }; } catch (e) { - logError('Could not build bidrequest, error deatils:', e); + logError("Could not build bidrequest, error deatils:", e); } }, @@ -200,114 +223,138 @@ export const spec = { * Format Sovrn responses as Prebid bid responses * @param {id, seatbid} sovrnResponse A successful response from Sovrn. * @return {Bid[]} An array of formatted bids. - */ - interpretResponse: function({ body: {id, seatbid} }) { - if (!id || !seatbid || !Array.isArray(seatbid)) return [] + */ + interpretResponse: function ({ body: { id, seatbid } }) { + if (!id || !seatbid || !Array.isArray(seatbid)) return []; try { return seatbid - .filter(seat => seat) - .map(seat => seat.bid.map(sovrnBid => { - const bid = { - requestId: sovrnBid.impid, - cpm: parseFloat(sovrnBid.price), - width: parseInt(sovrnBid.w), - height: parseInt(sovrnBid.h), - creativeId: sovrnBid.crid || sovrnBid.id, - dealId: sovrnBid.dealid || null, - currency: 'USD', - netRevenue: true, - mediaType: sovrnBid.nurl ? BANNER : VIDEO, - ttl: sovrnBid.ext?.ttl || 90, - meta: { advertiserDomains: sovrnBid && sovrnBid.adomain ? sovrnBid.adomain : [] } - } - - if (sovrnBid.nurl) { - bid.ad = decodeURIComponent(`${sovrnBid.adm}`) - } else { - bid.vastXml = decodeURIComponent(sovrnBid.adm) - } + .filter((seat) => seat) + .map((seat) => + seat.bid.map((sovrnBid) => { + const bid = { + requestId: sovrnBid.impid, + cpm: parseFloat(sovrnBid.price), + width: parseInt(sovrnBid.w), + height: parseInt(sovrnBid.h), + creativeId: sovrnBid.crid || sovrnBid.id, + dealId: sovrnBid.dealid || null, + currency: "USD", + netRevenue: true, + mediaType: sovrnBid.nurl ? BANNER : VIDEO, + ttl: sovrnBid.ext?.ttl || 90, + meta: { + advertiserDomains: + sovrnBid && sovrnBid.adomain ? sovrnBid.adomain : [], + }, + }; + + if (sovrnBid.nurl) { + bid.ad = decodeURIComponent( + `${sovrnBid.adm}` + ); + } else { + bid.vastXml = decodeURIComponent(sovrnBid.adm); + } - return bid - })) - .flat() + return bid; + }) + ) + .flat(); } catch (e) { - logError('Could not interpret bidresponse, error details:', e) - return e + logError("Could not interpret bidresponse, error details:", e); + return e; } }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { + getUserSyncs: function ( + syncOptions, + serverResponses, + gdprConsent, + uspConsent + ) { try { - const tracks = [] + const tracks = []; if (serverResponses && serverResponses.length !== 0) { if (syncOptions.iframeEnabled) { - const iidArr = serverResponses.filter(resp => deepAccess(resp, 'body.ext.iid')) - .map(resp => resp.body.ext.iid); + const iidArr = serverResponses + .filter((resp) => deepAccess(resp, "body.ext.iid")) + .map((resp) => resp.body.ext.iid); const params = []; - if (gdprConsent && gdprConsent.gdprApplies && typeof gdprConsent.consentString === 'string') { - params.push(['gdpr_consent', gdprConsent.consentString]); + if ( + gdprConsent && + gdprConsent.gdprApplies && + typeof gdprConsent.consentString === "string" + ) { + params.push(["gdpr_consent", gdprConsent.consentString]); } if (uspConsent) { - params.push(['us_privacy', uspConsent]); + params.push(["us_privacy", uspConsent]); } if (iidArr[0]) { - params.push(['informer', iidArr[0]]); + params.push(["informer", iidArr[0]]); tracks.push({ - type: 'iframe', - url: 'https://ap.lijit.com/beacon?' + params.map(p => p.join('=')).join('&') + type: "iframe", + url: + "https://ap.lijit.com/beacon?" + + params.map((p) => p.join("=")).join("&"), }); } } if (syncOptions.pixelEnabled) { - serverResponses.filter(resp => deepAccess(resp, 'body.ext.sync.pixels')) + serverResponses + .filter((resp) => deepAccess(resp, "body.ext.sync.pixels")) .reduce((acc, resp) => acc.concat(resp.body.ext.sync.pixels), []) - .map(pixel => pixel.url) - .forEach(url => tracks.push({ type: 'image', url })) + .map((pixel) => pixel.url) + .forEach((url) => tracks.push({ type: "image", url })); } } - return tracks + return tracks; } catch (e) { - return [] + return []; } }, -} +}; function _buildVideoRequestObj(bid) { - const videoObj = {} - const bidSizes = deepAccess(bid, 'sizes') - const videoAdUnitParams = deepAccess(bid, 'mediaTypes.video', {}) - const videoBidderParams = deepAccess(bid, 'params.video', {}) - const computedParams = {} + const videoObj = {}; + const bidSizes = deepAccess(bid, "sizes"); + const videoAdUnitParams = deepAccess(bid, "mediaTypes.video", {}); + const videoBidderParams = deepAccess(bid, "params.video", {}); + const computedParams = {}; if (bidSizes) { - const sizes = (Array.isArray(bidSizes[0])) ? bidSizes[0] : bidSizes - computedParams.w = sizes[0] - computedParams.h = sizes[1] + const sizes = Array.isArray(bidSizes[0]) ? bidSizes[0] : bidSizes; + computedParams.w = sizes[0]; + computedParams.h = sizes[1]; } else if (Array.isArray(videoAdUnitParams.playerSize)) { - const sizes = (Array.isArray(videoAdUnitParams.playerSize[0])) ? videoAdUnitParams.playerSize[0] : videoAdUnitParams.playerSize - computedParams.w = sizes[0] - computedParams.h = sizes[1] + const sizes = Array.isArray(videoAdUnitParams.playerSize[0]) + ? videoAdUnitParams.playerSize[0] + : videoAdUnitParams.playerSize; + computedParams.w = sizes[0]; + computedParams.h = sizes[1]; } const videoParams = { ...computedParams, ...videoAdUnitParams, - ...videoBidderParams + ...videoBidderParams, }; - Object.keys(ORTB_VIDEO_PARAMS).forEach(paramName => { + Object.keys(ORTB_VIDEO_PARAMS).forEach((paramName) => { if (videoParams.hasOwnProperty(paramName)) { if (ORTB_VIDEO_PARAMS[paramName](videoParams[paramName])) { - videoObj[paramName] = videoParams[paramName] + videoObj[paramName] = videoParams[paramName]; } else { - logWarn(`The OpenRTB video param ${paramName} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.`); + logWarn( + `The OpenRTB video param ${paramName} has been skipped due to misformating. Please refer to OpenRTB 2.5 spec.` + ); } } - }) - return videoObj + }); + return videoObj; } -registerBidder(spec) +registerBidder(spec); diff --git a/modules/ttdBidAdapter.js b/modules/ttdBidAdapter.js index 884c43c438a..a83cf1cda04 100644 --- a/modules/ttdBidAdapter.js +++ b/modules/ttdBidAdapter.js @@ -1,41 +1,49 @@ -import * as utils from '../src/utils.js'; -import { config } from '../src/config.js'; -import { createEidsArray } from './userId/eids.js'; -import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; - -const BIDADAPTERVERSION = 'TTD-PREBID-2022.06.28'; -const BIDDER_CODE = 'ttd'; -const BIDDER_CODE_LONG = 'thetradedesk'; -const BIDDER_ENDPOINT = 'https://direct.adsrvr.org/bid/bidder/'; -const USER_SYNC_ENDPOINT = 'https://match.adsrvr.org'; +import * as utils from "../src/utils.js"; +import { config } from "../src/config.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { BANNER, VIDEO } from "../src/mediaTypes.js"; + +const BIDADAPTERVERSION = "TTD-PREBID-2022.06.28"; +const BIDDER_CODE = "ttd"; +const BIDDER_CODE_LONG = "thetradedesk"; +const BIDDER_ENDPOINT = "https://direct.adsrvr.org/bid/bidder/"; +const USER_SYNC_ENDPOINT = "https://match.adsrvr.org"; const MEDIA_TYPE = { BANNER: 1, - VIDEO: 2 + VIDEO: 2, }; function getExt(firstPartyData) { const ext = { ver: BIDADAPTERVERSION, - pbjs: '$prebid.version$', - keywords: firstPartyData.site?.keywords ? firstPartyData.site.keywords.split(',').map(k => k.trim()) : [] - } + pbjs: "$prebid.version$", + keywords: firstPartyData.site?.keywords + ? firstPartyData.site.keywords.split(",").map((k) => k.trim()) + : [], + }; return { - ttdprebid: ext + ttdprebid: ext, }; } function getRegs(bidderRequest) { let regs = {}; - if (bidderRequest.gdprConsent && typeof bidderRequest.gdprConsent.gdprApplies === 'boolean') { - utils.deepSetValue(regs, 'ext.gdpr', bidderRequest.gdprConsent.gdprApplies ? 1 : 0); + if ( + bidderRequest.gdprConsent && + typeof bidderRequest.gdprConsent.gdprApplies === "boolean" + ) { + utils.deepSetValue( + regs, + "ext.gdpr", + bidderRequest.gdprConsent.gdprApplies ? 1 : 0 + ); } if (bidderRequest.uspConsent) { - utils.deepSetValue(regs, 'ext.us_privacy', bidderRequest.uspConsent); + utils.deepSetValue(regs, "ext.us_privacy", bidderRequest.uspConsent); } - if (config.getConfig('coppa') === true) { + if (config.getConfig("coppa") === true) { regs.coppa = 1; } if (bidderRequest.ortb2?.regs) { @@ -51,11 +59,15 @@ function getBidFloor(bid) { } let floor = bid.getFloor({ - currency: 'USD', - mediaType: '*', - size: '*' + currency: "USD", + mediaType: "*", + size: "*", }); - if (utils.isPlainObject(floor) && !isNaN(floor.floor) && floor.currency === 'USD') { + if ( + utils.isPlainObject(floor) && + !isNaN(floor.floor) && + floor.currency === "USD" + ) { return floor.floor; } return null; @@ -63,25 +75,29 @@ function getBidFloor(bid) { function getSource(validBidRequests) { let source = { - tid: validBidRequests[0].auctionId + tid: validBidRequests[0].auctionId, }; if (validBidRequests[0].schain) { - utils.deepSetValue(source, 'ext.schain', validBidRequests[0].schain); + utils.deepSetValue(source, "ext.schain", validBidRequests[0].schain); } return source; } function getDevice() { - const language = navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage; + const language = + navigator.language || + navigator.browserLanguage || + navigator.userLanguage || + navigator.systemLanguage; let device = { ua: navigator.userAgent, dnt: utils.getDNT() ? 1 : 0, language: language, - connectiontype: getConnectionType() + connectiontype: getConnectionType(), }; return device; -}; +} function getConnectionType() { const connection = navigator.connection || navigator.webkitConnection; @@ -89,18 +105,18 @@ function getConnectionType() { return 0; } switch (connection.type) { - case 'ethernet': + case "ethernet": return 1; - case 'wifi': + case "wifi": return 2; - case 'cellular': + case "cellular": switch (connection.effectiveType) { - case 'slow-2g': - case '2g': + case "slow-2g": + case "2g": return 4; - case '3g': + case "3g": return 5; - case '4g': + case "4g": return 6; default: return 3; @@ -113,66 +129,75 @@ function getConnectionType() { function getUser(bidderRequest) { let user = {}; if (bidderRequest.gdprConsent) { - utils.deepSetValue(user, 'ext.consent', bidderRequest.gdprConsent.consentString); + utils.deepSetValue( + user, + "ext.consent", + bidderRequest.gdprConsent.consentString + ); } - if (utils.isStr(utils.deepAccess(bidderRequest, 'bids.0.userId.tdid'))) { + if (utils.isStr(utils.deepAccess(bidderRequest, "bids.0.userId.tdid"))) { user.buyeruid = bidderRequest.bids[0].userId.tdid; } - var eids = createEidsArray(utils.deepAccess(bidderRequest, 'bids.0.userId')) + var eids = utils.deepAccess(bidderRequest, "userIdAsEids"); if (eids.length) { - utils.deepSetValue(user, 'ext.eids', eids); + utils.deepSetValue(user, "ext.eids", eids); } // gather user.data - const ortb2UserData = utils.deepAccess(bidderRequest, 'ortb2.user.data'); + const ortb2UserData = utils.deepAccess(bidderRequest, "ortb2.user.data"); if (ortb2UserData && ortb2UserData.length) { user = utils.mergeDeep(user, { - data: [...ortb2UserData] + data: [...ortb2UserData], }); - }; + } return user; } function getSite(bidderRequest, firstPartyData) { - var site = utils.mergeDeep({ - page: utils.deepAccess(bidderRequest, 'refererInfo.page'), - ref: utils.deepAccess(bidderRequest, 'refererInfo.ref'), - publisher: { - id: utils.deepAccess(bidderRequest, 'bids.0.params.publisherId'), + var site = utils.mergeDeep( + { + page: utils.deepAccess(bidderRequest, "refererInfo.page"), + ref: utils.deepAccess(bidderRequest, "refererInfo.ref"), + publisher: { + id: utils.deepAccess(bidderRequest, "bids.0.params.publisherId"), + }, }, - }, - firstPartyData.site + firstPartyData.site ); var publisherDomain = bidderRequest.refererInfo.domain; if (publisherDomain) { - utils.deepSetValue(site, 'publisher.domain', publisherDomain); + utils.deepSetValue(site, "publisher.domain", publisherDomain); } return site; } function getImpression(bidRequest) { let impression = { - id: bidRequest.bidId + id: bidRequest.bidId, }; - const gpid = utils.deepAccess(bidRequest, 'ortb2Imp.ext.gpid'); - const tid = utils.deepAccess(bidRequest, 'ortb2Imp.ext.tid'); + const gpid = utils.deepAccess(bidRequest, "ortb2Imp.ext.gpid"); + const tid = utils.deepAccess(bidRequest, "ortb2Imp.ext.tid"); if (gpid || tid) { - impression.ext = {} - if (gpid) { impression.ext.gpid = gpid } - if (tid) { impression.ext.tid = tid } + impression.ext = {}; + if (gpid) { + impression.ext.gpid = gpid; + } + if (tid) { + impression.ext.tid = tid; + } } const tagid = gpid || bidRequest.params.placementId; if (tagid) { - impression.tagid = tagid + impression.tagid = tagid; } - const mediaTypesVideo = utils.deepAccess(bidRequest, 'mediaTypes.video'); - const mediaTypesBanner = utils.deepAccess(bidRequest, 'mediaTypes.banner'); + const mediaTypesVideo = utils.deepAccess(bidRequest, "mediaTypes.video"); + const mediaTypesBanner = utils.deepAccess(bidRequest, "mediaTypes.banner"); let mediaTypes = {}; if (mediaTypesBanner) { @@ -187,35 +212,36 @@ function getImpression(bidRequest) { let bidfloor = getBidFloor(bidRequest); if (bidfloor) { impression.bidfloor = parseFloat(bidfloor); - impression.bidfloorcur = 'USD'; + impression.bidfloorcur = "USD"; } return impression; } function getSizes(sizes) { - const sizeStructs = utils.parseSizesInput(sizes) - .filter(x => x) // sizes that don't conform are returned as null, which we want to ignore - .map(x => x.split('x')) - .map(size => { + const sizeStructs = utils + .parseSizesInput(sizes) + .filter((x) => x) // sizes that don't conform are returned as null, which we want to ignore + .map((x) => x.split("x")) + .map((size) => { return { width: parseInt(size[0]), height: parseInt(size[1]), - } + }; }); return sizeStructs; } function banner(bid) { - const sizes = getSizes(bid.mediaTypes.banner.sizes).map(x => { + const sizes = getSizes(bid.mediaTypes.banner.sizes).map((x) => { return { w: x.width, h: x.height, - } + }; }); - const pos = parseInt(utils.deepAccess(bid, 'mediaTypes.banner.pos')); - const expdir = utils.deepAccess(bid, 'params.banner.expdir'); + const pos = parseInt(utils.deepAccess(bid, "mediaTypes.banner.pos")); + const expdir = utils.deepAccess(bid, "params.banner.expdir"); let optionalParams = {}; if (pos) { optionalParams.pos = pos; @@ -230,9 +256,10 @@ function banner(bid) { h: sizes[0].h, format: sizes, }, - optionalParams); + optionalParams + ); - const battr = utils.deepAccess(bid, 'ortb2Imp.battr'); + const battr = utils.deepAccess(bid, "ortb2Imp.battr"); if (battr) { banner.battr = battr; } @@ -241,21 +268,24 @@ function banner(bid) { } function video(bid) { - let minduration = utils.deepAccess(bid, 'mediaTypes.video.minduration'); - const maxduration = utils.deepAccess(bid, 'mediaTypes.video.maxduration'); - const playerSize = utils.deepAccess(bid, 'mediaTypes.video.playerSize'); - const api = utils.deepAccess(bid, 'mediaTypes.video.api'); - const mimes = utils.deepAccess(bid, 'mediaTypes.video.mimes'); - const placement = utils.deepAccess(bid, 'mediaTypes.video.placement'); - const protocols = utils.deepAccess(bid, 'mediaTypes.video.protocols'); - const playbackmethod = utils.deepAccess(bid, 'mediaTypes.video.playbackmethod'); - const pos = utils.deepAccess(bid, 'mediaTypes.video.pos'); - const startdelay = utils.deepAccess(bid, 'mediaTypes.video.startdelay'); - const skip = utils.deepAccess(bid, 'mediaTypes.video.skip'); - const skipmin = utils.deepAccess(bid, 'mediaTypes.video.skipmin'); - const skipafter = utils.deepAccess(bid, 'mediaTypes.video.skipafter'); - const minbitrate = utils.deepAccess(bid, 'mediaTypes.video.minbitrate'); - const maxbitrate = utils.deepAccess(bid, 'mediaTypes.video.maxbitrate'); + let minduration = utils.deepAccess(bid, "mediaTypes.video.minduration"); + const maxduration = utils.deepAccess(bid, "mediaTypes.video.maxduration"); + const playerSize = utils.deepAccess(bid, "mediaTypes.video.playerSize"); + const api = utils.deepAccess(bid, "mediaTypes.video.api"); + const mimes = utils.deepAccess(bid, "mediaTypes.video.mimes"); + const placement = utils.deepAccess(bid, "mediaTypes.video.placement"); + const protocols = utils.deepAccess(bid, "mediaTypes.video.protocols"); + const playbackmethod = utils.deepAccess( + bid, + "mediaTypes.video.playbackmethod" + ); + const pos = utils.deepAccess(bid, "mediaTypes.video.pos"); + const startdelay = utils.deepAccess(bid, "mediaTypes.video.startdelay"); + const skip = utils.deepAccess(bid, "mediaTypes.video.skip"); + const skipmin = utils.deepAccess(bid, "mediaTypes.video.skipmin"); + const skipafter = utils.deepAccess(bid, "mediaTypes.video.skipafter"); + const minbitrate = utils.deepAccess(bid, "mediaTypes.video.minbitrate"); + const maxbitrate = utils.deepAccess(bid, "mediaTypes.video.maxbitrate"); if (!minduration || !utils.isInteger(minduration)) { minduration = 0; @@ -266,10 +296,10 @@ function video(bid) { api: api, mimes: mimes, placement: placement, - protocols: protocols + protocols: protocols, }; - if (typeof playerSize !== 'undefined') { + if (typeof playerSize !== "undefined") { if (utils.isArray(playerSize[0])) { video.w = parseInt(playerSize[0][0]); video.h = parseInt(playerSize[0][1]); @@ -304,7 +334,7 @@ function video(bid) { video.maxbitrate = maxbitrate; } - const battr = utils.deepAccess(bid, 'ortb2Imp.battr'); + const battr = utils.deepAccess(bid, "ortb2Imp.battr"); if (battr) { video.battr = battr; } @@ -329,55 +359,84 @@ export const spec = { // required parameters if (!bid || !bid.params) { - utils.logWarn(BIDDER_CODE + ': Missing bid parameters'); + utils.logWarn(BIDDER_CODE + ": Missing bid parameters"); return false; } if (!bid.params.supplySourceId) { - utils.logWarn(BIDDER_CODE + ': Missing required parameter params.supplySourceId'); + utils.logWarn( + BIDDER_CODE + ": Missing required parameter params.supplySourceId" + ); return false; } if (!alphaRegex.test(bid.params.supplySourceId)) { - utils.logWarn(BIDDER_CODE + ': supplySourceId must only contain alphabetic characters'); + utils.logWarn( + BIDDER_CODE + ": supplySourceId must only contain alphabetic characters" + ); return false; } if (!bid.params.publisherId) { - utils.logWarn(BIDDER_CODE + ': Missing required parameter params.publisherId'); + utils.logWarn( + BIDDER_CODE + ": Missing required parameter params.publisherId" + ); return false; } if (bid.params.publisherId.length > 32) { - utils.logWarn(BIDDER_CODE + ': params.publisherId must be 32 characters or less'); + utils.logWarn( + BIDDER_CODE + ": params.publisherId must be 32 characters or less" + ); return false; } - const gpid = utils.deepAccess(bid, 'ortb2Imp.ext.gpid'); + const gpid = utils.deepAccess(bid, "ortb2Imp.ext.gpid"); if (!bid.params.placementId && !gpid) { - utils.logWarn(BIDDER_CODE + ': one of params.placementId or gpid (via the GPT module https://docs.prebid.org/dev-docs/modules/gpt-pre-auction.html) must be passed'); + utils.logWarn( + BIDDER_CODE + + ": one of params.placementId or gpid (via the GPT module https://docs.prebid.org/dev-docs/modules/gpt-pre-auction.html) must be passed" + ); return false; } - const mediaTypesBanner = utils.deepAccess(bid, 'mediaTypes.banner'); - const mediaTypesVideo = utils.deepAccess(bid, 'mediaTypes.video'); + const mediaTypesBanner = utils.deepAccess(bid, "mediaTypes.banner"); + const mediaTypesVideo = utils.deepAccess(bid, "mediaTypes.video"); if (!mediaTypesBanner && !mediaTypesVideo) { - utils.logWarn(BIDDER_CODE + ': one of mediaTypes.banner or mediaTypes.video must be passed'); + utils.logWarn( + BIDDER_CODE + + ": one of mediaTypes.banner or mediaTypes.video must be passed" + ); return false; } if (mediaTypesVideo) { - if (!mediaTypesVideo.maxduration || !utils.isInteger(mediaTypesVideo.maxduration)) { - utils.logWarn(BIDDER_CODE + ': mediaTypes.video.maxduration must be set to the maximum video ad duration in seconds'); + if ( + !mediaTypesVideo.maxduration || + !utils.isInteger(mediaTypesVideo.maxduration) + ) { + utils.logWarn( + BIDDER_CODE + + ": mediaTypes.video.maxduration must be set to the maximum video ad duration in seconds" + ); return false; } if (!mediaTypesVideo.api || mediaTypesVideo.api.length === 0) { - utils.logWarn(BIDDER_CODE + ': mediaTypes.video.api should be an array of supported api frameworks. See the Open RTB v2.5 spec for valid values'); + utils.logWarn( + BIDDER_CODE + + ": mediaTypes.video.api should be an array of supported api frameworks. See the Open RTB v2.5 spec for valid values" + ); return false; } if (!mediaTypesVideo.mimes || mediaTypesVideo.mimes.length === 0) { - utils.logWarn(BIDDER_CODE + ': mediaTypes.video.mimes should be an array of supported mime types'); + utils.logWarn( + BIDDER_CODE + + ": mediaTypes.video.mimes should be an array of supported mime types" + ); return false; } if (!mediaTypesVideo.protocols) { - utils.logWarn(BIDDER_CODE + ': mediaTypes.video.protocols should be an array of supported protocols. See the Open RTB v2.5 spec for valid values'); + utils.logWarn( + BIDDER_CODE + + ": mediaTypes.video.protocols should be an array of supported protocols. See the Open RTB v2.5 spec for valid values" + ); return false; } } @@ -396,16 +455,16 @@ export const spec = { const firstPartyData = bidderRequest.ortb2 || {}; let topLevel = { id: bidderRequest.auctionId, - imp: validBidRequests.map(bidRequest => getImpression(bidRequest)), + imp: validBidRequests.map((bidRequest) => getImpression(bidRequest)), site: getSite(bidderRequest, firstPartyData), device: getDevice(), user: getUser(bidderRequest), at: 1, - cur: ['USD'], + cur: ["USD"], regs: getRegs(bidderRequest), source: getSource(validBidRequests), - ext: getExt(firstPartyData) - } + ext: getExt(firstPartyData), + }; if (firstPartyData && firstPartyData.bcat) { topLevel.bcat = firstPartyData.bcat; @@ -418,12 +477,12 @@ export const spec = { let url = BIDDER_ENDPOINT + bidderRequest.bids[0].params.supplySourceId; let serverRequest = { - method: 'POST', + method: "POST", url: url, data: topLevel, options: { - withCredentials: true - } + withCredentials: true, + }, }; return serverRequest; @@ -450,19 +509,21 @@ export const spec = { * @param {ttdResponseObj} bidResponse A successful response from ttd. * @param {ServerRequest} serverRequest The result of buildRequests() that lead to this response. * @return {Bid[]} An array of formatted bids. - */ + */ interpretResponse: function (response, serverRequest) { - let seatBidsInResponse = utils.deepAccess(response, 'body.seatbid'); - const currency = utils.deepAccess(response, 'body.cur'); + let seatBidsInResponse = utils.deepAccess(response, "body.seatbid"); + const currency = utils.deepAccess(response, "body.cur"); if (!seatBidsInResponse || seatBidsInResponse.length === 0) { return []; } let bidResponses = []; - let requestedImpressions = utils.deepAccess(serverRequest, 'data.imp'); + let requestedImpressions = utils.deepAccess(serverRequest, "data.imp"); - seatBidsInResponse.forEach(seatBid => { - seatBid.bid.forEach(bid => { - let matchingRequestedImpression = requestedImpressions.find(imp => imp.id === bid.impid); + seatBidsInResponse.forEach((seatBid) => { + seatBid.bid.forEach((bid) => { + let matchingRequestedImpression = requestedImpressions.find( + (imp) => imp.id === bid.impid + ); const cpm = bid.price || 0; let bidResponse = { @@ -470,7 +531,7 @@ export const spec = { cpm: cpm, creativeId: bid.crid, dealId: bid.dealid || null, - currency: currency || 'USD', + currency: currency || "USD", netRevenue: true, ttl: bid.ttl || 360, meta: {}, @@ -481,24 +542,18 @@ export const spec = { } if (bid.ext.mediatype === MEDIA_TYPE.BANNER) { - Object.assign( - bidResponse, - { - width: bid.w, - height: bid.h, - ad: utils.replaceAuctionPrice(bid.adm, cpm), - mediaType: BANNER - } - ); + Object.assign(bidResponse, { + width: bid.w, + height: bid.h, + ad: utils.replaceAuctionPrice(bid.adm, cpm), + mediaType: BANNER, + }); } else if (bid.ext.mediatype === MEDIA_TYPE.VIDEO) { - Object.assign( - bidResponse, - { - width: matchingRequestedImpression.video.w, - height: matchingRequestedImpression.video.h, - mediaType: VIDEO - } - ); + Object.assign(bidResponse, { + width: matchingRequestedImpression.video.w, + height: matchingRequestedImpression.video.h, + mediaType: VIDEO, + }); if (bid.nurl) { bidResponse.vastUrl = utils.replaceAuctionPrice(bid.nurl, cpm); } else { @@ -522,26 +577,35 @@ export const spec = { * @param {uspConsent} uspConsent USP consent object * @return {UserSync[]} The user syncs which should be dropped. */ - getUserSyncs: function(syncOptions, serverResponses, gdprConsent = {}, uspConsent = '') { + getUserSyncs: function ( + syncOptions, + serverResponses, + gdprConsent = {}, + uspConsent = "" + ) { const syncs = []; - let gdprParams = `&gdpr=${gdprConsent.gdprApplies ? 1 : 0}&gdpr_consent=${encodeURIComponent(gdprConsent.consentString)}`; + let gdprParams = `&gdpr=${ + gdprConsent.gdprApplies ? 1 : 0 + }&gdpr_consent=${encodeURIComponent(gdprConsent.consentString)}`; - let url = `${USER_SYNC_ENDPOINT}/track/usersync?us_privacy=${encodeURIComponent(uspConsent)}${gdprParams}`; + let url = `${USER_SYNC_ENDPOINT}/track/usersync?us_privacy=${encodeURIComponent( + uspConsent + )}${gdprParams}`; if (syncOptions.pixelEnabled) { syncs.push({ - type: 'image', - url: url + '&ust=image' + type: "image", + url: url + "&ust=image", }); } else if (syncOptions.iframeEnabled) { syncs.push({ - type: 'iframe', - url: url + '&ust=iframe' + type: "iframe", + url: url + "&ust=iframe", }); } return syncs; }, }; -registerBidder(spec) +registerBidder(spec); diff --git a/modules/yieldmoBidAdapter.js b/modules/yieldmoBidAdapter.js index b4b916a1048..5ae6cd83d57 100644 --- a/modules/yieldmoBidAdapter.js +++ b/modules/yieldmoBidAdapter.js @@ -11,34 +11,52 @@ import { isStr, logError, parseQueryStringParameters, - parseUrl -} from '../src/utils.js'; -import {BANNER, VIDEO} from '../src/mediaTypes.js'; -import {registerBidder} from '../src/adapters/bidderFactory.js'; -import {Renderer} from '../src/Renderer.js'; -import {find, includes} from '../src/polyfill.js'; -import {createEidsArray} from './userId/eids.js'; - -const BIDDER_CODE = 'yieldmo'; + parseUrl, +} from "../src/utils.js"; +import { BANNER, VIDEO } from "../src/mediaTypes.js"; +import { registerBidder } from "../src/adapters/bidderFactory.js"; +import { Renderer } from "../src/Renderer.js"; +import { find, includes } from "../src/polyfill.js"; + +const BIDDER_CODE = "yieldmo"; const GVLID = 173; -const CURRENCY = 'USD'; +const CURRENCY = "USD"; const TIME_TO_LIVE = 300; const NET_REVENUE = true; const PB_COOKIE_ASSIST_SYNC_ENDPOINT = `https://ads.yieldmo.com/pbcas`; -const BANNER_PATH = '/exchange/prebid'; -const VIDEO_PATH = '/exchange/prebidvideo'; -const STAGE_DOMAIN = 'https://ads-stg.yieldmo.com'; -const PROD_DOMAIN = 'https://ads.yieldmo.com'; -const OUTSTREAM_VIDEO_PLAYER_URL = 'https://prebid-outstream.yieldmo.com/bundle.js'; -const OPENRTB_VIDEO_BIDPARAMS = ['mimes', 'startdelay', 'placement', 'startdelay', 'skipafter', 'protocols', 'api', - 'playbackmethod', 'maxduration', 'minduration', 'pos', 'skip', 'skippable']; -const OPENRTB_VIDEO_SITEPARAMS = ['name', 'domain', 'cat', 'keywords']; +const BANNER_PATH = "/exchange/prebid"; +const VIDEO_PATH = "/exchange/prebidvideo"; +const STAGE_DOMAIN = "https://ads-stg.yieldmo.com"; +const PROD_DOMAIN = "https://ads.yieldmo.com"; +const OUTSTREAM_VIDEO_PLAYER_URL = + "https://prebid-outstream.yieldmo.com/bundle.js"; +const OPENRTB_VIDEO_BIDPARAMS = [ + "mimes", + "startdelay", + "placement", + "startdelay", + "skipafter", + "protocols", + "api", + "playbackmethod", + "maxduration", + "minduration", + "pos", + "skip", + "skippable", +]; +const OPENRTB_VIDEO_SITEPARAMS = ["name", "domain", "cat", "keywords"]; const LOCAL_WINDOW = getWindowTop(); const DEFAULT_PLAYBACK_METHOD = 2; const DEFAULT_START_DELAY = 0; const VAST_TIMEOUT = 15000; const MAX_BANNER_REQUEST_URL_LENGTH = 8000; -const BANNER_REQUEST_PROPERTIES_TO_REDUCE = ['description', 'title', 'pr', 'page_url']; +const BANNER_REQUEST_PROPERTIES_TO_REDUCE = [ + "description", + "title", + "pr", + "page_url", +]; export const spec = { code: BIDDER_CODE, @@ -50,8 +68,13 @@ export const spec = { * @return boolean, true if valid, otherwise false */ isBidRequestValid: function (bid) { - return !!(bid && bid.adUnitCode && bid.bidId && (hasBannerMediaType(bid) || hasVideoMediaType(bid)) && - validateVideoParams(bid)); + return !!( + bid && + bid.adUnitCode && + bid.bidId && + (hasBannerMediaType(bid) || hasVideoMediaType(bid)) && + validateVideoParams(bid) + ); }, /** @@ -65,13 +88,17 @@ export const spec = { const stage = isStage(bidderRequest); const bannerUrl = getAdserverUrl(BANNER_PATH, stage); const videoUrl = getAdserverUrl(VIDEO_PATH, stage); - const bannerBidRequests = bidRequests.filter(request => hasBannerMediaType(request)); - const videoBidRequests = bidRequests.filter(request => hasVideoMediaType(request)); + const bannerBidRequests = bidRequests.filter((request) => + hasBannerMediaType(request) + ); + const videoBidRequests = bidRequests.filter((request) => + hasVideoMediaType(request) + ); let serverRequests = []; const eids = getEids(bidRequests[0]) || []; if (bannerBidRequests.length > 0) { let serverRequest = { - pbav: '$prebid.version$', + pbav: "$prebid.version$", p: [], // TODO: is 'page' the right value here? page_url: bidderRequest.refererInfo.page, @@ -80,16 +107,18 @@ export const spec = { description: getPageDescription(), userConsent: JSON.stringify({ // case of undefined, stringify will remove param - gdprApplies: deepAccess(bidderRequest, 'gdprConsent.gdprApplies') || '', - cmp: deepAccess(bidderRequest, 'gdprConsent.consentString') || '' + gdprApplies: + deepAccess(bidderRequest, "gdprConsent.gdprApplies") || "", + cmp: deepAccess(bidderRequest, "gdprConsent.consentString") || "", }), - us_privacy: deepAccess(bidderRequest, 'uspConsent') || '' + us_privacy: deepAccess(bidderRequest, "uspConsent") || "", }; if (canAccessTopWindow()) { - serverRequest.pr = (LOCAL_WINDOW.document && LOCAL_WINDOW.document.referrer) || ''; + serverRequest.pr = + (LOCAL_WINDOW.document && LOCAL_WINDOW.document.referrer) || ""; serverRequest.scrd = LOCAL_WINDOW.devicePixelRatio || 0; - serverRequest.title = LOCAL_WINDOW.document.title || ''; + serverRequest.title = LOCAL_WINDOW.document.title || ""; serverRequest.w = LOCAL_WINDOW.innerWidth; serverRequest.h = LOCAL_WINDOW.innerHeight; } @@ -99,40 +128,46 @@ export const spec = { serverRequest.mtp = mtp; } - bannerBidRequests.forEach(request => { + bannerBidRequests.forEach((request) => { serverRequest.p.push(addPlacement(request)); - const pubcid = getId(request, 'pubcid'); + const pubcid = getId(request, "pubcid"); if (pubcid) { serverRequest.pubcid = pubcid; } else if (request.crumbs && request.crumbs.pubcid) { serverRequest.pubcid = request.crumbs.pubcid; } - const tdid = getId(request, 'tdid'); + const tdid = getId(request, "tdid"); if (tdid) { serverRequest.tdid = tdid; } - const criteoId = getId(request, 'criteoId'); + const criteoId = getId(request, "criteoId"); if (criteoId) { serverRequest.cri_prebid = criteoId; } if (request.schain) { serverRequest.schain = JSON.stringify(request.schain); } - if (deepAccess(request, 'params.lr_env')) { + if (deepAccess(request, "params.lr_env")) { serverRequest.ats_envelope = request.params.lr_env; } }); - serverRequest.p = '[' + serverRequest.p.toString() + ']'; + serverRequest.p = "[" + serverRequest.p.toString() + "]"; if (eids.length) { serverRequest.eids = JSON.stringify(eids); - }; + } // check if url exceeded max length - const fullUrl = `${bannerUrl}?${parseQueryStringParameters(serverRequest)}`; + const fullUrl = `${bannerUrl}?${parseQueryStringParameters( + serverRequest + )}`; let extraCharacters = fullUrl.length - MAX_BANNER_REQUEST_URL_LENGTH; if (extraCharacters > 0) { for (let i = 0; i < BANNER_REQUEST_PROPERTIES_TO_REDUCE.length; i++) { - extraCharacters = shortcutProperty(extraCharacters, serverRequest, BANNER_REQUEST_PROPERTIES_TO_REDUCE[i]); + extraCharacters = shortcutProperty( + extraCharacters, + serverRequest, + BANNER_REQUEST_PROPERTIES_TO_REDUCE[i] + ); if (extraCharacters <= 0) { break; @@ -141,9 +176,9 @@ export const spec = { } serverRequests.push({ - method: 'GET', + method: "GET", url: bannerUrl, - data: serverRequest + data: serverRequest, }); } @@ -151,11 +186,11 @@ export const spec = { const serverRequest = openRtbRequest(videoBidRequests, bidderRequest); if (eids.length) { serverRequest.user = { eids }; - }; + } serverRequests.push({ - method: 'POST', + method: "POST", url: videoUrl, - data: serverRequest + data: serverRequest, }); } return serverRequests; @@ -171,39 +206,49 @@ export const spec = { let bids = []; const data = serverResponse.body; if (data.length > 0) { - data.forEach(response => { + data.forEach((response) => { if (response.cpm > 0) { bids.push(createNewBannerBid(response)); } }); } if (data.seatbid) { - const seatbids = data.seatbid.reduce((acc, seatBid) => acc.concat(seatBid.bid), []); - seatbids.forEach(bid => bids.push(createNewVideoBid(bid, bidRequest))); + const seatbids = data.seatbid.reduce( + (acc, seatBid) => acc.concat(seatBid.bid), + [] + ); + seatbids.forEach((bid) => bids.push(createNewVideoBid(bid, bidRequest))); } return bids; }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent = {}, uspConsent = '') { + getUserSyncs: function ( + syncOptions, + serverResponses, + gdprConsent = {}, + uspConsent = "" + ) { const syncs = []; const gdprFlag = `&gdpr=${gdprConsent.gdprApplies ? 1 : 0}`; - const gdprString = `&gdpr_consent=${encodeURIComponent((gdprConsent.consentString || ''))}`; + const gdprString = `&gdpr_consent=${encodeURIComponent( + gdprConsent.consentString || "" + )}`; const usPrivacy = `us_privacy=${encodeURIComponent(uspConsent)}`; const pbCookieAssistSyncUrl = `${PB_COOKIE_ASSIST_SYNC_ENDPOINT}?${usPrivacy}${gdprFlag}${gdprString}`; if (syncOptions.iframeEnabled) { syncs.push({ - type: 'iframe', - url: pbCookieAssistSyncUrl + '&type=iframe' + type: "iframe", + url: pbCookieAssistSyncUrl + "&type=iframe", }); } else if (syncOptions.pixelEnabled) { syncs.push({ - type: 'image', - url: pbCookieAssistSyncUrl + '&type=image' + type: "image", + url: pbCookieAssistSyncUrl + "&type=image", }); } return syncs; - } + }, }; registerBidder(spec); @@ -215,14 +260,14 @@ registerBidder(spec); * @param {BidRequest} bidRequest bid request */ function hasBannerMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.banner'); + return !!deepAccess(bidRequest, "mediaTypes.banner"); } /** * @param {BidRequest} bidRequest bid request */ function hasVideoMediaType(bidRequest) { - return !!deepAccess(bidRequest, 'mediaTypes.video'); + return !!deepAccess(bidRequest, "mediaTypes.video"); } /** @@ -230,11 +275,11 @@ function hasVideoMediaType(bidRequest) { * @param request bid request */ function addPlacement(request) { - const gpid = deepAccess(request, 'ortb2Imp.ext.data.pbadslot'); + const gpid = deepAccess(request, "ortb2Imp.ext.data.pbadslot"); const placementInfo = { placement_id: request.adUnitCode, callback_id: request.bidId, - sizes: request.mediaTypes.banner.sizes + sizes: request.mediaTypes.banner.sizes, }; if (request.params) { if (request.params.placementId) { @@ -250,7 +295,7 @@ function addPlacement(request) { } // get the transaction id for the banner bid. - const transactionId = deepAccess(request, 'ortb2Imp.ext.tid'); + const transactionId = deepAccess(request, "ortb2Imp.ext.tid"); if (transactionId) { placementInfo.tid = transactionId; @@ -268,7 +313,7 @@ function addPlacement(request) { function createNewBannerBid(response) { return { dealId: response.publisherDealId, - requestId: response['callback_id'], + requestId: response["callback_id"], cpm: response.cpm, width: response.width, height: response.height, @@ -290,7 +335,10 @@ function createNewBannerBid(response) { * @param bidRequest server request */ function createNewVideoBid(response, bidRequest) { - const imp = find((deepAccess(bidRequest, 'data.imp') || []), imp => imp.id === response.impid); + const imp = find( + deepAccess(bidRequest, "data.imp") || [], + (imp) => imp.id === response.impid + ); let result = { dealId: response.dealid, @@ -321,7 +369,7 @@ function createNewVideoBid(response, bidRequest) { allowVpaid: true, autoPlay: true, preload: true, - mute: true + mute: true, }, id: imp.tagid, loaded: false, @@ -346,7 +394,7 @@ function createNewVideoBid(response, bidRequest) { */ function getDNT() { return ( - window.doNotTrack === '1' || window.navigator.doNotTrack === '1' || false + window.doNotTrack === "1" || window.navigator.doNotTrack === "1" || false ); } @@ -355,11 +403,13 @@ function getDNT() { */ function getPageDescription() { if (document.querySelector('meta[name="description"]')) { - return document - .querySelector('meta[name="description"]') - .getAttribute('content') || ''; // Value of the description metadata from the publisher's page. + return ( + document + .querySelector('meta[name="description"]') + .getAttribute("content") || "" + ); // Value of the description metadata from the publisher's page. } else { - return ''; + return ""; } } @@ -370,7 +420,9 @@ function getPageDescription() { * @returns an id if there is one, or undefined */ function getId(request, idType) { - return (typeof deepAccess(request, 'userId') === 'object') ? request.userId[idType] : undefined; + return typeof deepAccess(request, "userId") === "object" + ? request.userId[idType] + : undefined; } /** @@ -384,13 +436,13 @@ function openRtbRequest(bidRequests, bidderRequest) { id: bidRequests[0].bidderRequestId, tmax: bidderRequest.timeout || 400, at: 1, - imp: bidRequests.map(bidRequest => openRtbImpression(bidRequest)), + imp: bidRequests.map((bidRequest) => openRtbImpression(bidRequest)), site: openRtbSite(bidRequests[0], bidderRequest), - device: deepAccess(bidderRequest, 'ortb2.device'), + device: deepAccess(bidderRequest, "ortb2.device"), badv: bidRequests[0].params.badv || [], - bcat: deepAccess(bidderRequest, 'bcat') || bidRequests[0].params.bcat || [], + bcat: deepAccess(bidderRequest, "bcat") || bidRequests[0].params.bcat || [], ext: { - prebid: '$prebid.version$', + prebid: "$prebid.version$", }, ats_envelope: bidRequests[0].params.lr_env, }; @@ -412,7 +464,7 @@ function openRtbRequest(bidRequests, bidderRequest) { * @return Object OpenRTB's 'imp' (impression) object */ function openRtbImpression(bidRequest) { - const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.data.pbadslot'); + const gpid = deepAccess(bidRequest, "ortb2Imp.ext.data.pbadslot"); const size = extractPlayerSize(bidRequest); const imp = { id: bidRequest.bidId, @@ -420,24 +472,24 @@ function openRtbImpression(bidRequest) { bidfloor: getBidFloor(bidRequest, VIDEO), ext: { placement_id: bidRequest.params.placementId, - tid: deepAccess(bidRequest, 'ortb2Imp.ext.tid') + tid: deepAccess(bidRequest, "ortb2Imp.ext.tid"), }, video: { w: size[0], h: size[1], - linearity: 1 - } + linearity: 1, + }, }; - const mediaTypesParams = deepAccess(bidRequest, 'mediaTypes.video'); + const mediaTypesParams = deepAccess(bidRequest, "mediaTypes.video"); Object.keys(mediaTypesParams) - .filter(param => includes(OPENRTB_VIDEO_BIDPARAMS, param)) - .forEach(param => imp.video[param] = mediaTypesParams[param]); + .filter((param) => includes(OPENRTB_VIDEO_BIDPARAMS, param)) + .forEach((param) => (imp.video[param] = mediaTypesParams[param])); - const videoParams = deepAccess(bidRequest, 'params.video'); + const videoParams = deepAccess(bidRequest, "params.video"); Object.keys(videoParams) - .filter(param => includes(OPENRTB_VIDEO_BIDPARAMS, param)) - .forEach(param => imp.video[param] = videoParams[param]); + .filter((param) => includes(OPENRTB_VIDEO_BIDPARAMS, param)) + .forEach((param) => (imp.video[param] = videoParams[param])); if (imp.video.skippable) { imp.video.skip = 1; @@ -445,7 +497,7 @@ function openRtbImpression(bidRequest) { } if (imp.video.placement !== 1) { imp.video.startdelay = DEFAULT_START_DELAY; - imp.video.playbackmethod = [ DEFAULT_PLAYBACK_METHOD ]; + imp.video.playbackmethod = [DEFAULT_PLAYBACK_METHOD]; } if (gpid) { imp.ext.gpid = gpid; @@ -456,11 +508,20 @@ function openRtbImpression(bidRequest) { function getBidFloor(bidRequest, mediaType) { let floorInfo = {}; - if (typeof bidRequest.getFloor === 'function') { - floorInfo = bidRequest.getFloor({ currency: CURRENCY, mediaType, size: '*' }); + if (typeof bidRequest.getFloor === "function") { + floorInfo = bidRequest.getFloor({ + currency: CURRENCY, + mediaType, + size: "*", + }); } - return floorInfo.floor || bidRequest.params.bidfloor || bidRequest.params.bidFloor || 0; + return ( + floorInfo.floor || + bidRequest.params.bidfloor || + bidRequest.params.bidFloor || + 0 + ); } /** @@ -468,7 +529,7 @@ function getBidFloor(bidRequest, mediaType) { * @return [number, number] || null Player's width and height, or undefined otherwise. */ function extractPlayerSize(bidRequest) { - const sizeArr = deepAccess(bidRequest, 'mediaTypes.video.playerSize'); + const sizeArr = deepAccess(bidRequest, "mediaTypes.video.playerSize"); if (isArrayOfNums(sizeArr, 2)) { return sizeArr; } else if (isArray(sizeArr) && isArrayOfNums(sizeArr[0], 2)) { @@ -485,7 +546,7 @@ function extractPlayerSize(bidRequest) { function openRtbSite(bidRequest, bidderRequest) { let result = {}; - const loc = parseUrl(deepAccess(bidderRequest, 'refererInfo.page')); + const loc = parseUrl(deepAccess(bidderRequest, "refererInfo.page")); if (!isEmpty(loc)) { result.page = `${loc.protocol}://${loc.hostname}${loc.pathname}`; } @@ -494,16 +555,16 @@ function openRtbSite(bidRequest, bidderRequest) { result.ref = bidderRequest.refererInfo.ref; } - const keywords = document.getElementsByTagName('meta')['keywords']; + const keywords = document.getElementsByTagName("meta")["keywords"]; if (keywords && keywords.content) { result.keywords = keywords.content; } - const siteParams = deepAccess(bidRequest, 'params.site'); + const siteParams = deepAccess(bidRequest, "params.site"); if (siteParams) { Object.keys(siteParams) - .filter(param => includes(OPENRTB_VIDEO_SITEPARAMS, param)) - .forEach(param => result[param] = siteParams[param]); + .filter((param) => includes(OPENRTB_VIDEO_SITEPARAMS, param)) + .forEach((param) => (result[param] = siteParams[param])); } return result; } @@ -515,13 +576,13 @@ function openRtbSite(bidRequest, bidderRequest) { */ function populateOpenRtbGdpr(openRtbRequest, bidderRequest) { const gdpr = bidderRequest.gdprConsent; - if (gdpr && 'gdprApplies' in gdpr) { - deepSetValue(openRtbRequest, 'regs.ext.gdpr', gdpr.gdprApplies ? 1 : 0); - deepSetValue(openRtbRequest, 'user.ext.consent', gdpr.consentString); + if (gdpr && "gdprApplies" in gdpr) { + deepSetValue(openRtbRequest, "regs.ext.gdpr", gdpr.gdprApplies ? 1 : 0); + deepSetValue(openRtbRequest, "user.ext.consent", gdpr.consentString); } - const uspConsent = deepAccess(bidderRequest, 'uspConsent'); + const uspConsent = deepAccess(bidderRequest, "uspConsent"); if (uspConsent) { - deepSetValue(openRtbRequest, 'regs.ext.us_privacy', uspConsent); + deepSetValue(openRtbRequest, "regs.ext.us_privacy", uspConsent); } } @@ -538,22 +599,22 @@ function validateVideoParams(bid) { const paramRequired = (paramStr, value, conditionStr) => { let error = `"${paramStr}" is required`; if (conditionStr) { - error += ' when ' + conditionStr; + error += " when " + conditionStr; } throw new Error(error); }; const paramInvalid = (paramStr, value, expectedStr) => { - expectedStr = expectedStr ? ', expected: ' + expectedStr : ''; + expectedStr = expectedStr ? ", expected: " + expectedStr : ""; value = JSON.stringify(value); throw new Error(`"${paramStr}"=${value} is invalid${expectedStr}`); }; - const isDefined = val => typeof val !== 'undefined'; + const isDefined = (val) => typeof val !== "undefined"; const validate = (fieldPath, validateCb, errorCb, errorCbParam) => { - if (fieldPath.indexOf('video') === 0) { - const valueFieldPath = 'params.' + fieldPath; - const mediaFieldPath = 'mediaTypes.' + fieldPath; + if (fieldPath.indexOf("video") === 0) { + const valueFieldPath = "params." + fieldPath; + const mediaFieldPath = "mediaTypes." + fieldPath; const valueParams = deepAccess(bid, valueFieldPath); const mediaTypesParams = deepAccess(bid, mediaFieldPath); const hasValidValueParams = validateCb(valueParams); @@ -562,8 +623,10 @@ function validateVideoParams(bid) { if (hasValidValueParams) return valueParams; else if (hasValidMediaTypesParams) return hasValidMediaTypesParams; else { - if (!hasValidValueParams) errorCb(valueFieldPath, valueParams, errorCbParam); - else if (!hasValidMediaTypesParams) errorCb(mediaFieldPath, mediaTypesParams, errorCbParam); + if (!hasValidValueParams) + errorCb(valueFieldPath, valueParams, errorCbParam); + else if (!hasValidMediaTypesParams) + errorCb(mediaFieldPath, mediaTypesParams, errorCbParam); } return valueParams || mediaTypesParams; } else { @@ -576,47 +639,104 @@ function validateVideoParams(bid) { }; try { - validate('video.context', val => !isEmpty(val), paramRequired); - - validate('params.placementId', val => !isEmpty(val), paramRequired); - - validate('video.playerSize', val => isArrayOfNums(val, 2) || - (isArray(val) && val.every(v => isArrayOfNums(v, 2))), - paramInvalid, 'array of 2 integers, ex: [640,480] or [[640,480]]'); - - validate('video.mimes', val => isDefined(val), paramRequired); - validate('video.mimes', val => isArray(val) && val.every(v => isStr(v)), paramInvalid, - 'array of strings, ex: ["video/mp4"]'); - - const placement = validate('video.placement', val => isDefined(val), paramRequired); - validate('video.placement', val => val >= 1 && val <= 5, paramInvalid); + validate("video.context", (val) => !isEmpty(val), paramRequired); + + validate("params.placementId", (val) => !isEmpty(val), paramRequired); + + validate( + "video.playerSize", + (val) => + isArrayOfNums(val, 2) || + (isArray(val) && val.every((v) => isArrayOfNums(v, 2))), + paramInvalid, + "array of 2 integers, ex: [640,480] or [[640,480]]" + ); + + validate("video.mimes", (val) => isDefined(val), paramRequired); + validate( + "video.mimes", + (val) => isArray(val) && val.every((v) => isStr(v)), + paramInvalid, + 'array of strings, ex: ["video/mp4"]' + ); + + const placement = validate( + "video.placement", + (val) => isDefined(val), + paramRequired + ); + validate("video.placement", (val) => val >= 1 && val <= 5, paramInvalid); if (placement === 1) { - validate('video.startdelay', val => isDefined(val), - (field, v) => paramRequired(field, v, 'placement == 1')); - validate('video.startdelay', val => isNumber(val), paramInvalid, 'number, ex: 5'); + validate( + "video.startdelay", + (val) => isDefined(val), + (field, v) => paramRequired(field, v, "placement == 1") + ); + validate( + "video.startdelay", + (val) => isNumber(val), + paramInvalid, + "number, ex: 5" + ); } - validate('video.protocols', val => isDefined(val), paramRequired); - validate('video.protocols', val => isArrayOfNums(val) && val.every(v => (v >= 1 && v <= 6)), - paramInvalid, 'array of numbers, ex: [2,3]'); - - validate('video.api', val => isDefined(val), paramRequired); - validate('video.api', val => isArrayOfNums(val) && val.every(v => (v >= 1 && v <= 6)), - paramInvalid, 'array of numbers, ex: [2,3]'); - - validate('video.playbackmethod', val => !isDefined(val) || isArrayOfNums(val), paramInvalid, - 'array of integers, ex: [2,6]'); - - validate('video.maxduration', val => isDefined(val), paramRequired); - validate('video.maxduration', val => isInteger(val), paramInvalid); - validate('video.minduration', val => !isDefined(val) || isNumber(val), paramInvalid); - validate('video.skippable', val => !isDefined(val) || isBoolean(val), paramInvalid); - validate('video.skipafter', val => !isDefined(val) || isNumber(val), paramInvalid); - validate('video.pos', val => !isDefined(val) || isNumber(val), paramInvalid); - validate('params.badv', val => !isDefined(val) || isArray(val), paramInvalid, - 'array of strings, ex: ["ford.com","pepsi.com"]'); - validate('params.bcat', val => !isDefined(val) || isArray(val), paramInvalid, - 'array of strings, ex: ["IAB1-5","IAB1-6"]'); + validate("video.protocols", (val) => isDefined(val), paramRequired); + validate( + "video.protocols", + (val) => isArrayOfNums(val) && val.every((v) => v >= 1 && v <= 6), + paramInvalid, + "array of numbers, ex: [2,3]" + ); + + validate("video.api", (val) => isDefined(val), paramRequired); + validate( + "video.api", + (val) => isArrayOfNums(val) && val.every((v) => v >= 1 && v <= 6), + paramInvalid, + "array of numbers, ex: [2,3]" + ); + + validate( + "video.playbackmethod", + (val) => !isDefined(val) || isArrayOfNums(val), + paramInvalid, + "array of integers, ex: [2,6]" + ); + + validate("video.maxduration", (val) => isDefined(val), paramRequired); + validate("video.maxduration", (val) => isInteger(val), paramInvalid); + validate( + "video.minduration", + (val) => !isDefined(val) || isNumber(val), + paramInvalid + ); + validate( + "video.skippable", + (val) => !isDefined(val) || isBoolean(val), + paramInvalid + ); + validate( + "video.skipafter", + (val) => !isDefined(val) || isNumber(val), + paramInvalid + ); + validate( + "video.pos", + (val) => !isDefined(val) || isNumber(val), + paramInvalid + ); + validate( + "params.badv", + (val) => !isDefined(val) || isArray(val), + paramInvalid, + 'array of strings, ex: ["ford.com","pepsi.com"]' + ); + validate( + "params.bcat", + (val) => !isDefined(val) || isArray(val), + paramInvalid, + 'array of strings, ex: ["IAB1-5","IAB1-6"]' + ); return true; } catch (e) { logError(e.message); @@ -634,14 +754,17 @@ function validateVideoParams(bid) { */ function shortcutProperty(extraCharacters, target, propertyName) { if (target[propertyName].length > extraCharacters) { - target[propertyName] = target[propertyName].substring(0, target[propertyName].length - extraCharacters); + target[propertyName] = target[propertyName].substring( + 0, + target[propertyName].length - extraCharacters + ); - return 0 + return 0; } const charactersLeft = extraCharacters - target[propertyName].length; - target[propertyName] = ''; + target[propertyName] = ""; return charactersLeft; } @@ -652,10 +775,10 @@ function shortcutProperty(extraCharacters, target, propertyName) { * @return array of eids objects */ function getEids(bidRequest) { - if (deepAccess(bidRequest, 'userId')) { - return createEidsArray(bidRequest.userId) || []; + if (deepAccess(bidRequest, "userIdAsEids")) { + return bidRequest.bid.userIdAsEids || []; } -}; +} /** * Check if top window can be accessed @@ -673,7 +796,7 @@ function canAccessTopWindow() { } function isStage(bidderRequest) { - return !!bidderRequest.refererInfo?.referer?.includes('pb_force_a'); + return !!bidderRequest.refererInfo?.referer?.includes("pb_force_a"); } function getAdserverUrl(path, stage) { diff --git a/package-lock.json b/package-lock.json index 66295994170..91bc7e93a84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "prebid.js", - "version": "7.36.0-pre", + "version": "7.39.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.16.7", @@ -54,7 +54,7 @@ "execa": "^1.0.0", "faker": "^5.5.3", "fs.extra": "^1.3.2", - "gulp": "^4.0.0", + "gulp": "^4.0.2", "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0", diff --git a/package.json b/package.json index a05a958dd17..f36b75f75b3 100644 --- a/package.json +++ b/package.json @@ -63,7 +63,7 @@ "execa": "^1.0.0", "faker": "^5.5.3", "fs.extra": "^1.3.2", - "gulp": "^4.0.0", + "gulp": "^4.0.2", "gulp-clean": "^0.4.0", "gulp-concat": "^2.6.0", "gulp-connect": "^5.7.0",