import { getWindowTop, deepAccess, logMessage } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; /** * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid */ const BIDDER_CODE = 'colossusssp'; const G_URL = 'https://colossusssp.com/?c=o&m=multi'; const G_URL_SYNC = 'https://sync.colossusssp.com'; function isBidResponseValid(bid) { if (!bid.requestId || !bid.cpm || !bid.creativeId || !bid.ttl || !bid.currency) { return false; } switch (bid.mediaType) { case BANNER: return Boolean(bid.width && bid.height && bid.ad); case VIDEO: return Boolean(bid.vastUrl); case NATIVE: return Boolean(bid.native); default: return false; } } function getUserId(eids, id, source, uidExt) { if (id) { var uid = { id }; if (uidExt) { uid.ext = uidExt; } eids.push({ source, uids: [ uid ] }); } } export const spec = { code: BIDDER_CODE, supportedMediaTypes: [BANNER, VIDEO, NATIVE], /** * Determines whether or not the given bid request is valid. * * @param {object} bid The bid to validate. * @return boolean True if this is a valid bid, and false otherwise. */ isBidRequestValid: (bid) => { const validPlacamentId = bid.params && !isNaN(bid.params.placement_id); const validGroupId = bid.params && !isNaN(bid.params.group_id); return Boolean(bid.bidId && (validPlacamentId || validGroupId)); }, /** * Make a server request from the list of BidRequests. * * @param {BidRequest[]} validBidRequests A non-empty list of valid bid requests that should be sent to the Server. * @return ServerRequest Info describing the request to the server. */ buildRequests: (validBidRequests, bidderRequest) => { // convert Native ORTB definition to old-style prebid native definition validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests); let deviceWidth = 0; let deviceHeight = 0; let winLocation; try { const winTop = getWindowTop(); deviceWidth = winTop.screen.width; deviceHeight = winTop.screen.height; winLocation = winTop.location; } catch (e) { logMessage(e); winLocation = window.location; } const refferUrl = bidderRequest.refererInfo?.page; let refferLocation; try { refferLocation = refferUrl && new URL(refferUrl); } catch (e) { logMessage(e); } const firstPartyData = bidderRequest.ortb2 || {}; const userObj = firstPartyData.user; const siteObj = firstPartyData.site; const appObj = firstPartyData.app; // TODO: does the fallback to window.location make sense? const location = refferLocation || winLocation; let placements = []; let request = { deviceWidth, deviceHeight, language: (navigator && navigator.language) ? navigator.language : '', secure: location.protocol === 'https:' ? 1 : 0, host: location.host, page: location.pathname, userObj, siteObj, appObj, placements: placements }; if (bidderRequest) { if (bidderRequest.uspConsent) { request.ccpa = bidderRequest.uspConsent; } if (bidderRequest.gdprConsent) { request.gdpr_consent = bidderRequest.gdprConsent.consentString || 'ALL'; request.gdpr_require = bidderRequest.gdprConsent.gdprApplies ? 1 : 0; } // Add GPP consent if (bidderRequest.gppConsent) { request.gpp = bidderRequest.gppConsent.gppString; request.gpp_sid = bidderRequest.gppConsent.applicableSections; } else if (bidderRequest.ortb2?.regs?.gpp) { request.gpp = bidderRequest.ortb2.regs.gpp; request.gpp_sid = bidderRequest.ortb2.regs.gpp_sid; } } for (let i = 0; i < validBidRequests.length; i++) { let bid = validBidRequests[i]; const { mediaTypes } = bid; let placement = { placementId: bid.params.placement_id, groupId: bid.params.group_id, bidId: bid.bidId, tid: bid.ortb2Imp?.ext?.tid, eids: bid.userIdAsEids || [], floor: {} }; if (bid.schain) { placement.schain = bid.schain; } let gpid = deepAccess(bid, 'ortb2Imp.ext.gpid') || deepAccess(bid, 'ortb2Imp.ext.data.pbadslot'); if (gpid) { placement.gpid = gpid; } if (bid.userId) { getUserId(placement.eids, bid.userId.idl_env, 'identityLink'); getUserId(placement.eids, bid.userId.id5id, 'id5-sync.com'); getUserId(placement.eids, bid.userId.uid2 && bid.userId.uid2.id, 'uidapi.com'); getUserId(placement.eids, bid.userId.tdid, 'adserver.org', { rtiPartner: 'TDID' }); } if (mediaTypes && mediaTypes[BANNER]) { placement.traffic = BANNER; placement.sizes = mediaTypes[BANNER].sizes; } else if (mediaTypes && mediaTypes[VIDEO]) { placement.traffic = VIDEO; placement.sizes = mediaTypes[VIDEO].playerSize; placement.playerSize = mediaTypes[VIDEO].playerSize; placement.minduration = mediaTypes[VIDEO].minduration; placement.maxduration = mediaTypes[VIDEO].maxduration; placement.mimes = mediaTypes[VIDEO].mimes; placement.protocols = mediaTypes[VIDEO].protocols; placement.startdelay = mediaTypes[VIDEO].startdelay; placement.placement = mediaTypes[VIDEO].plcmt; placement.skip = mediaTypes[VIDEO].skip; placement.skipafter = mediaTypes[VIDEO].skipafter; placement.minbitrate = mediaTypes[VIDEO].minbitrate; placement.maxbitrate = mediaTypes[VIDEO].maxbitrate; placement.delivery = mediaTypes[VIDEO].delivery; placement.playbackmethod = mediaTypes[VIDEO].playbackmethod; placement.api = mediaTypes[VIDEO].api; placement.linearity = mediaTypes[VIDEO].linearity; } else if (mediaTypes && mediaTypes[NATIVE]) { placement.traffic = NATIVE; placement.native = mediaTypes[NATIVE]; } if (typeof bid.getFloor === 'function') { let tmpFloor = {}; for (let size of placement.sizes) { tmpFloor = bid.getFloor({ currency: 'USD', mediaType: placement.traffic, size: size }); if (tmpFloor) { placement.floor[`${size[0]}x${size[1]}`] = tmpFloor.floor; } } } placements.push(placement); } return { method: 'POST', url: G_URL, data: request }; }, /** * Unpack the response from the server into a list of bids. * * @param {*} serverResponse A successful response from the server. * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: (serverResponse) => { let response = []; try { serverResponse = serverResponse.body; for (let i = 0; i < serverResponse.length; i++) { let resItem = serverResponse[i]; if (isBidResponseValid(resItem)) { const advertiserDomains = resItem.adomain && resItem.adomain.length ? resItem.adomain : []; resItem.meta = { ...resItem.meta, advertiserDomains }; response.push(resItem); } } } catch (e) { logMessage(e); }; return response; }, getUserSyncs: (syncOptions, serverResponses, gdprConsent, uspConsent) => { let syncType = syncOptions.iframeEnabled ? 'iframe' : 'image'; let syncUrl = G_URL_SYNC + `/${syncType}?pbjs=1`; if (gdprConsent && gdprConsent.consentString) { if (typeof gdprConsent.gdprApplies === 'boolean') { syncUrl += `&gdpr=${Number(gdprConsent.gdprApplies)}&gdpr_consent=${gdprConsent.consentString}`; } else { syncUrl += `&gdpr=0&gdpr_consent=${gdprConsent.consentString}`; } } if (uspConsent && uspConsent.consentString) { syncUrl += `&ccpa_consent=${uspConsent.consentString}`; } const coppa = config.getConfig('coppa') ? 1 : 0; syncUrl += `&coppa=${coppa}`; return [{ type: syncType, url: syncUrl }]; }, onBidWon: (bid) => { if (bid.nurl) { ajax(bid.nurl, null); } } }; registerBidder(spec);