From 57fc9bbffde0a348855011b9115082d0d31acbeb Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 5 Aug 2021 16:23:38 +0300 Subject: [PATCH 1/8] added Brave bidder adapter with test and docs Commit has standard bidder adapter 2 new files adapter js, adapter md --- modules/braveBidAdapter.js | 267 +++++++++++++++++++++++++++++++++++++ modules/braveBidAdapter.md | 135 +++++++++++++++++++ 2 files changed, 402 insertions(+) create mode 100644 modules/braveBidAdapter.js create mode 100644 modules/braveBidAdapter.md diff --git a/modules/braveBidAdapter.js b/modules/braveBidAdapter.js new file mode 100644 index 00000000000..7ea3eb9cd9b --- /dev/null +++ b/modules/braveBidAdapter.js @@ -0,0 +1,267 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'brave'; +const DEFAULT_CUR = 'USD'; +const ENDPOINT_URL = `https://point.bravegroup.tv/?t=2&partner=hash`; + +const NATIVE_ASSETS_IDS = { 1: 'title', 2: 'icon', 3: 'image', 4: 'body', 5: 'sponsoredBy', 6: 'cta' }; +const NATIVE_ASSETS = { + title: { id: 1, name: 'title' }, + icon: { id: 2, type: 1, name: 'img' }, + image: { id: 3, type: 3, name: 'img' }, + body: { id: 4, type: 2, name: 'data' }, + sponsoredBy: { id: 5, type: 1, name: 'data' }, + cta: { id: 6, type: 12, name: 'data' } +}; + +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) => { + return !!(bid.params.placementId && bid.params.placementId.toString().length === 32); + }, + + /** + * 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) => { + if (validBidRequests.length === 0 || !bidderRequest) return []; + + const endpointURL = ENDPOINT_URL.replace('hash', validBidRequests[0].params.placementId); + + let imp = validBidRequests.map(br => { + let impObject = { + id: br.bidId, + secure: 1 + }; + + if (br.mediaTypes.banner) { + impObject.banner = createBannerRequest(br); + } else if (br.mediaTypes.video) { + impObject.video = createVideoRequest(br); + } else if (br.mediaTypes.native) { + impObject.native = { + id: br.transactionId, + ver: '1.2', + request: createNativeRequest(br) + }; + } + return impObject; + }); + + let w = window; + let l = w.document.location.href; + let r = w.document.referrer; + + let loopChecker = 0; + while (w !== w.parent) { + if (++loopChecker == 10) break; + try { + w = w.parent; + l = w.location.href; + r = w.document.referrer; + } catch (e) { + break; + } + } + + let page = l || bidderRequest.refererInfo.referer; + + let data = { + id: bidderRequest.bidderRequestId, + cur: [ DEFAULT_CUR ], + device: { + w: screen.width, + h: screen.height, + language: (navigator && navigator.language) ? navigator.language.indexOf('-') != -1 ? navigator.language.split('-')[0] : navigator.language : '', + ua: navigator.userAgent, + }, + site: { + domain: utils.parseUrl(page).hostname, + page: page, + }, + tmax: bidderRequest.timeout || config.getConfig('bidderTimeout') || 500, + imp + }; + + if (r) { + data.site.ref = r; + } + + if (bidderRequest.gdprConsent) { + data['regs'] = {'ext': {'gdpr': bidderRequest.gdprConsent.gdprApplies ? 1 : 0}}; + data['user'] = {'ext': {'consent': bidderRequest.gdprConsent.consentString ? bidderRequest.gdprConsent.consentString : ''}}; + } + + if (bidderRequest.uspConsent !== undefined) { + if (!data['regs'])data['regs'] = {'ext': {}}; + data['regs']['ext']['us_privacy'] = bidderRequest.uspConsent; + } + + if (config.getConfig('coppa') === true) { + if (!data['regs'])data['regs'] = {'coppa': 1}; + else data['regs']['coppa'] = 1; + } + + if (validBidRequests[0].schain) { + data['source'] = {'ext': {'schain': validBidRequests[0].schain}}; + } + + return { + method: 'POST', + url: endpointURL, + data: data + }; + }, + + /** + * 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) => { + if (!serverResponse || utils.isEmpty(serverResponse.body)) return []; + + let bids = []; + serverResponse.body.seatbid.forEach(response => { + response.bid.forEach(bid => { + let mediaType = bid.ext && bid.ext.mediaType ? bid.ext.mediaType : 'banner'; + + let bidObj = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + ttl: 1200, + currency: DEFAULT_CUR, + netRevenue: true, + creativeId: bid.crid, + dealId: bid.dealid || null, + mediaType: mediaType + }; + + switch (mediaType) { + case 'video': + bidObj.vastUrl = bid.adm; + break; + case 'native': + bidObj.native = parseNative(bid.adm); + break; + default: + bidObj.ad = bid.adm; + } + + bids.push(bidObj); + }); + }); + + return bids; + }, + + onBidWon: (bid) => { + if (utils.isStr(bid.nurl) && bid.nurl !== '') { + utils.triggerPixel(bid.nurl); + } + } +}; + +const parseNative = adm => { + let bid = { + clickUrl: adm.native.link && adm.native.link.url, + impressionTrackers: adm.native.imptrackers || [], + clickTrackers: (adm.native.link && adm.native.link.clicktrackers) || [], + jstracker: adm.native.jstracker || [] + }; + adm.native.assets.forEach(asset => { + let kind = NATIVE_ASSETS_IDS[asset.id]; + let content = kind && asset[NATIVE_ASSETS[kind].name]; + if (content) { + bid[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h }; + } + }); + + return bid; +} + +const createNativeRequest = br => { + let impObject = { + ver: '1.2', + assets: [] + }; + + let keys = Object.keys(br.mediaTypes.native); + + for (let key of keys) { + const props = NATIVE_ASSETS[key]; + if (props) { + const asset = { + required: br.mediaTypes.native[key].required ? 1 : 0, + id: props.id, + [props.name]: {} + }; + + if (props.type) asset[props.name]['type'] = props.type; + if (br.mediaTypes.native[key].len) asset[props.name]['len'] = br.mediaTypes.native[key].len; + if (br.mediaTypes.native[key].sizes && br.mediaTypes.native[key].sizes[0]) { + asset[props.name]['w'] = br.mediaTypes.native[key].sizes[0]; + asset[props.name]['h'] = br.mediaTypes.native[key].sizes[1]; + } + + impObject.assets.push(asset); + } + } + + return impObject; +} + +const createBannerRequest = br => { + let size = []; + + if (br.mediaTypes.banner.sizes && Array.isArray(br.mediaTypes.banner.sizes)) { + if (Array.isArray(br.mediaTypes.banner.sizes[0])) { size = br.mediaTypes.banner.sizes[0]; } else { size = br.mediaTypes.banner.sizes; } + } else size = [300, 250]; + + return { id: br.transactionId, w: size[0], h: size[1] }; +}; + +const createVideoRequest = br => { + let videoObj = {id: br.transactionId}; + let supportParamsList = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'skip', 'minbitrate', 'maxbitrate', 'api', 'linearity']; + + for (let param of supportParamsList) { + if (br.mediaTypes.video[param] !== undefined) { + videoObj[param] = br.mediaTypes.video[param]; + } + } + + if (br.mediaTypes.video.playerSize && Array.isArray(br.mediaTypes.video.playerSize)) { + if (Array.isArray(br.mediaTypes.video.playerSize[0])) { + videoObj.w = br.mediaTypes.video.playerSize[0][0]; + videoObj.h = br.mediaTypes.video.playerSize[0][1]; + } else { + videoObj.w = br.mediaTypes.video.playerSize[0]; + videoObj.h = br.mediaTypes.video.playerSize[1]; + } + } else { + videoObj.w = 640; + videoObj.h = 480; + } + + return videoObj; +} + +registerBidder(spec); diff --git a/modules/braveBidAdapter.md b/modules/braveBidAdapter.md new file mode 100644 index 00000000000..77d2338ff16 --- /dev/null +++ b/modules/braveBidAdapter.md @@ -0,0 +1,135 @@ +# Overview + +``` +Module Name: Brave Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support@thebrave.io +``` + +# Description + +Module which connects to Brave SSP demand sources + +# Test Parameters + + +250x300 banner test +``` +var adUnits = [{ + code: 'brave-prebid', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'brave', + params : { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +native test +``` +var adUnits = [{ + code: 'brave-native-prebid', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + len: 80 + }, + sponsoredBy: { + required: true + }, + clickUrl: { + required: true + }, + privacyLink: { + required: false + }, + body: { + required: true + }, + icon: { + required: true, + sizes: [50, 50] + } + } + }, + bids: [{ + bidder: 'brave', + params: { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +video test +``` +var adUnits = [{ + code: 'brave-video-prebid', + mediaTypes: { + video: { + minduration:1, + maxduration:999, + boxingallowed:1, + skip:0, + mimes:[ + 'application/javascript', + 'video/mp4' + ], + playerSize: [[768, 1024]], + protocols:[ + 2,3 + ], + linearity:1, + api:[ + 1, + 2 + ] + } + }, + bids: [{ + bidder: 'brave', + params: { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +# Bid Parameters +## Banner + +| Name | Scope | Type | Description | Example +| ---- | ----- | ---- | ----------- | ------- +| `placementId` | required | String | The placement ID from Brave | "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" + + +# Ad Unit and page Setup: + +```html + + + +``` From 60ac8ba9508049763c0d7e41aa88e859007f5ac2 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 5 Aug 2021 16:24:49 +0300 Subject: [PATCH 2/8] added test spec file witch covered code least 80 % --- test/spec/modules/braveBidAdapter_spec.js | 363 ++++++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 test/spec/modules/braveBidAdapter_spec.js diff --git a/test/spec/modules/braveBidAdapter_spec.js b/test/spec/modules/braveBidAdapter_spec.js new file mode 100644 index 00000000000..392f3b9f263 --- /dev/null +++ b/test/spec/modules/braveBidAdapter_spec.js @@ -0,0 +1,363 @@ +import { expect } from 'chai'; +import { spec } from 'modules/braveBidAdapter.js'; + +const request_native = { + code: 'brave-native-prebid', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + len: 80 + }, + sponsoredBy: { + required: true + }, + clickUrl: { + required: true + }, + privacyLink: { + required: false + }, + body: { + required: true + }, + icon: { + required: true, + sizes: [50, 50] + } + } + }, + bidder: 'brave', + params: { + placementId: 'to0QI2aPgkbBZq6vgf0oHitouZduz0qw' + } +}; + +const request_banner = { + code: 'brave-prebid', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bidder: 'brave', + params: { + placementId: 'to0QI2aPgkbBZq6vgf0oHitouZduz0qw' + } +} + +const bidRequest = { + gdprConsent: { + consentString: 'HFIDUYFIUYIUYWIPOI87392DSU', + gdprApplies: true + }, + uspConsent: 'uspConsentString', + bidderRequestId: 'testid', + refererInfo: { + referer: 'testdomain.com' + }, + timeout: 700 +} + +const request_video = { + code: 'brave-video-prebid', + mediaTypes: { video: { + minduration: 1, + maxduration: 999, + boxingallowed: 1, + skip: 0, + mimes: [ + 'application/javascript', + 'video/mp4' + ], + playerSize: [[768, 1024]], + protocols: [ + 2, 3 + ], + linearity: 1, + api: [ + 1, + 2 + ] + } + }, + + bidder: 'brave', + params: { + placementId: 'to0QI2aPgkbBZq6vgf0oHitouZduz0qw' + } + +} + +const response_banner = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: 'admcode', + crid: 'crid', + ext: { + mediaType: 'banner' + } + }] + }] +}; + +const response_video = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: 'admcode', + crid: 'crid', + ext: { + mediaType: 'video' + } + }], + }], +}; + +let imgData = { + url: `https://example.com/image`, + w: 1200, + h: 627 +}; + +const response_native = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: { native: + { + assets: [ + {id: 1, title: 'dummyText'}, + {id: 3, image: imgData}, + { + id: 5, + data: {value: 'organization.name'} + } + ], + link: {url: 'example.com'}, + imptrackers: ['tracker1.com', 'tracker2.com', 'tracker3.com'], + jstracker: 'tracker1.com' + } + }, + crid: 'crid', + ext: { + mediaType: 'native' + } + }], + }], +}; + +describe('BraveBidAdapter', function() { + describe('isBidRequestValid', function() { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(request_banner)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, request_banner); + bid.params = { + 'IncorrectParam': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('build Native Request', function () { + const request = spec.buildRequests([request_native], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.bravegroup.tv/?t=2&partner=to0QI2aPgkbBZq6vgf0oHitouZduz0qw'); + }); + + it('Returns empty data if no valid requests are passed', function () { + let serverRequest = spec.buildRequests([]); + expect(serverRequest).to.be.an('array').that.is.empty; + }); + }); + + describe('build Banner Request', function () { + const request = spec.buildRequests([request_banner], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.bravegroup.tv/?t=2&partner=to0QI2aPgkbBZq6vgf0oHitouZduz0qw'); + }); + }); + + describe('build Video Request', function () { + const request = spec.buildRequests([request_video], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.bravegroup.tv/?t=2&partner=to0QI2aPgkbBZq6vgf0oHitouZduz0qw'); + }); + }); + + describe('interpretResponse', function () { + it('Empty response must return empty array', function() { + const emptyResponse = null; + let response = spec.interpretResponse(emptyResponse); + + expect(response).to.be.an('array').that.is.empty; + }) + + it('Should interpret banner response', function () { + const bannerResponse = { + body: response_banner + } + + const expectedBidResponse = { + requestId: response_banner.seatbid[0].bid[0].impid, + cpm: response_banner.seatbid[0].bid[0].price, + width: response_banner.seatbid[0].bid[0].w, + height: response_banner.seatbid[0].bid[0].h, + ttl: response_banner.ttl || 1200, + currency: response_banner.cur || 'USD', + netRevenue: true, + creativeId: response_banner.seatbid[0].bid[0].crid, + dealId: response_banner.seatbid[0].bid[0].dealid, + mediaType: 'banner', + ad: response_banner.seatbid[0].bid[0].adm + } + + let bannerResponses = spec.interpretResponse(bannerResponse); + + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.ad).to.equal(expectedBidResponse.ad); + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + + it('Should interpret video response', function () { + const videoResponse = { + body: response_video + } + + const expectedBidResponse = { + requestId: response_video.seatbid[0].bid[0].impid, + cpm: response_video.seatbid[0].bid[0].price, + width: response_video.seatbid[0].bid[0].w, + height: response_video.seatbid[0].bid[0].h, + ttl: response_video.ttl || 1200, + currency: response_video.cur || 'USD', + netRevenue: true, + creativeId: response_video.seatbid[0].bid[0].crid, + dealId: response_video.seatbid[0].bid[0].dealid, + mediaType: 'video', + vastUrl: response_video.seatbid[0].bid[0].adm + } + + let videoResponses = spec.interpretResponse(videoResponse); + + expect(videoResponses).to.be.an('array').that.is.not.empty; + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.vastUrl).to.equal(expectedBidResponse.vastUrl) + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + + it('Should interpret native response', function () { + const nativeResponse = { + body: response_native + } + + const expectedBidResponse = { + requestId: response_native.seatbid[0].bid[0].impid, + cpm: response_native.seatbid[0].bid[0].price, + width: response_native.seatbid[0].bid[0].w, + height: response_native.seatbid[0].bid[0].h, + ttl: response_native.ttl || 1200, + currency: response_native.cur || 'USD', + netRevenue: true, + creativeId: response_native.seatbid[0].bid[0].crid, + dealId: response_native.seatbid[0].bid[0].dealid, + mediaType: 'native', + native: {clickUrl: response_native.seatbid[0].bid[0].adm.native.link.url} + } + + let nativeResponses = spec.interpretResponse(nativeResponse); + + expect(nativeResponses).to.be.an('array').that.is.not.empty; + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'native', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.native.clickUrl).to.equal(expectedBidResponse.native.clickUrl) + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + }); +}) From 2f68f67b9db0180e9f09f827a4c5aa1211c44a6a Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:42:51 +0300 Subject: [PATCH 3/8] adding videoHeroes bidder adapter --- modules/videoheroesBidAdapter.js | 267 +++++++++++++++++++++++++++++++ modules/videoheroesBidAdapter.md | 134 ++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100644 modules/videoheroesBidAdapter.js create mode 100644 modules/videoheroesBidAdapter.md diff --git a/modules/videoheroesBidAdapter.js b/modules/videoheroesBidAdapter.js new file mode 100644 index 00000000000..769f354294e --- /dev/null +++ b/modules/videoheroesBidAdapter.js @@ -0,0 +1,267 @@ +import * as utils from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; +import { config } from '../src/config.js'; + +const BIDDER_CODE = 'videoheroes'; +const DEFAULT_CUR = 'USD'; +const ENDPOINT_URL = `https://point.contextualadv.com/?t=2&partner=hash`; + +const NATIVE_ASSETS_IDS = { 1: 'title', 2: 'icon', 3: 'image', 4: 'body', 5: 'sponsoredBy', 6: 'cta' }; +const NATIVE_ASSETS = { + title: { id: 1, name: 'title' }, + icon: { id: 2, type: 1, name: 'img' }, + image: { id: 3, type: 3, name: 'img' }, + body: { id: 4, type: 2, name: 'data' }, + sponsoredBy: { id: 5, type: 1, name: 'data' }, + cta: { id: 6, type: 12, name: 'data' } +}; + +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) => { + return !!(bid.params.placementId && bid.params.placementId.toString().length === 32); + }, + + /** + * 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) => { + if (validBidRequests.length === 0 || !bidderRequest) return []; + + const endpointURL = ENDPOINT_URL.replace('hash', validBidRequests[0].params.placementId); + + let imp = validBidRequests.map(br => { + let impObject = { + id: br.bidId, + secure: 1 + }; + + if (br.mediaTypes.banner) { + impObject.banner = createBannerRequest(br); + } else if (br.mediaTypes.video) { + impObject.video = createVideoRequest(br); + } else if (br.mediaTypes.native) { + impObject.native = { + id: br.transactionId, + ver: '1.2', + request: createNativeRequest(br) + }; + } + return impObject; + }); + + let w = window; + let l = w.document.location.href; + let r = w.document.referrer; + + let loopChecker = 0; + while (w !== w.parent) { + if (++loopChecker == 10) break; + try { + w = w.parent; + l = w.location.href; + r = w.document.referrer; + } catch (e) { + break; + } + } + + let page = l || bidderRequest.refererInfo.referer; + + let data = { + id: bidderRequest.bidderRequestId, + cur: [ DEFAULT_CUR ], + device: { + w: screen.width, + h: screen.height, + language: (navigator && navigator.language) ? navigator.language.indexOf('-') != -1 ? navigator.language.split('-')[0] : navigator.language : '', + ua: navigator.userAgent, + }, + site: { + domain: utils.parseUrl(page).hostname, + page: page, + }, + tmax: bidderRequest.timeout || config.getConfig('bidderTimeout') || 500, + imp + }; + + if (r) { + data.site.ref = r; + } + + if (bidderRequest.gdprConsent) { + data['regs'] = {'ext': {'gdpr': bidderRequest.gdprConsent.gdprApplies ? 1 : 0}}; + data['user'] = {'ext': {'consent': bidderRequest.gdprConsent.consentString ? bidderRequest.gdprConsent.consentString : ''}}; + } + + if (bidderRequest.uspConsent !== undefined) { + if (!data['regs'])data['regs'] = {'ext': {}}; + data['regs']['ext']['us_privacy'] = bidderRequest.uspConsent; + } + + if (config.getConfig('coppa') === true) { + if (!data['regs'])data['regs'] = {'coppa': 1}; + else data['regs']['coppa'] = 1; + } + + if (validBidRequests[0].schain) { + data['source'] = {'ext': {'schain': validBidRequests[0].schain}}; + } + + return { + method: 'POST', + url: endpointURL, + data: data + }; + }, + + /** + * 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) => { + if (!serverResponse || utils.isEmpty(serverResponse.body)) return []; + + let bids = []; + serverResponse.body.seatbid.forEach(response => { + response.bid.forEach(bid => { + let mediaType = bid.ext && bid.ext.mediaType ? bid.ext.mediaType : 'banner'; + + let bidObj = { + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + ttl: 1200, + currency: DEFAULT_CUR, + netRevenue: true, + creativeId: bid.crid, + dealId: bid.dealid || null, + mediaType: mediaType + }; + + switch (mediaType) { + case 'video': + bidObj.vastUrl = bid.adm; + break; + case 'native': + bidObj.native = parseNative(bid.adm); + break; + default: + bidObj.ad = bid.adm; + } + + bids.push(bidObj); + }); + }); + + return bids; + }, + + onBidWon: (bid) => { + if (utils.isStr(bid.nurl) && bid.nurl !== '') { + utils.triggerPixel(bid.nurl); + } + } +}; + +const parseNative = adm => { + let bid = { + clickUrl: adm.native.link && adm.native.link.url, + impressionTrackers: adm.native.imptrackers || [], + clickTrackers: (adm.native.link && adm.native.link.clicktrackers) || [], + jstracker: adm.native.jstracker || [] + }; + adm.native.assets.forEach(asset => { + let kind = NATIVE_ASSETS_IDS[asset.id]; + let content = kind && asset[NATIVE_ASSETS[kind].name]; + if (content) { + bid[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h }; + } + }); + + return bid; +} + +const createNativeRequest = br => { + let impObject = { + ver: '1.2', + assets: [] + }; + + let keys = Object.keys(br.mediaTypes.native); + + for (let key of keys) { + const props = NATIVE_ASSETS[key]; + if (props) { + const asset = { + required: br.mediaTypes.native[key].required ? 1 : 0, + id: props.id, + [props.name]: {} + }; + + if (props.type) asset[props.name]['type'] = props.type; + if (br.mediaTypes.native[key].len) asset[props.name]['len'] = br.mediaTypes.native[key].len; + if (br.mediaTypes.native[key].sizes && br.mediaTypes.native[key].sizes[0]) { + asset[props.name]['w'] = br.mediaTypes.native[key].sizes[0]; + asset[props.name]['h'] = br.mediaTypes.native[key].sizes[1]; + } + + impObject.assets.push(asset); + } + } + + return impObject; +} + +const createBannerRequest = br => { + let size = []; + + if (br.mediaTypes.banner.sizes && Array.isArray(br.mediaTypes.banner.sizes)) { + if (Array.isArray(br.mediaTypes.banner.sizes[0])) { size = br.mediaTypes.banner.sizes[0]; } else { size = br.mediaTypes.banner.sizes; } + } else size = [300, 250]; + + return { id: br.transactionId, w: size[0], h: size[1] }; +}; + +const createVideoRequest = br => { + let videoObj = {id: br.transactionId}; + let supportParamsList = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'skip', 'minbitrate', 'maxbitrate', 'api', 'linearity']; + + for (let param of supportParamsList) { + if (br.mediaTypes.video[param] !== undefined) { + videoObj[param] = br.mediaTypes.video[param]; + } + } + + if (br.mediaTypes.video.playerSize && Array.isArray(br.mediaTypes.video.playerSize)) { + if (Array.isArray(br.mediaTypes.video.playerSize[0])) { + videoObj.w = br.mediaTypes.video.playerSize[0][0]; + videoObj.h = br.mediaTypes.video.playerSize[0][1]; + } else { + videoObj.w = br.mediaTypes.video.playerSize[0]; + videoObj.h = br.mediaTypes.video.playerSize[1]; + } + } else { + videoObj.w = 640; + videoObj.h = 480; + } + + return videoObj; +} + +registerBidder(spec); diff --git a/modules/videoheroesBidAdapter.md b/modules/videoheroesBidAdapter.md new file mode 100644 index 00000000000..2848f1462cd --- /dev/null +++ b/modules/videoheroesBidAdapter.md @@ -0,0 +1,134 @@ +# Overview + +``` +Module Name: Video Heroes Bidder Adapter +Module Type: Bidder Adapter +Maintainer: support@videoheroes.tv +``` + +# Description + +Module which connects to VideoHeroes SSP demand sources + +# Test Parameters + +250x300 banner test +``` +var adUnits = [{ + code: 'videoheroes-prebid', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bids: [{ + bidder: 'videoheroes', + params : { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +native test +``` +var adUnits = [{ + code: 'videoheroes-native-prebid', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + len: 80 + }, + sponsoredBy: { + required: true + }, + clickUrl: { + required: true + }, + privacyLink: { + required: false + }, + body: { + required: true + }, + icon: { + required: true, + sizes: [50, 50] + } + } + }, + bids: [{ + bidder: 'videoheroes', + params: { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +video test +``` +var adUnits = [{ + code: 'videoheroes-video-prebid', + mediaTypes: { + video: { + minduration:1, + maxduration:999, + boxingallowed:1, + skip:0, + mimes:[ + 'application/javascript', + 'video/mp4' + ], + playerSize: [[768, 1024]], + protocols:[ + 2,3 + ], + linearity:1, + api:[ + 1, + 2 + ] + } + }, + bids: [{ + bidder: 'videoheroes', + params: { + placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + } + }] +}]; +``` + +# Bid Parameters +## Banner + +| Name | Scope | Type | Description | Example +| ---- | ----- | ---- | ----------- | ------- +| `placementId` | required | String | The placement ID from Video Heroes | "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" + + +# Ad Unit and page Setup: + +```html + + + +``` From 532844dfdd9605206b1a84dd993697a30c2cc944 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 21 Apr 2022 15:49:27 +0300 Subject: [PATCH 4/8] added videoHeroes test spec --- .../modules/videoheroesBidAdapter_spec.js | 363 ++++++++++++++++++ 1 file changed, 363 insertions(+) create mode 100644 test/spec/modules/videoheroesBidAdapter_spec.js diff --git a/test/spec/modules/videoheroesBidAdapter_spec.js b/test/spec/modules/videoheroesBidAdapter_spec.js new file mode 100644 index 00000000000..8f99ca4d17d --- /dev/null +++ b/test/spec/modules/videoheroesBidAdapter_spec.js @@ -0,0 +1,363 @@ +import { expect } from 'chai'; +import { spec } from 'modules/videoheroesBidAdapter.js'; + +const request_native = { + code: 'videoheroes-native-prebid', + mediaTypes: { + native: { + title: { + required: true, + len: 800 + }, + image: { + required: true, + len: 80 + }, + sponsoredBy: { + required: true + }, + clickUrl: { + required: true + }, + privacyLink: { + required: false + }, + body: { + required: true + }, + icon: { + required: true, + sizes: [50, 50] + } + } + }, + bidder: 'videoheroes', + params: { + placementId: '1a8d9c22db19906cb8a5fd4518d05f62' + } +}; + +const request_banner = { + code: 'videoheroes-prebid', + mediaTypes: { + banner: { + sizes: [[300, 250]] + } + }, + bidder: 'videoheroes', + params: { + placementId: '1a8d9c22db19906cb8a5fd4518d05f62' + } +} + +const bidRequest = { + gdprConsent: { + consentString: 'HFIDUYFIUYIUYWIPOI87392DSU', + gdprApplies: true + }, + uspConsent: 'uspConsentString', + bidderRequestId: 'testid', + refererInfo: { + referer: 'testdomain.com' + }, + timeout: 700 +} + +const request_video = { + code: 'videoheroes-video-prebid', + mediaTypes: { video: { + minduration: 1, + maxduration: 999, + boxingallowed: 1, + skip: 0, + mimes: [ + 'application/javascript', + 'video/mp4' + ], + playerSize: [[768, 1024]], + protocols: [ + 2, 3 + ], + linearity: 1, + api: [ + 1, + 2 + ] + } + }, + + bidder: 'videoheroes', + params: { + placementId: '1a8d9c22db19906cb8a5fd4518d05f62' + } + +} + +const response_banner = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: 'admcode', + crid: 'crid', + ext: { + mediaType: 'banner' + } + }] + }] +}; + +const response_video = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: 'admcode', + crid: 'crid', + ext: { + mediaType: 'video' + } + }], + }], +}; + +let imgData = { + url: `https://example.com/image`, + w: 1200, + h: 627 +}; + +const response_native = { + id: 'request_id', + bidid: 'request_imp_id', + seatbid: [{ + bid: [{ + id: 'bid_id', + impid: 'request_imp_id', + price: 5, + adomain: ['example.com'], + adm: { native: + { + assets: [ + {id: 1, title: 'dummyText'}, + {id: 3, image: imgData}, + { + id: 5, + data: {value: 'organization.name'} + } + ], + link: {url: 'example.com'}, + imptrackers: ['tracker1.com', 'tracker2.com', 'tracker3.com'], + jstracker: 'tracker1.com' + } + }, + crid: 'crid', + ext: { + mediaType: 'native' + } + }], + }], +}; + +describe('VideoheroesBidAdapter', function() { + describe('isBidRequestValid', function() { + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(request_banner)).to.equal(true); + }); + + it('should return false when required params are not passed', function () { + let bid = Object.assign({}, request_banner); + bid.params = { + 'IncorrectParam': 0 + }; + expect(spec.isBidRequestValid(bid)).to.equal(false); + }); + }); + + describe('build Native Request', function () { + const request = spec.buildRequests([request_native], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.contextualadv.com/?t=2&partner=1a8d9c22db19906cb8a5fd4518d05f62'); + }); + + it('Returns empty data if no valid requests are passed', function () { + let serverRequest = spec.buildRequests([]); + expect(serverRequest).to.be.an('array').that.is.empty; + }); + }); + + describe('build Banner Request', function () { + const request = spec.buildRequests([request_banner], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.contextualadv.com/?t=2&partner=1a8d9c22db19906cb8a5fd4518d05f62'); + }); + }); + + describe('build Video Request', function () { + const request = spec.buildRequests([request_video], bidRequest); + + it('Creates a ServerRequest object with method, URL and data', function () { + expect(request).to.exist; + expect(request.method).to.exist; + expect(request.url).to.exist; + expect(request.data).to.exist; + }); + + it('sends bid request to our endpoint via POST', function () { + expect(request.method).to.equal('POST'); + }); + + it('Returns valid URL', function () { + expect(request.url).to.equal('https://point.contextualadv.com/?t=2&partner=1a8d9c22db19906cb8a5fd4518d05f62'); + }); + }); + + describe('interpretResponse', function () { + it('Empty response must return empty array', function() { + const emptyResponse = null; + let response = spec.interpretResponse(emptyResponse); + + expect(response).to.be.an('array').that.is.empty; + }) + + it('Should interpret banner response', function () { + const bannerResponse = { + body: response_banner + } + + const expectedBidResponse = { + requestId: response_banner.seatbid[0].bid[0].impid, + cpm: response_banner.seatbid[0].bid[0].price, + width: response_banner.seatbid[0].bid[0].w, + height: response_banner.seatbid[0].bid[0].h, + ttl: response_banner.ttl || 1200, + currency: response_banner.cur || 'USD', + netRevenue: true, + creativeId: response_banner.seatbid[0].bid[0].crid, + dealId: response_banner.seatbid[0].bid[0].dealid, + mediaType: 'banner', + ad: response_banner.seatbid[0].bid[0].adm + } + + let bannerResponses = spec.interpretResponse(bannerResponse); + + expect(bannerResponses).to.be.an('array').that.is.not.empty; + let dataItem = bannerResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'ad', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.ad).to.equal(expectedBidResponse.ad); + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + + it('Should interpret video response', function () { + const videoResponse = { + body: response_video + } + + const expectedBidResponse = { + requestId: response_video.seatbid[0].bid[0].impid, + cpm: response_video.seatbid[0].bid[0].price, + width: response_video.seatbid[0].bid[0].w, + height: response_video.seatbid[0].bid[0].h, + ttl: response_video.ttl || 1200, + currency: response_video.cur || 'USD', + netRevenue: true, + creativeId: response_video.seatbid[0].bid[0].crid, + dealId: response_video.seatbid[0].bid[0].dealid, + mediaType: 'video', + vastUrl: response_video.seatbid[0].bid[0].adm + } + + let videoResponses = spec.interpretResponse(videoResponse); + + expect(videoResponses).to.be.an('array').that.is.not.empty; + let dataItem = videoResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'vastUrl', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.vastUrl).to.equal(expectedBidResponse.vastUrl) + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + + it('Should interpret native response', function () { + const nativeResponse = { + body: response_native + } + + const expectedBidResponse = { + requestId: response_native.seatbid[0].bid[0].impid, + cpm: response_native.seatbid[0].bid[0].price, + width: response_native.seatbid[0].bid[0].w, + height: response_native.seatbid[0].bid[0].h, + ttl: response_native.ttl || 1200, + currency: response_native.cur || 'USD', + netRevenue: true, + creativeId: response_native.seatbid[0].bid[0].crid, + dealId: response_native.seatbid[0].bid[0].dealid, + mediaType: 'native', + native: {clickUrl: response_native.seatbid[0].bid[0].adm.native.link.url} + } + + let nativeResponses = spec.interpretResponse(nativeResponse); + + expect(nativeResponses).to.be.an('array').that.is.not.empty; + let dataItem = nativeResponses[0]; + expect(dataItem).to.have.all.keys('requestId', 'cpm', 'width', 'height', 'native', 'ttl', 'creativeId', + 'netRevenue', 'currency', 'dealId', 'mediaType'); + expect(dataItem.requestId).to.equal(expectedBidResponse.requestId); + expect(dataItem.cpm).to.equal(expectedBidResponse.cpm); + expect(dataItem.native.clickUrl).to.equal(expectedBidResponse.native.clickUrl) + expect(dataItem.ttl).to.equal(expectedBidResponse.ttl); + expect(dataItem.creativeId).to.equal(expectedBidResponse.creativeId); + expect(dataItem.netRevenue).to.be.true; + expect(dataItem.currency).to.equal(expectedBidResponse.currency); + expect(dataItem.width).to.equal(expectedBidResponse.width); + expect(dataItem.height).to.equal(expectedBidResponse.height); + }); + }); +}) From 7641e7ab99ea47cce2321c7a34fc1f872d4a2123 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 21 Apr 2022 22:43:02 +0300 Subject: [PATCH 5/8] Update braveBidAdapter.js --- modules/braveBidAdapter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/braveBidAdapter.js b/modules/braveBidAdapter.js index d616772cb5b..18bad6b0f75 100644 --- a/modules/braveBidAdapter.js +++ b/modules/braveBidAdapter.js @@ -173,7 +173,6 @@ export const spec = { }, onBidWon: (bid) => { - if (isStr(bid.nurl) && bid.nurl !== '') { triggerPixel(bid.nurl); } From 3ec4a440815cf962ee668284e9b1b16de4b6e006 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 21 Apr 2022 22:58:50 +0300 Subject: [PATCH 6/8] Update braveBidAdapter.js From 128679424a7d08e289a756ab54b00ffc2f76e916 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Thu, 21 Apr 2022 23:32:53 +0300 Subject: [PATCH 7/8] Update videoheroesBidAdapter.md --- modules/videoheroesBidAdapter.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/videoheroesBidAdapter.md b/modules/videoheroesBidAdapter.md index 2848f1462cd..f2a2ca9f7ba 100644 --- a/modules/videoheroesBidAdapter.md +++ b/modules/videoheroesBidAdapter.md @@ -24,7 +24,7 @@ var adUnits = [{ bids: [{ bidder: 'videoheroes', params : { - placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + placementId : "1a8d9c22db19906cb8a5fd4518d05f62" // test placementId, please replace after test } }] }]; @@ -65,7 +65,7 @@ var adUnits = [{ bids: [{ bidder: 'videoheroes', params: { - placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + placementId : "1a8d9c22db19906cb8a5fd4518d05f62" // test placementId, please replace after test } }] }]; @@ -99,7 +99,7 @@ var adUnits = [{ bids: [{ bidder: 'videoheroes', params: { - placementId : "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" // test placementId, please replace after test + placementId : "1a8d9c22db19906cb8a5fd4518d05f62" // test placementId, please replace after test } }] }]; @@ -110,7 +110,7 @@ var adUnits = [{ | Name | Scope | Type | Description | Example | ---- | ----- | ---- | ----------- | ------- -| `placementId` | required | String | The placement ID from Video Heroes | "to0QI2aPgkbBZq6vgf0oHitouZduz0qw" +| `placementId` | required | String | The placement ID from Video Heroes | "1a8d9c22db19906cb8a5fd4518d05f62" # Ad Unit and page Setup: From 584bf432e93eab5e115f11fb318b2921dbe65f37 Mon Sep 17 00:00:00 2001 From: Sacha <35510349+thebraveio@users.noreply.github.com> Date: Sun, 15 May 2022 21:52:06 +0300 Subject: [PATCH 8/8] upd import of utils lib to load only certain fnc --- modules/videoheroesBidAdapter.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/videoheroesBidAdapter.js b/modules/videoheroesBidAdapter.js index 769f354294e..edcdd698153 100644 --- a/modules/videoheroesBidAdapter.js +++ b/modules/videoheroesBidAdapter.js @@ -1,4 +1,4 @@ -import * as utils from '../src/utils.js'; +import { isEmpty, parseUrl, isStr, triggerPixel } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import { config } from '../src/config.js'; @@ -90,7 +90,7 @@ export const spec = { ua: navigator.userAgent, }, site: { - domain: utils.parseUrl(page).hostname, + domain: parseUrl(page).hostname, page: page, }, tmax: bidderRequest.timeout || config.getConfig('bidderTimeout') || 500, @@ -134,7 +134,7 @@ export const spec = { * @return {Bid[]} An array of bids which were nested inside the server. */ interpretResponse: (serverResponse) => { - if (!serverResponse || utils.isEmpty(serverResponse.body)) return []; + if (!serverResponse || isEmpty(serverResponse.body)) return []; let bids = []; serverResponse.body.seatbid.forEach(response => { @@ -173,8 +173,8 @@ export const spec = { }, onBidWon: (bid) => { - if (utils.isStr(bid.nurl) && bid.nurl !== '') { - utils.triggerPixel(bid.nurl); + if (isStr(bid.nurl) && bid.nurl !== '') { + triggerPixel(bid.nurl); } } };