From ab55073d787279fab845a695b085c3285f10c62d Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 22 Nov 2024 17:53:43 -0300 Subject: [PATCH 01/20] add blue --- modules/blueBidAdapter.js | 300 ++++++++++++++++++++++++++++++++++++++ modules/blueBidAdapter.md | 27 ++++ 2 files changed, 327 insertions(+) create mode 100644 modules/blueBidAdapter.js create mode 100644 modules/blueBidAdapter.md diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js new file mode 100644 index 00000000000..0d7a606b60f --- /dev/null +++ b/modules/blueBidAdapter.js @@ -0,0 +1,300 @@ +import { deepAccess, deepSetValue, logError } from '../src/utils.js'; +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER } from '../src/mediaTypes.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; +import { ortb25Translator } from '../libraries/ortb2.5Translator/translator.js'; + +/** + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid + * @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest + * @typedef {import('../src/adapters/bidderFactory.js').BidderSpec} BidderSpec + * @typedef {import('../src/adapters/bidderFactory.js').TimedOutBid} TimedOutBid + */ + +const BIDDER_CODE = 'blue'; +const GVLID = 620; +const CDB_ENDPOINT = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid'; + +export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); +const TRANSLATOR = ortb25Translator(); + +/** + * Defines the generic oRTB converter and all customization functions. + */ +const CONVERTER = ortbConverter({ + context: { + netRevenue: true, + ttl: 60, + }, + imp, + request, + bidResponse, + response, +}); + +/** + * Builds an impression object for the ORTB 2.5 request. + * + * @param {function} buildImp - The function for building an imp object. + * @param {Object} bidRequest - The bid request object. + * @param {Object} context - The context object. + * @returns {Object} The ORTB 2.5 imp object. + */ +function imp(buildImp, bidRequest, context) { + let imp = buildImp(bidRequest, context); + const params = bidRequest.params; + + imp.tagid = bidRequest.adUnitCode; + deepSetValue(imp, 'ext', { + ...bidRequest.params.ext, + ...imp.ext, + rwdd: imp.rwdd, + floors: getFloors(bidRequest), + bidder: { + publishersubid: params?.publisherSubId, + zoneid: params?.zoneId, + uid: params?.uid, + }, + }); + + delete imp.rwdd; // oRTB 2.6 field moved to ext + + return imp; +} + +/** + * Builds a request object for the ORTB 2.5 request. + * + * @param {function} buildRequest - The function for building a request object. + * @param {Array} imps - An array of ORTB 2.5 impression objects. + * @param {Object} bidderRequest - The bidder request object. + * @param {Object} context - The context object. + * @returns {Object} The ORTB 2.5 request object. + */ +function request(buildRequest, imps, bidderRequest, context) { + let request = buildRequest(imps, bidderRequest, context); + + // params.pubid should override publisher id + if (typeof context.publisherId !== 'undefined') { + if (typeof request.app !== 'undefined') { + deepSetValue(request, 'app.publisher.id', context.publisherId); + } else { + deepSetValue(request, 'site.publisher.id', context.publisherId); + } + } + + if (bidderRequest && bidderRequest.gdprConsent) { + deepSetValue( + request, + 'regs.ext.gdprversion', + bidderRequest.gdprConsent.apiVersion + ); + } + + // Translate 2.6 OpenRTB request into 2.5 OpenRTB request + request = TRANSLATOR(request); + + return request; +} + +/** + * Build bid from oRTB 2.5 bid. + * + * @param buildBidResponse + * @param bid + * @param context + * @returns {*} + */ +function bidResponse(buildBidResponse, bid, context) { + context.mediaType = deepAccess(bid, 'ext.mediatype'); + let bidResponse = buildBidResponse(bid, context); + + bidResponse.currency = deepAccess(bid, 'ext.cur'); + + if (typeof deepAccess(bid, 'ext.meta') !== 'undefined') { + deepSetValue(bidResponse, 'meta', { + ...bidResponse.meta, + ...bid.ext.meta, + }); + } + if (typeof deepAccess(bid, 'ext.paf.content_id') !== 'undefined') { + deepSetValue(bidResponse, 'meta.paf.content_id', bid.ext.paf.content_id); + } + + return bidResponse; +} + +/** + * Builds bid response from the oRTB 2.5 bid response. + * + * @param buildResponse + * @param bidResponses + * @param ortbResponse + * @param context + * @returns * + */ +function response(buildResponse, bidResponses, ortbResponse, context) { + let response = buildResponse(bidResponses, ortbResponse, context); + + const pafTransmission = deepAccess(ortbResponse, 'ext.paf.transmission'); + response.bids.forEach((bid) => { + if ( + typeof pafTransmission !== 'undefined' && + typeof deepAccess(bid, 'meta.paf.content_id') !== 'undefined' + ) { + deepSetValue(bid, 'meta.paf.transmission', pafTransmission); + } else { + delete bid.meta.paf; + } + }); + + return response; +} + +/** @type {BidderSpec} */ +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER], + + /** + * f + * @param {object} bid + * @return {boolean} + */ + isBidRequestValid: (bid) => { + // either one of zoneId or networkId should be set + if (!(bid && bid.params && bid.params.publisherId)) { + return false; + } + + return true; + }, + + /** + * @param {BidRequest[]} bidRequests + * @param {*} bidderRequest + * @return {ServerRequest} + */ + buildRequests: (bidRequests, bidderRequest) => { + const context = buildContext(bidRequests, bidderRequest); + const url = buildCdbUrl(context); + const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); + + if (data) { + return { method: 'POST', url, data, bidRequests }; + } + }, + + /** + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} + */ + interpretResponse: (response, request) => { + if (typeof response?.body == 'undefined') { + return []; // no bid + } + + const interpretedResponse = CONVERTER.fromORTB({ + response: response.body, + request: request.data, + }); + const bids = interpretedResponse.bids || []; + + return bids; + }, +}; + +/** + * @param {BidRequest[]} bidRequests + * @param bidderRequest + */ +function buildContext(bidRequests, bidderRequest) { + return { + url: bidderRequest?.refererInfo?.page || '', + publisherId: bidRequests.find((bidRequest) => bidRequest.params?.pubid) + ?.params.pubid, + }; +} + +/** + * @param {Object} context + * @return {string} + */ +function buildCdbUrl(context) { + let url = CDB_ENDPOINT; + url += '&wv=' + encodeURIComponent('$prebid.version$'); + url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); + + if (context.publisherId) { + url += `&publisherId=` + context.publisherId; + } + + return url; +} + +function parseSizes(sizes, parser = (s) => s) { + if (sizes == undefined) { + return []; + } + if (Array.isArray(sizes[0])) { + // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map((size) => parser(size)); + } + return [parser(sizes)]; // or a single one ? (ie. [728,90]) +} + +function parseSize(size) { + return size[0] + 'x' + size[1]; +} + +function pickAvailableGetFloorFunc(bidRequest) { + if (bidRequest.getFloor) { + return bidRequest.getFloor; + } + if (bidRequest.params.bidFloor && bidRequest.params.bidFloorCur) { + try { + const floor = parseFloat(bidRequest.params.bidFloor); + return () => { + return { + currency: bidRequest.params.bidFloorCur, + floor: floor, + }; + }; + } catch {} + } + return undefined; +} + +function getFloors(bidRequest) { + try { + const floors = {}; + + const getFloor = pickAvailableGetFloorFunc(bidRequest); + + if (getFloor) { + if (bidRequest.mediaTypes?.banner) { + floors.banner = {}; + const bannerSizes = parseSizes( + deepAccess(bidRequest, 'mediaTypes.banner.sizes') + ); + bannerSizes.forEach( + (bannerSize) => + (floors.banner[parseSize(bannerSize).toString()] = getFloor.call( + bidRequest, + { size: bannerSize, mediaType: BANNER } + )) + ); + } + + return floors; + } + } catch (e) { + logError('Could not parse floors from Prebid: ' + e); + } +} + +registerBidder(spec); diff --git a/modules/blueBidAdapter.md b/modules/blueBidAdapter.md new file mode 100644 index 00000000000..91edde8556a --- /dev/null +++ b/modules/blueBidAdapter.md @@ -0,0 +1,27 @@ +# Overview + +Module Name: Blue Bidder Adapter +Module Type: Bidder Adapter +Maintainer: celsooliveira@getblue.io + +# Description + +Module that connects to Blue's demand sources. + +# Test Parameters +``` + var adUnits = [ + { + code: 'banner-ad-div', + sizes: [[300, 250], [728, 90]], + bids: [ + { + bidder: 'blue', + params: { + zoneId: 497747 + } + } + ] + } + ]; +``` From fb57fb14d42eceebfd330221b0032bc9f8c039ef Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Wed, 27 Nov 2024 14:48:24 -0300 Subject: [PATCH 02/20] uncommited stuff --- integrationExamples/gpt/hello_world.html | 4 +- modules/blueBidAdapter.js | 12 +- test/spec/modules/blueBidAdapter_spec.js | 1253 ++++++++++++++++++++++ 3 files changed, 1266 insertions(+), 3 deletions(-) create mode 100755 test/spec/modules/blueBidAdapter_spec.js diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 03a2356f0ef..cb9bb70ed33 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -26,9 +26,9 @@ // Replace this object to test a new Adapter! bids: [{ - bidder: 'appnexus', + bidder: 'blue', params: { - placementId: 13144370 + publisherId: 13144370 } }] diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 0d7a606b60f..ca43a9eb9fc 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -16,6 +16,7 @@ import { ortb25Translator } from '../libraries/ortb2.5Translator/translator.js'; const BIDDER_CODE = 'blue'; const GVLID = 620; const CDB_ENDPOINT = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid'; +const BUNDLE_COOKIE_NAME = 'ckid'; export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); const TRANSLATOR = ortb25Translator(); @@ -180,9 +181,19 @@ export const spec = { */ buildRequests: (bidRequests, bidderRequest) => { const context = buildContext(bidRequests, bidderRequest); + const blueId = storage.cookiesAreEnabled() && storage.getCookie(BUNDLE_COOKIE_NAME); const url = buildCdbUrl(context); const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); + // put user id in the request + if (data.user == undefined) { + data.user = {}; + } + if (data.user.ext == undefined) { + data.user.ext = { + buyerid: blueId + }; + } if (data) { return { method: 'POST', url, data, bidRequests }; } @@ -268,7 +279,6 @@ function pickAvailableGetFloorFunc(bidRequest) { } return undefined; } - function getFloors(bidRequest) { try { const floors = {}; diff --git a/test/spec/modules/blueBidAdapter_spec.js b/test/spec/modules/blueBidAdapter_spec.js new file mode 100755 index 00000000000..b3b2dd0a438 --- /dev/null +++ b/test/spec/modules/blueBidAdapter_spec.js @@ -0,0 +1,1253 @@ +import { expect } from 'chai'; +import { + spec, + storage, +} from 'modules/blueBidAdapter.js'; +import * as utils from 'src/utils.js'; +import * as refererDetection from 'src/refererDetection.js'; +import * as ajax from 'src/ajax.js'; +import { config } from '../../../src/config.js'; +import { BANNER, NATIVE, VIDEO } from '../../../src/mediaTypes.js'; +import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; +import 'modules/userId/index.js'; +import 'modules/consentManagementTcf.js'; +import 'modules/consentManagementUsp.js'; +import 'modules/consentManagementGpp.js'; +import 'modules/schain.js'; +import {hook} from '../../../src/hook.js'; + +describe('The Blue bidding adapter', function () { + let utilsMock, sandbox, ajaxStub; + + beforeEach(function () { + $$PREBID_GLOBAL$$.bidderSettings = { + blue: { + storageAllowed: true + } + }; + // Remove FastBid to avoid side effects + localStorage.removeItem('blue_fast_bid'); + utilsMock = sinon.mock(utils); + + sandbox = sinon.sandbox.create(); + ajaxStub = sandbox.stub(ajax, 'ajax'); + }); + + afterEach(function () { + $$PREBID_GLOBAL$$.bidderSettings = {}; + global.Blue = undefined; + utilsMock.restore(); + sandbox.restore(); + ajaxStub.restore(); + }); + + describe('isBidRequestValid', function () { + it('should return false when given an invalid bid', function () { + const bid = { + bidder: 'blue', + }; + const isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equal(false); + }); + + it('should return true when given a zoneId bid', function () { + const bid = { + bidder: 'blue', + params: { + publisherId: 123, + }, + }; + const isValid = spec.isBidRequestValid(bid); + expect(isValid).to.equal(true); + }); + }); + + describe('buildRequests', function () { + const refererUrl = 'https://blue.com?pbt_debug=1&pbt_nolog=1'; + const bidderRequest = { + refererInfo: { + page: refererUrl, + topmostLocation: refererUrl + }, + timeout: 3000, + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: { + vendorConsents: { + '91': 1 + }, + }, + apiVersion: 1, + }, + }; + + let localStorageIsEnabledStub; + + before(() => { + hook.ready(); + }); + + this.beforeEach(function () { + localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); + localStorageIsEnabledStub.returns(true); + }); + + afterEach(function () { + localStorageIsEnabledStub.restore(); + config.resetConfig(); + }); + + it('should properly build a request using random uuid as auction id', function () { + const generateUUIDStub = sinon.stub(utils, 'generateUUID'); + generateUUIDStub.returns('def'); + const bidderRequest = {}; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.id).to.equal('def'); + generateUUIDStub.restore(); + }); + + it('should properly transmit source.tid if available', function () { + const bidderRequest = { + ortb2: { + source: { + tid: 'abc' + } + } + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.source.tid).to.equal('abc'); + }); + + it('should properly transmit tmax if available', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + transactionId: 'transaction-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.tmax).to.equal(bidderRequest.timeout); + }); + + it('should properly transmit bidId if available', function () { + const bidderRequest = {}; + const bidRequests = [ + { + bidId: 'bidId', + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.imp[0].id).to.equal('bidId'); + }); + + it('should properly forward eids', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: {} + }, + ]; + const br = { + ...bidderRequest, + ortb2: { + user: { + ext: { + eids: [ + { + source: 'blue.com', + uids: [{ + id: 'abc', + atype: 1 + }] + } + ] + } + } + } + } + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(br)); + const ortbRequest = request.data; + expect(ortbRequest.user.ext.eids).to.deep.equal([ + { + source: 'blue.com', + uids: [{ + id: 'abc', + atype: 1 + }] + } + ]); + }); + + it('should properly build a publisherId request', function () { + const bidderRequest = { + refererInfo: { + page: refererUrl, + topmostLocation: refererUrl, + }, + timeout: 3000, + gdprConsent: { + gdprApplies: false, + consentString: undefined, + vendorData: { + vendorConsents: { + '1': 0 + }, + }, + }, + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + ortb2Imp: { + ext: { + tid: 'transaction-123', + }, + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + }, + }, + ]; + + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + expect(request.url).to.contain('https://bidder-us-east-1.getblue.io/engine/?src=prebid'); + expect(request.method).to.equal('POST'); + const ortbRequest = request.data; + expect(ortbRequest.site.page).to.equal(refererUrl); + expect(ortbRequest.imp).to.have.lengthOf(1); + expect(ortbRequest.imp[0].tagid).to.equal('bid-123'); + expect(ortbRequest.imp[0].banner.format).to.have.lengthOf(2); + expect(ortbRequest.imp[0].banner.format[0].w).to.equal(300); + expect(ortbRequest.imp[0].banner.format[0].h).to.equal(250); + expect(ortbRequest.imp[0].banner.format[1].w).to.equal(728); + expect(ortbRequest.imp[0].banner.format[1].h).to.equal(90); + expect(ortbRequest.user?.ext?.consent).to.equal(undefined); + expect(ortbRequest.regs.ext.gdpr).to.equal(0); + }); + + it('should properly build a request with undefined gdpr consent fields when they are not provided', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + timeout: 3000, + gdprConsent: {}, + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.user?.ext?.consent).to.equal(undefined); + expect(ortbRequest.regs?.ext?.gdpr).to.equal(undefined); + }); + + it('should properly build a request with ccpa consent field', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + timeout: 3000, + uspConsent: '1YNY', + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.regs.ext.us_privacy).to.equal('1YNY'); + }); + + it('should properly build a request with overridden tmax', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + timeout: 1234 + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.tmax).to.equal(1234); + }); + + it('should properly build a request with device sua field', function () { + const sua = { + platform: { + brand: 'abc' + } + } + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + timeout: 3000, + uspConsent: '1YNY', + ortb2: { + device: { + sua: sua + } + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.device.ext.sua).not.to.be.null; + expect(ortbRequest.device.ext.sua.platform.brand).to.equal('abc'); + }); + + it('should properly build a request with gpp consent field', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const ortb2 = { + regs: { + gpp: 'gpp_consent_string', + gpp_sid: [0, 1, 2], + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; + expect(ortbRequest.regs.ext.gpp).to.equal('gpp_consent_string'); + expect(ortbRequest.regs.ext.gpp_sid).to.deep.equal([0, 1, 2]); + }); + + it('should properly build a request with dsa object', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + let dsa = { + required: 3, + pubrender: 0, + datatopub: 2, + transparency: [{ + domain: 'platform1domain.com', + params: [1] + }, { + domain: 'SSP2domain.com', + params: [1, 2] + }] + }; + const ortb2 = { + regs: { + ext: { + dsa: dsa + } + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; + expect(ortbRequest.regs.ext.dsa).to.deep.equal(dsa); + }); + + it('should properly build a request with schain object', function () { + const expectedSchain = { + someProperty: 'someValue' + }; + const bidRequests = [ + { + bidder: 'blue', + schain: expectedSchain, + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.source.ext.schain).to.equal(expectedSchain); + }); + + it('should properly build a request with bcat field', function () { + const bcat = ['IAB1', 'IAB2']; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + ortb2: { + bcat + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.bcat).to.deep.equal(bcat); + }); + + it('should properly build a request with badv field', function () { + const badv = ['ford.com']; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + ortb2: { + badv + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.badv).to.deep.equal(badv); + }); + + it('should properly build a request with bapp field', function () { + const bapp = ['com.foo.mygame']; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + ]; + const bidderRequest = { + ortb2: { + bapp + } + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.bapp).to.deep.equal(bapp); + }); + + it('should properly build a request without first party data', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123 + } + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2: {} })).data; + expect(ortbRequest.site.page).to.equal(refererUrl); + expect(ortbRequest.imp).to.have.lengthOf(1); + expect(ortbRequest.imp[0].tagid).to.equal('bid-123'); + expect(ortbRequest.imp[0].banner.format).to.have.lengthOf(1); + expect(ortbRequest.imp[0].banner.format[0].w).to.equal(728); + expect(ortbRequest.imp[0].banner.format[0].h).to.equal(90); + expect(ortbRequest.imp[0].ext.bidder.zoneid).to.equal(123); + expect(ortbRequest.user.ext.consent).to.equal('consentDataString'); + expect(ortbRequest.regs.ext.gdpr).to.equal(1); + expect(ortbRequest.regs.ext.gdprversion).to.equal(1); + }); + + it('should properly build a request with first party data', function () { + const siteData = { + keywords: ['power tools'], + content: { + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }] + }, + ext: { + data: { + pageType: 'article' + } + } + }; + const userData = { + gender: 'M', + data: [{ + name: 'some_provider', + ext: { + segtax: 3 + }, + segment: [ + { 'id': '1001' }, + { 'id': '1002' } + ] + }], + ext: { + data: { + registered: true + } + } + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + ext: { + bidfloor: 0.75 + } + }, + ortb2Imp: { + ext: { + data: { + someContextAttribute: 'abc' + } + } + } + }, + ]; + + const ortb2 = { + site: siteData, + user: userData + }; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; + expect(ortbRequest.user).to.deep.equal({ ...userData, ext: { ...userData.ext, consent: 'consentDataString' } }); + expect(ortbRequest.site).to.deep.equal({ ...siteData, page: refererUrl, domain: 'blue.com', publisher: { ...ortbRequest.site.publisher, domain: 'blue.com' } }); + expect(ortbRequest.imp[0].ext.bidfloor).to.equal(0.75); + expect(ortbRequest.imp[0].ext.data.someContextAttribute).to.equal('abc') + }); + + it('should properly build a request when coppa flag is true', function () { + const bidRequests = []; + const bidderRequest = {}; + config.setConfig({ coppa: true }); + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.regs.coppa).to.equal(1); + }); + + it('should properly build a request when coppa flag is false', function () { + const bidRequests = []; + const bidderRequest = {}; + config.setConfig({ coppa: false }); + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.regs.coppa).to.equal(0); + }); + + it('should properly build a request when coppa flag is not defined', function () { + const bidRequests = []; + const bidderRequest = {}; + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.regs?.coppa).to.be.undefined; + }); + + it('should properly build a banner request with floors', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + }, + + getFloor: inputParams => { + if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { + return { + currency: 'USD', + floor: 1.0 + }; + } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { + return { + currency: 'USD', + floor: 2.0 + }; + } else { + return {} + } + } + }, + ]; + const bidderRequest = {}; + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext.floors).to.deep.equal({ + 'banner': { + '300x250': { 'currency': 'USD', 'floor': 1 }, + '728x90': { 'currency': 'USD', 'floor': 2 } + } + }); + }); + + it('should properly build a request with static floors', function () { + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + bidFloor: 1, + bidFloorCur: 'EUR' + }, + }, + ]; + const bidderRequest = {}; + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext.floors).to.deep.equal({ + 'banner': { + '300x250': { 'currency': 'EUR', 'floor': 1 }, + '728x90': { 'currency': 'EUR', 'floor': 1 } + } + }); + }); + + it('should properly build a request when imp.rwdd is present', function () { + const bidderRequest = {}; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123 + }, + ortb2Imp: { + rwdd: 1 + } + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext.rwdd).to.equal(1); + }); + + it('should properly build a request when imp.rwdd is false', function () { + const bidderRequest = {}; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123 + }, + ortb2Imp: { + rwdd: 0 + } + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext?.rwdd).to.equal(0); + }); + + it('should properly build a request when FLEDGE is enabled', function () { + const bidderRequest = { + paapi: { + enabled: true + } + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123 + }, + ortb2Imp: { + ext: { + igs: { + ae: 1 + } + } + } + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext.igs.ae).to.equal(1); + }); + + it('should properly build a request when FLEDGE is disabled', function () { + const bidderRequest = { + paapi: { + enabled: false + }, + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123 + }, + ortb2Imp: { + ext: { + igs: { + ae: 1 + } + } + } + }, + ]; + + const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; + expect(ortbRequest.imp[0].ext.igs?.ae).to.be.undefined; + }); + + it('should properly transmit the pubid and slot uid if available', function () { + const bidderRequest = { + ortb2: { + site: { + publisher: { + id: 'pub-777' + } + } + } + }; + const bidRequests = [ + { + bidder: 'blue', + adUnitCode: 'bid-123', + ortb2Imp: { + ext: { + tid: 'transaction-123', + }, + }, + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + zoneId: 123, + }, + }, + { + bidder: 'blue', + adUnitCode: 'bid-234', + ortb2Imp: { + ext: { + tid: 'transaction-234', + }, + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]] + } + }, + params: { + networkId: 456, + pubid: 'pub-888', + uid: 888 + }, + }, + ]; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.site.publisher.id).to.equal('pub-888'); + expect(ortbRequest.imp[0].ext.bidder.uid).to.be.undefined; + expect(ortbRequest.imp[1].ext.bidder.uid).to.equal(888); + }); + + it('should properly transmit device.ext.cdep if available', function () { + const bidderRequest = { + ortb2: { + device: { + ext: { + cdep: 'cookieDeprecationLabel' + } + } + } + }; + const bidRequests = []; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const ortbRequest = request.data; + expect(ortbRequest.device.ext.cdep).to.equal('cookieDeprecationLabel'); + }); + }); + + describe('interpretResponse', function () { + const refererUrl = 'https://blue.com?pbt_debug=1&pbt_nolog=1'; + const bidderRequest = { + refererInfo: { + page: refererUrl, + topmostLocation: refererUrl + }, + timeout: 3000, + gdprConsent: { + gdprApplies: true, + consentString: 'consentDataString', + vendorData: { + vendorConsents: { + '91': 1 + }, + }, + apiVersion: 1, + }, + }; + + function mockResponse(winningBidId, mediaType) { + return { + id: 'test-requestId', + seatbid: [ + { + seat: 'blue', + bid: [ + { + id: 'test-bidderId', + impid: winningBidId, + price: 1.23, + adomain: ['blue.com'], + bundle: '', + iurl: 'http://some_image/', + cid: '123456', + crid: 'test-crId', + dealid: 'deal-code', + w: 728, + h: 90, + adm: 'test-ad', + adm_native: mediaType === NATIVE ? { + ver: '1.2', + assets: [ + { + id: 10, + title: { + text: 'Some product' + } + }, + { + id: 11, + img: { + type: 3, + url: 'https://main_image_url.com', + w: 400, + h: 400 + } + }, + { + id: 12, + data: { + value: 'Some product' + } + }, + { + id: 13, + data: { + value: '1,499 TL' + } + }, + { + id: 15, + data: { + value: 'CTA' + }, + link: { + url: 'https://cta_url.com' + } + }, + { + id: 17, + img: { + type: 1, + url: 'https://main_image_url.com', + w: 200, + h: 200 + }, + link: { + url: 'https://icon_image_url.com' + } + }, + { + id: 16, + data: { + value: 'Some brand' + } + } + ], + eventtrackers: [ + { + event: 1, + method: 1, + url: 'https://eventtrackers.com' + }, + { + event: 1, + method: 1, + url: 'https://test_in_isolation.blue.com/tpd?dd=HTlW9l9xTEZqRHVlSHFiSWx5Q2VQMlEwSTJhNCUyQkxNazQ1Y29LR3ZmS2VTSDFsUGdkRHNoWjQ2UWp0SGtVZ1RTbHI0TFRpTlVqNWxiUkZOeGVFNjVraW53R0loRVJQNDJOY2R1eWxVdjBBQ1BEdVFvTyUyRlg3aWJaeUFha3UyemNNVGpmJTJCS1prc0FwRjZRJTJCQ2dpaFBJeVhZRmQlMkZURVZocUFRdm03OTdFZHZSbURNZWt4Uzh2M1NSUUxmTmhaTnNnRXd4VkZlOTdJOXdnNGZjaVolMkZWYmdYVjJJMkQ0eGxQaFIwQmVtWk1sQ09tNXlGY0Nwc09GTDladzExJTJGVExGNXJsdGpneERDeTMlMkJuNUlUcEU4NDFLMTZPc2ZoWFUwMmpGbDFpVjBPZUVtTlEwaWNOeHRyRFYyenRKd0lpJTJGTTElMkY1WGZ3Smo3aTh0bUJzdzZRdlZUSXppanNkamo3ekZNZjhKdjl2VDJ5eHV1YnVzdmdRdk5iWnprNXVFMVdmbGs0QU1QY0ozZQ' + } + ], + privacy: 'https://cta_url.com', + ext: { + privacy: { + imageurl: 'https://icon_image_url.com', + clickurl: 'https://cta_url.com', + longlegaltext: '' + } + } + } : undefined, + ext: { + mediatype: mediaType, + displayurl: mediaType === VIDEO ? 'http://test-ad' : undefined, + dsa: { + adrender: 1 + }, + meta: { + networkName: 'Blue' + }, + videoPlayerType: mediaType === VIDEO ? 'RadiantMediaPlayer' : undefined, + videoPlayerConfig: mediaType === VIDEO ? {} : undefined, + cur: 'CUR' + } + } + ] + } + ] + }; + } + + it('should return an empty array when parsing an empty bid response', function () { + const bidRequests = []; + const response = {}; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const bids = spec.interpretResponse(response, request); + expect(bids).to.have.lengthOf(0); + }); + + it('should return an empty array when parsing a well-formed no bid response', function () { + const bidRequests = []; + const response = { seatbid: [] }; + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const bids = spec.interpretResponse({ body: response }, request); + expect(bids).to.have.lengthOf(0); + }); + + it('should properly parse a banner bid response', function () { + const bidRequests = [{ + adUnitCode: 'test-requestId', + bidId: 'test-bidId', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + networkId: 456, + } + }]; + const response = mockResponse('test-bidId', BANNER); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const bids = spec.interpretResponse({ body: response }, request); + expect(bids).to.have.lengthOf(1); + expect(bids[0].mediaType).to.equal(BANNER); + expect(bids[0].requestId).to.equal('test-bidId'); + expect(bids[0].seatBidId).to.equal('test-bidderId') + expect(bids[0].cpm).to.equal(1.23); + expect(bids[0].currency).to.equal('CUR'); + expect(bids[0].width).to.equal(728); + expect(bids[0].height).to.equal(90); + expect(bids[0].ad).to.equal('test-ad'); + expect(bids[0].creativeId).to.equal('test-crId'); + expect(bids[0].dealId).to.equal('deal-code'); + expect(bids[0].meta.advertiserDomains[0]).to.equal('blue.com'); + expect(bids[0].meta.networkName).to.equal('Blue'); + expect(bids[0].meta.dsa.adrender).to.equal(1); + }); + + it('should properly parse a bid response when banner win with twin ad units', function () { + const bidRequests = [{ + adUnitCode: 'test-requestId', + bidId: 'test-bidId', + mediaTypes: { + video: { + context: 'instream', + mimes: ['video/mpeg'], + playerSize: [640, 480], + protocols: [5, 6], + maxduration: 30, + api: [1, 2] + } + }, + params: { + networkId: 456, + }, + }, { + adUnitCode: 'test-requestId', + bidId: 'test-bidId2', + mediaTypes: { + banner: { + sizes: [[728, 90]] + } + }, + params: { + networkId: 456, + } + }]; + const response = mockResponse('test-bidId2', BANNER); + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const bids = spec.interpretResponse({ body: response }, request); + expect(bids).to.have.lengthOf(1); + expect(bids[0].mediaType).to.equal(BANNER); + expect(bids[0].requestId).to.equal('test-bidId2'); + expect(bids[0].seatBidId).to.equal('test-bidderId') + expect(bids[0].cpm).to.equal(1.23); + expect(bids[0].currency).to.equal('CUR'); + expect(bids[0].width).to.equal(728); + expect(bids[0].height).to.equal(90); + expect(bids[0].ad).to.equal('test-ad'); + expect(bids[0].creativeId).to.equal('test-crId'); + expect(bids[0].dealId).to.equal('deal-code'); + expect(bids[0].meta.advertiserDomains[0]).to.equal('blue.com'); + expect(bids[0].meta.networkName).to.equal('Blue'); + expect(bids[0].meta.dsa.adrender).to.equal(1); + }); + + [{ + hasBidResponseLevelPafData: true, + hasBidResponseBidLevelPafData: true, + shouldContainsBidMetaPafData: true + }, + { + hasBidResponseLevelPafData: false, + hasBidResponseBidLevelPafData: true, + shouldContainsBidMetaPafData: false + }, + { + hasBidResponseLevelPafData: true, + hasBidResponseBidLevelPafData: false, + shouldContainsBidMetaPafData: false + }, + { + hasBidResponseLevelPafData: false, + hasBidResponseBidLevelPafData: false, + shouldContainsBidMetaPafData: false + }].forEach(testCase => + it('should properly forward or not meta paf data', () => { + const bidPafContentId = 'abcdef'; + const pafTransmission = { + version: '12' + }; + const bidRequests = [{ + bidId: 'test-bidId', + adUnitCode: 'adUnitId', + sizes: [[300, 250]], + params: { + networkId: 456, + } + }]; + const response = { + id: 'test-requestId', + seatbid: [{ + seat: 'blue', + bid: [ + { + id: 'test-bidderId', + impid: 'test-bidId', + w: 728, + h: 90, + ext: { + mediatype: BANNER, + paf: testCase.hasBidResponseBidLevelPafData ? { + content_id: bidPafContentId + } : undefined + } + } + ] + }], + ext: (testCase.hasBidResponseLevelPafData ? { + paf: { + transmission: pafTransmission + } + } : undefined) + }; + + const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); + const bids = spec.interpretResponse({ body: response }, request); + + expect(bids).to.have.lengthOf(1); + + const expectedBidMetaPafData = { + paf: { + content_id: bidPafContentId, + transmission: pafTransmission + } + }; + + if (testCase.shouldContainsBidMetaPafData) { + expect(bids[0].meta).to.deep.equal(expectedBidMetaPafData); + } else { + expect(bids[0].meta).not.to.deep.equal(expectedBidMetaPafData); + } + }) + ) + }); +}); From d69a4c2ddbc320ccf02f7be0b1625c90352e303b Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Wed, 27 Nov 2024 14:51:59 -0300 Subject: [PATCH 03/20] uncommited stuff --- integrationExamples/gpt/hello_world.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index cb9bb70ed33..03a2356f0ef 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -26,9 +26,9 @@ // Replace this object to test a new Adapter! bids: [{ - bidder: 'blue', + bidder: 'appnexus', params: { - publisherId: 13144370 + placementId: 13144370 } }] From e29efa1e169e2c176a97693b6db140fe3e7c258a Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Wed, 27 Nov 2024 14:53:59 -0300 Subject: [PATCH 04/20] uncommited stuff --- modules/blueBidAdapter.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/blueBidAdapter.md b/modules/blueBidAdapter.md index 91edde8556a..80c05019d52 100644 --- a/modules/blueBidAdapter.md +++ b/modules/blueBidAdapter.md @@ -18,7 +18,7 @@ Module that connects to Blue's demand sources. { bidder: 'blue', params: { - zoneId: 497747 + publisherId: "xpto" } } ] From 5c18e1b954b426b43adf94641399ec8ebeff72f5 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Thu, 5 Dec 2024 14:31:01 -0300 Subject: [PATCH 05/20] less duplicated code --- modules/blueBidAdapter.js | 116 +++++++++++++++----------------------- 1 file changed, 47 insertions(+), 69 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index ca43a9eb9fc..529979214f0 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -180,9 +180,21 @@ export const spec = { * @return {ServerRequest} */ buildRequests: (bidRequests, bidderRequest) => { - const context = buildContext(bidRequests, bidderRequest); - const blueId = storage.cookiesAreEnabled() && storage.getCookie(BUNDLE_COOKIE_NAME); - const url = buildCdbUrl(context); + const context = { + url: bidderRequest?.refererInfo?.page || '', + publisherId: bidRequests.find((bidRequest) => bidRequest.params?.pubid) + ?.params.pubid, + }; + const blueId = + storage.cookiesAreEnabled() && storage.getCookie(BUNDLE_COOKIE_NAME); + let url = CDB_ENDPOINT; + url += '&wv=' + encodeURIComponent('$prebid.version$'); + url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); + + if (context.publisherId) { + url += `&publisherId=` + context.publisherId; + } + const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); // put user id in the request if (data.user == undefined) { @@ -191,7 +203,7 @@ export const spec = { if (data.user.ext == undefined) { data.user.ext = { - buyerid: blueId + buyerid: blueId, }; } if (data) { @@ -219,81 +231,47 @@ export const spec = { }, }; -/** - * @param {BidRequest[]} bidRequests - * @param bidderRequest - */ -function buildContext(bidRequests, bidderRequest) { - return { - url: bidderRequest?.refererInfo?.page || '', - publisherId: bidRequests.find((bidRequest) => bidRequest.params?.pubid) - ?.params.pubid, - }; -} - -/** - * @param {Object} context - * @return {string} - */ -function buildCdbUrl(context) { - let url = CDB_ENDPOINT; - url += '&wv=' + encodeURIComponent('$prebid.version$'); - url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); - - if (context.publisherId) { - url += `&publisherId=` + context.publisherId; - } - - return url; -} - -function parseSizes(sizes, parser = (s) => s) { - if (sizes == undefined) { - return []; - } - if (Array.isArray(sizes[0])) { - // is there several sizes ? (ie. [[728,90],[200,300]]) - return sizes.map((size) => parser(size)); - } - return [parser(sizes)]; // or a single one ? (ie. [728,90]) -} - -function parseSize(size) { - return size[0] + 'x' + size[1]; -} - -function pickAvailableGetFloorFunc(bidRequest) { - if (bidRequest.getFloor) { - return bidRequest.getFloor; - } - if (bidRequest.params.bidFloor && bidRequest.params.bidFloorCur) { - try { - const floor = parseFloat(bidRequest.params.bidFloor); - return () => { - return { - currency: bidRequest.params.bidFloorCur, - floor: floor, - }; - }; - } catch {} - } - return undefined; -} function getFloors(bidRequest) { try { const floors = {}; - const getFloor = pickAvailableGetFloorFunc(bidRequest); + let getFloor; + + if (bidRequest.getFloor) { + getFloor = bidRequest.getFloor; + } + if (bidRequest.params.bidFloor && bidRequest.params.bidFloorCur) { + try { + const floor = parseFloat(bidRequest.params.bidFloor); + return () => { + getFloor = { + currency: bidRequest.params.bidFloorCur, + floor: floor, + }; + }; + } catch {} + } + getFloor = undefined; if (getFloor) { if (bidRequest.mediaTypes?.banner) { floors.banner = {}; - const bannerSizes = parseSizes( - deepAccess(bidRequest, 'mediaTypes.banner.sizes') - ); + + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); + const parser = (s) => s; + + if (sizes == undefined) { + return []; + } + if (Array.isArray(sizes[0])) { + // is there several sizes ? (ie. [[728,90],[200,300]]) + return sizes.map((size) => parser(size)); + } + const bannerSizes = [parser(sizes)]; // or a single one ? (ie. [728,90]) + bannerSizes.forEach( (bannerSize) => - (floors.banner[parseSize(bannerSize).toString()] = getFloor.call( + (floors.banner[(bannerSize[0] + 'x' + bannerSize[1]).toString()] = getFloor.call( bidRequest, { size: bannerSize, mediaType: BANNER } )) From 6ac6a61905e1733dab0f552a30379c13f255c47e Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Thu, 5 Dec 2024 14:33:11 -0300 Subject: [PATCH 06/20] less duplicated code --- modules/blueBidAdapter.js | 72 ++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 38 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 529979214f0..b9c7d14a788 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -235,53 +235,49 @@ function getFloors(bidRequest) { try { const floors = {}; - let getFloor; - - if (bidRequest.getFloor) { - getFloor = bidRequest.getFloor; - } - if (bidRequest.params.bidFloor && bidRequest.params.bidFloorCur) { - try { - const floor = parseFloat(bidRequest.params.bidFloor); - return () => { - getFloor = { + const parseBidFloor = () => { + if (bidRequest.params?.bidFloor && bidRequest.params?.bidFloorCur) { + try { + const floor = parseFloat(bidRequest.params.bidFloor); + return { currency: bidRequest.params.bidFloorCur, floor: floor, }; - }; - } catch {} - } - getFloor = undefined; - - if (getFloor) { - if (bidRequest.mediaTypes?.banner) { - floors.banner = {}; - - const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); - const parser = (s) => s; - - if (sizes == undefined) { - return []; + } catch { + return undefined; } - if (Array.isArray(sizes[0])) { - // is there several sizes ? (ie. [[728,90],[200,300]]) - return sizes.map((size) => parser(size)); - } - const bannerSizes = [parser(sizes)]; // or a single one ? (ie. [728,90]) - - bannerSizes.forEach( - (bannerSize) => - (floors.banner[(bannerSize[0] + 'x' + bannerSize[1]).toString()] = getFloor.call( - bidRequest, - { size: bannerSize, mediaType: BANNER } - )) - ); } + return undefined; + }; + + const calculateBannerFloors = (getFloor) => { + const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); + if (!sizes) return []; + + const normalizeSizes = (sizes) => + Array.isArray(sizes[0]) ? sizes : [sizes]; // Normalize to array of sizes + const bannerSizes = normalizeSizes(sizes); + + return bannerSizes.reduce((bannerFloors, bannerSize) => { + const sizeKey = `${bannerSize[0]}x${bannerSize[1]}`; + bannerFloors[sizeKey] = getFloor.call(bidRequest, { + size: bannerSize, + mediaType: BANNER, + }); + return bannerFloors; + }, {}); + }; + + let getFloor = bidRequest.getFloor || parseBidFloor(); - return floors; + if (getFloor && bidRequest.mediaTypes?.banner) { + floors.banner = calculateBannerFloors(getFloor); } + + return floors; } catch (e) { logError('Could not parse floors from Prebid: ' + e); + return {}; } } From 968b798f3b6c56e494fa11f831d7732878877e80 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Thu, 5 Dec 2024 14:34:18 -0300 Subject: [PATCH 07/20] less duplicated code --- modules/blueBidAdapter.js | 137 +++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 46 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index b9c7d14a788..5cba985dc48 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -161,75 +161,120 @@ export const spec = { supportedMediaTypes: [BANNER], /** - * f + * Validates the bid request. * @param {object} bid * @return {boolean} */ - isBidRequestValid: (bid) => { - // either one of zoneId or networkId should be set - if (!(bid && bid.params && bid.params.publisherId)) { - return false; - } - - return true; - }, + isBidRequestValid: (bid) => isValidBidRequest(bid), /** + * Builds requests for the bidder. * @param {BidRequest[]} bidRequests * @param {*} bidderRequest * @return {ServerRequest} */ buildRequests: (bidRequests, bidderRequest) => { - const context = { - url: bidderRequest?.refererInfo?.page || '', - publisherId: bidRequests.find((bidRequest) => bidRequest.params?.pubid) - ?.params.pubid, - }; - const blueId = - storage.cookiesAreEnabled() && storage.getCookie(BUNDLE_COOKIE_NAME); - let url = CDB_ENDPOINT; - url += '&wv=' + encodeURIComponent('$prebid.version$'); - url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); - - if (context.publisherId) { - url += `&publisherId=` + context.publisherId; - } - - const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); - // put user id in the request - if (data.user == undefined) { - data.user = {}; - } + const context = buildContext(bidRequests, bidderRequest); + const url = buildUrl(context.publisherId); + const data = prepareData(bidRequests, bidderRequest, context); - if (data.user.ext == undefined) { - data.user.ext = { - buyerid: blueId, - }; - } if (data) { return { method: 'POST', url, data, bidRequests }; } }, /** + * Interprets the server response. * @param {*} response * @param {ServerRequest} request * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} */ - interpretResponse: (response, request) => { - if (typeof response?.body == 'undefined') { - return []; // no bid - } + interpretResponse: (response, request) => interpretServerResponse(response, request), +}; - const interpretedResponse = CONVERTER.fromORTB({ - response: response.body, - request: request.data, - }); - const bids = interpretedResponse.bids || []; +// Helper functions - return bids; - }, -}; +/** + * Validates a bid request. + * @param {object} bid + * @return {boolean} + */ +function isValidBidRequest(bid) { + return bid?.params?.publisherId ? true : false; +} + +/** + * Builds the request context. + * @param {BidRequest[]} bidRequests + * @param {*} bidderRequest + * @return {object} + */ +function buildContext(bidRequests, bidderRequest) { + const publisherId = bidRequests.find((bidRequest) => bidRequest.params?.pubid)?.params.pubid; + return { + url: bidderRequest?.refererInfo?.page || '', + publisherId, + }; +} + +/** + * Builds the request URL. + * @param {string} publisherId + * @return {string} + */ +function buildUrl(publisherId) { + let url = CDB_ENDPOINT; + url += '&wv=' + encodeURIComponent('$prebid.version$'); + url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); + + if (publisherId) { + url += `&publisherId=` + publisherId; + } + + return url; +} + +/** + * Prepares the request data. + * @param {BidRequest[]} bidRequests + * @param {*} bidderRequest + * @param {object} context + * @return {object} + */ +function prepareData(bidRequests, bidderRequest, context) { + const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); + + if (!data.user) { + data.user = {}; + } + + if (!data.user.ext) { + data.user.ext = { + buyerid: storage.cookiesAreEnabled() ? storage.getCookie(BUNDLE_COOKIE_NAME) : undefined, + }; + } + + return data; +} + +/** + * Interprets the server response. + * @param {*} response + * @param {ServerRequest} request + * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} + */ +function interpretServerResponse(response, request) { + if (!response?.body) { + return []; // No bids + } + + const interpretedResponse = CONVERTER.fromORTB({ + response: response.body, + request: request.data, + }); + + return interpretedResponse.bids || []; +} function getFloors(bidRequest) { try { From 82077213ddaccbd602d236ae6592b9bad0e6cb62 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Thu, 5 Dec 2024 14:35:16 -0300 Subject: [PATCH 08/20] less duplicated code --- modules/blueBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 5cba985dc48..40fd4af9979 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -200,7 +200,7 @@ export const spec = { * @return {boolean} */ function isValidBidRequest(bid) { - return bid?.params?.publisherId ? true : false; + return bid && bid.params && bid.params.publisherId; } /** From b980c32cbcd07c098221f0df24e1e05346f6f6e8 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Thu, 5 Dec 2024 14:40:02 -0300 Subject: [PATCH 09/20] less duplicated code --- modules/blueBidAdapter.js | 73 +++++++++++++++++++++++++-------------- 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 40fd4af9979..10450ca1c10 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -44,27 +44,38 @@ const CONVERTER = ortbConverter({ * @returns {Object} The ORTB 2.5 imp object. */ function imp(buildImp, bidRequest, context) { - let imp = buildImp(bidRequest, context); - const params = bidRequest.params; + const imp = buildImp(bidRequest, context); + const params = bidRequest.params || {}; imp.tagid = bidRequest.adUnitCode; - deepSetValue(imp, 'ext', { - ...bidRequest.params.ext, + + const ext = { + ...params.ext, ...imp.ext, rwdd: imp.rwdd, floors: getFloors(bidRequest), - bidder: { - publishersubid: params?.publisherSubId, - zoneid: params?.zoneId, - uid: params?.uid, - }, - }); + bidder: buildBidderExt(params), + }; - delete imp.rwdd; // oRTB 2.6 field moved to ext + deepSetValue(imp, 'ext', ext); return imp; } +/** + * Builds the bidder extension object for the impression. + * + * @param {Object} params - The parameters from the bid request. + * @returns {Object} The bidder extension object. + */ +function buildBidderExt(params) { + return { + publishersubid: params.publisherSubId, + zoneid: params.zoneId, + uid: params.uid, + }; +} + /** * Builds a request object for the ORTB 2.5 request. * @@ -77,27 +88,37 @@ function imp(buildImp, bidRequest, context) { function request(buildRequest, imps, bidderRequest, context) { let request = buildRequest(imps, bidderRequest, context); - // params.pubid should override publisher id - if (typeof context.publisherId !== 'undefined') { - if (typeof request.app !== 'undefined') { - deepSetValue(request, 'app.publisher.id', context.publisherId); - } else { - deepSetValue(request, 'site.publisher.id', context.publisherId); - } + if (context.publisherId !== undefined) { + setPublisherId(request, context.publisherId); } - if (bidderRequest && bidderRequest.gdprConsent) { - deepSetValue( - request, - 'regs.ext.gdprversion', - bidderRequest.gdprConsent.apiVersion - ); + if (bidderRequest?.gdprConsent) { + setGdprVersion(request, bidderRequest.gdprConsent.apiVersion); } // Translate 2.6 OpenRTB request into 2.5 OpenRTB request - request = TRANSLATOR(request); + return TRANSLATOR(request); +} + +/** + * Sets the publisher ID in the request object based on the context. + * + * @param {Object} request - The ORTB 2.5 request object. + * @param {string} publisherId - The publisher ID to set. + */ +function setPublisherId(request, publisherId) { + const targetPath = request.app ? 'app.publisher.id' : 'site.publisher.id'; + deepSetValue(request, targetPath, publisherId); +} - return request; +/** + * Sets the GDPR version in the request object if GDPR consent is provided. + * + * @param {Object} request - The ORTB 2.5 request object. + * @param {string} gdprVersion - The GDPR API version. + */ +function setGdprVersion(request, gdprVersion) { + deepSetValue(request, 'regs.ext.gdprversion', gdprVersion); } /** From 64b502a4e8df1999c980a8c402ecb4dd5fdc8072 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 11:53:50 -0300 Subject: [PATCH 10/20] blue adapter --- integrationExamples/gpt/hello_world.html | 12 +- modules/blueBidAdapter.js | 389 ++----- package-lock.json | 12 +- test/spec/modules/blueBidAdapter_spec.js | 1270 +--------------------- 4 files changed, 128 insertions(+), 1555 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 03a2356f0ef..589d43f9bda 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -23,16 +23,18 @@ sizes: [[300, 250]], } }, - // Replace this object to test a new Adapter! bids: [{ - bidder: 'appnexus', + bidder: 'blue', params: { - placementId: 13144370 + bidFloor: 0.05, + currency: 'USD', + placementId: 13144370, + publisherId: 13144370 } }] - - }]; + }, + ]; var pbjs = pbjs || {}; pbjs.que = pbjs.que || []; diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 10450ca1c10..5f7c598bd51 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -1,350 +1,107 @@ -import { deepAccess, deepSetValue, logError } from '../src/utils.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER } from '../src/mediaTypes.js'; import { getStorageManager } from '../src/storageManager.js'; -import { ortbConverter } from '../libraries/ortbConverter/converter.js'; -import { ortb25Translator } from '../libraries/ortb2.5Translator/translator.js'; - -/** - * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest - * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid - * @typedef {import('../src/adapters/bidderFactory.js').ServerRequest} ServerRequest - * @typedef {import('../src/adapters/bidderFactory.js').BidderSpec} BidderSpec - * @typedef {import('../src/adapters/bidderFactory.js').TimedOutBid} TimedOutBid - */ +import { deepSetValue } from '../src/utils.js'; const BIDDER_CODE = 'blue'; -const GVLID = 620; -const CDB_ENDPOINT = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid'; -const BUNDLE_COOKIE_NAME = 'ckid'; - +const ENDPOINT_URL = 'https://bidder-us-east-1.getblue.io/engine/?src=prebid'; +const GVLID = 620; // GVLID for your bidder +const COOKIE_NAME = 'ckid'; // Cookie name for identifying users export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); -const TRANSLATOR = ortb25Translator(); -/** - * Defines the generic oRTB converter and all customization functions. - */ -const CONVERTER = ortbConverter({ +const converter = ortbConverter({ context: { - netRevenue: true, - ttl: 60, + netRevenue: true, // Default netRevenue setting + ttl: 100, // Default time-to-live for bid responses }, imp, - request, - bidResponse, - response, + request }); -/** - * Builds an impression object for the ORTB 2.5 request. - * - * @param {function} buildImp - The function for building an imp object. - * @param {Object} bidRequest - The bid request object. - * @param {Object} context - The context object. - * @returns {Object} The ORTB 2.5 imp object. - */ -function imp(buildImp, bidRequest, context) { - const imp = buildImp(bidRequest, context); - const params = bidRequest.params || {}; - - imp.tagid = bidRequest.adUnitCode; - - const ext = { - ...params.ext, - ...imp.ext, - rwdd: imp.rwdd, - floors: getFloors(bidRequest), - bidder: buildBidderExt(params), - }; - - deepSetValue(imp, 'ext', ext); - - return imp; -} - -/** - * Builds the bidder extension object for the impression. - * - * @param {Object} params - The parameters from the bid request. - * @returns {Object} The bidder extension object. - */ -function buildBidderExt(params) { - return { - publishersubid: params.publisherSubId, - zoneid: params.zoneId, - uid: params.uid, - }; -} - -/** - * Builds a request object for the ORTB 2.5 request. - * - * @param {function} buildRequest - The function for building a request object. - * @param {Array} imps - An array of ORTB 2.5 impression objects. - * @param {Object} bidderRequest - The bidder request object. - * @param {Object} context - The context object. - * @returns {Object} The ORTB 2.5 request object. - */ function request(buildRequest, imps, bidderRequest, context) { let request = buildRequest(imps, bidderRequest, context); - - if (context.publisherId !== undefined) { - setPublisherId(request, context.publisherId); - } - - if (bidderRequest?.gdprConsent) { - setGdprVersion(request, bidderRequest.gdprConsent.apiVersion); - } - - // Translate 2.6 OpenRTB request into 2.5 OpenRTB request - return TRANSLATOR(request); + deepSetValue(request, 'site.publisher.id', context.publisherId); + // eslint-disable-next-line no-console + return request; } -/** - * Sets the publisher ID in the request object based on the context. - * - * @param {Object} request - The ORTB 2.5 request object. - * @param {string} publisherId - The publisher ID to set. - */ -function setPublisherId(request, publisherId) { - const targetPath = request.app ? 'app.publisher.id' : 'site.publisher.id'; - deepSetValue(request, targetPath, publisherId); -} - -/** - * Sets the GDPR version in the request object if GDPR consent is provided. - * - * @param {Object} request - The ORTB 2.5 request object. - * @param {string} gdprVersion - The GDPR API version. - */ -function setGdprVersion(request, gdprVersion) { - deepSetValue(request, 'regs.ext.gdprversion', gdprVersion); -} - -/** - * Build bid from oRTB 2.5 bid. - * - * @param buildBidResponse - * @param bid - * @param context - * @returns {*} - */ -function bidResponse(buildBidResponse, bid, context) { - context.mediaType = deepAccess(bid, 'ext.mediatype'); - let bidResponse = buildBidResponse(bid, context); - - bidResponse.currency = deepAccess(bid, 'ext.cur'); - - if (typeof deepAccess(bid, 'ext.meta') !== 'undefined') { - deepSetValue(bidResponse, 'meta', { - ...bidResponse.meta, - ...bid.ext.meta, - }); - } - if (typeof deepAccess(bid, 'ext.paf.content_id') !== 'undefined') { - deepSetValue(bidResponse, 'meta.paf.content_id', bid.ext.paf.content_id); - } - - return bidResponse; -} - -/** - * Builds bid response from the oRTB 2.5 bid response. - * - * @param buildResponse - * @param bidResponses - * @param ortbResponse - * @param context - * @returns * - */ -function response(buildResponse, bidResponses, ortbResponse, context) { - let response = buildResponse(bidResponses, ortbResponse, context); - - const pafTransmission = deepAccess(ortbResponse, 'ext.paf.transmission'); - response.bids.forEach((bid) => { - if ( - typeof pafTransmission !== 'undefined' && - typeof deepAccess(bid, 'meta.paf.content_id') !== 'undefined' - ) { - deepSetValue(bid, 'meta.paf.transmission', pafTransmission); - } else { - delete bid.meta.paf; - } - }); - - return response; +function imp(buildImp, bidRequest, context) { + let imp = buildImp(bidRequest, context); + // eslint-disable-next-line no-console + console.log(JSON.stringify(imp, null, 2)); + imp.bidfloor = bidRequest.params.bidFloor; + imp.bidfloorcur = bidRequest.params.currency; + imp.tagid = bidRequest.params.placementId; + return imp; } -/** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [BANNER], - - /** - * Validates the bid request. - * @param {object} bid - * @return {boolean} - */ - isBidRequestValid: (bid) => isValidBidRequest(bid), - - /** - * Builds requests for the bidder. - * @param {BidRequest[]} bidRequests - * @param {*} bidderRequest - * @return {ServerRequest} - */ - buildRequests: (bidRequests, bidderRequest) => { - const context = buildContext(bidRequests, bidderRequest); - const url = buildUrl(context.publisherId); - const data = prepareData(bidRequests, bidderRequest, context); - - if (data) { - return { method: 'POST', url, data, bidRequests }; - } + supportedMediaTypes: [BANNER], // Supported ad types + + // Validate bid request + isBidRequestValid: function (bid) { + // eslint-disable-next-line no-console + console.log(bid); + return ( + !!bid.params.placementId && !!bid.params.publisherId + // !!bid.params.params.bidFloor && + // !!bid.params.params.currency + ); }, - /** - * Interprets the server response. - * @param {*} response - * @param {ServerRequest} request - * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} - */ - interpretResponse: (response, request) => interpretServerResponse(response, request), -}; - -// Helper functions - -/** - * Validates a bid request. - * @param {object} bid - * @return {boolean} - */ -function isValidBidRequest(bid) { - return bid && bid.params && bid.params.publisherId; -} - -/** - * Builds the request context. - * @param {BidRequest[]} bidRequests - * @param {*} bidderRequest - * @return {object} - */ -function buildContext(bidRequests, bidderRequest) { - const publisherId = bidRequests.find((bidRequest) => bidRequest.params?.pubid)?.params.pubid; - return { - url: bidderRequest?.refererInfo?.page || '', - publisherId, - }; -} - -/** - * Builds the request URL. - * @param {string} publisherId - * @return {string} - */ -function buildUrl(publisherId) { - let url = CDB_ENDPOINT; - url += '&wv=' + encodeURIComponent('$prebid.version$'); - url += '&cb=' + String(Math.floor(Math.random() * 99999999999)); - - if (publisherId) { - url += `&publisherId=` + publisherId; - } - - return url; -} - -/** - * Prepares the request data. - * @param {BidRequest[]} bidRequests - * @param {*} bidderRequest - * @param {object} context - * @return {object} - */ -function prepareData(bidRequests, bidderRequest, context) { - const data = CONVERTER.toORTB({ bidderRequest, bidRequests, context }); - - if (!data.user) { - data.user = {}; - } - - if (!data.user.ext) { - data.user.ext = { - buyerid: storage.cookiesAreEnabled() ? storage.getCookie(BUNDLE_COOKIE_NAME) : undefined, - }; - } - - return data; -} - -/** - * Interprets the server response. - * @param {*} response - * @param {ServerRequest} request - * @return {Bid[] | {bids: Bid[], fledgeAuctionConfigs: object[]}} - */ -function interpretServerResponse(response, request) { - if (!response?.body) { - return []; // No bids - } + // Build OpenRTB requests using `ortbConverter` + buildRequests: function (validBidRequests, bidderRequest) { + const context = { + publisherId: validBidRequests.find(bidRequest => bidRequest.params?.publisherId)?.params.publisherId, + } - const interpretedResponse = CONVERTER.fromORTB({ - response: response.body, - request: request.data, - }); + const ortbRequest = converter.toORTB({ + bidRequests: validBidRequests, + bidderRequest, + context + }); - return interpretedResponse.bids || []; -} + // Add GVLID and cookie ID to the request + ortbRequest.ext = ortbRequest.ext || {}; + deepSetValue(ortbRequest, 'ext.gvlid', GVLID); -function getFloors(bidRequest) { - try { - const floors = {}; + // Include user cookie if available + const ckid = storage.getCookie(COOKIE_NAME) || null; + if (ckid) { + deepSetValue(ortbRequest, 'user.ext.buyerid', ckid); + } - const parseBidFloor = () => { - if (bidRequest.params?.bidFloor && bidRequest.params?.bidFloorCur) { - try { - const floor = parseFloat(bidRequest.params.bidFloor); - return { - currency: bidRequest.params.bidFloorCur, - floor: floor, - }; - } catch { - return undefined; - } - } - return undefined; + return { + method: 'POST', + url: ENDPOINT_URL, + data: ortbRequest, + options: { + contentType: 'application/json', + }, }; + }, - const calculateBannerFloors = (getFloor) => { - const sizes = deepAccess(bidRequest, 'mediaTypes.banner.sizes'); - if (!sizes) return []; - - const normalizeSizes = (sizes) => - Array.isArray(sizes[0]) ? sizes : [sizes]; // Normalize to array of sizes - const bannerSizes = normalizeSizes(sizes); - - return bannerSizes.reduce((bannerFloors, bannerSize) => { - const sizeKey = `${bannerSize[0]}x${bannerSize[1]}`; - bannerFloors[sizeKey] = getFloor.call(bidRequest, { - size: bannerSize, - mediaType: BANNER, - }); - return bannerFloors; - }, {}); - }; + // Interpret OpenRTB responses using `ortbConverter` + interpretResponse: function (serverResponse, request) { + const ortbResponse = serverResponse.body; - let getFloor = bidRequest.getFloor || parseBidFloor(); + // Parse the OpenRTB response into Prebid bid responses + const prebidResponses = converter.fromORTB({ + response: ortbResponse, + request: request.data, + }).bids; - if (getFloor && bidRequest.mediaTypes?.banner) { - floors.banner = calculateBannerFloors(getFloor); - } + // Example: Modify bid responses if needed + prebidResponses.forEach((bid) => { + bid.meta = bid.meta || {}; + bid.meta.adapterVersion = '1.0.0'; + }); - return floors; - } catch (e) { - logError('Could not parse floors from Prebid: ' + e); - return {}; - } -} + return prebidResponses; + }, +}; registerBidder(spec); diff --git a/package-lock.json b/package-lock.json index 133c5a7a632..d30d4c26462 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7616,9 +7616,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001633", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", - "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", + "version": "1.0.30001688", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", + "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==", "funding": [ { "type": "opencollective", @@ -33565,9 +33565,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001633", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", - "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==" + "version": "1.0.30001688", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", + "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==" }, "caseless": { "version": "0.12.0", diff --git a/test/spec/modules/blueBidAdapter_spec.js b/test/spec/modules/blueBidAdapter_spec.js index b3b2dd0a438..fa71aeac70a 100755 --- a/test/spec/modules/blueBidAdapter_spec.js +++ b/test/spec/modules/blueBidAdapter_spec.js @@ -1,1253 +1,67 @@ import { expect } from 'chai'; -import { - spec, - storage, -} from 'modules/blueBidAdapter.js'; -import * as utils from 'src/utils.js'; -import * as refererDetection from 'src/refererDetection.js'; -import * as ajax from 'src/ajax.js'; -import { config } from '../../../src/config.js'; -import { BANNER, NATIVE, VIDEO } from '../../../src/mediaTypes.js'; -import {syncAddFPDToBidderRequest} from '../../helpers/fpd.js'; -import 'modules/userId/index.js'; -import 'modules/consentManagementTcf.js'; -import 'modules/consentManagementUsp.js'; -import 'modules/consentManagementGpp.js'; -import 'modules/schain.js'; -import {hook} from '../../../src/hook.js'; +import { spec, storage } from 'modules/blueBidAdapter.js'; -describe('The Blue bidding adapter', function () { - let utilsMock, sandbox, ajaxStub; - - beforeEach(function () { - $$PREBID_GLOBAL$$.bidderSettings = { - blue: { - storageAllowed: true - } +describe('blue Adapter', function () { + describe('isBidRequestValid', function () { + const validBid = { + bidder: 'blue', + params: { + bidFloor: 0.05, + currency: 'USD', + placementId: 13144370, + publisherId: 13144370, + }, }; - // Remove FastBid to avoid side effects - localStorage.removeItem('blue_fast_bid'); - utilsMock = sinon.mock(utils); - sandbox = sinon.sandbox.create(); - ajaxStub = sandbox.stub(ajax, 'ajax'); - }); - - afterEach(function () { - $$PREBID_GLOBAL$$.bidderSettings = {}; - global.Blue = undefined; - utilsMock.restore(); - sandbox.restore(); - ajaxStub.restore(); - }); + const invalidBid = { + bidder: 'blue', + params: { + bidFloor: 0.05, + currency: 'USD', + }, + }; - describe('isBidRequestValid', function () { - it('should return false when given an invalid bid', function () { - const bid = { - bidder: 'blue', - }; - const isValid = spec.isBidRequestValid(bid); - expect(isValid).to.equal(false); + it('should return true for valid bid', function () { + expect(spec.isBidRequestValid(validBid)).to.equal(true); }); - it('should return true when given a zoneId bid', function () { - const bid = { - bidder: 'blue', - params: { - publisherId: 123, - }, - }; - const isValid = spec.isBidRequestValid(bid); - expect(isValid).to.equal(true); + it('should return false for invalid bid', function () { + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); }); describe('buildRequests', function () { - const refererUrl = 'https://blue.com?pbt_debug=1&pbt_nolog=1'; - const bidderRequest = { - refererInfo: { - page: refererUrl, - topmostLocation: refererUrl - }, - timeout: 3000, - gdprConsent: { - gdprApplies: true, - consentString: 'consentDataString', - vendorData: { - vendorConsents: { - '91': 1 - }, - }, - apiVersion: 1, + const bidRequest = { + bidder: 'blue', + params: { + bidFloor: 0.05, + currency: 'USD', + placementId: 13144370, + publisherId: 13144370, }, + adUnitCode: 'div-gpt-ad-1460505748561-0', + sizes: [[300, 250]], }; - let localStorageIsEnabledStub; - - before(() => { - hook.ready(); - }); - - this.beforeEach(function () { - localStorageIsEnabledStub = sinon.stub(storage, 'localStorageIsEnabled'); - localStorageIsEnabledStub.returns(true); - }); - - afterEach(function () { - localStorageIsEnabledStub.restore(); - config.resetConfig(); - }); - - it('should properly build a request using random uuid as auction id', function () { - const generateUUIDStub = sinon.stub(utils, 'generateUUID'); - generateUUIDStub.returns('def'); - const bidderRequest = {}; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: {} - }, - ]; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.id).to.equal('def'); - generateUUIDStub.restore(); - }); - - it('should properly transmit source.tid if available', function () { - const bidderRequest = { - ortb2: { - source: { - tid: 'abc' - } - } - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: {} - }, - ]; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.source.tid).to.equal('abc'); - }); - - it('should properly transmit tmax if available', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - transactionId: 'transaction-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: {} - }, - ]; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.tmax).to.equal(bidderRequest.timeout); - }); - - it('should properly transmit bidId if available', function () { - const bidderRequest = {}; - const bidRequests = [ - { - bidId: 'bidId', - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: {} - }, - ]; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.imp[0].id).to.equal('bidId'); - }); - - it('should properly forward eids', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: {} - }, - ]; - const br = { - ...bidderRequest, - ortb2: { - user: { - ext: { - eids: [ - { - source: 'blue.com', - uids: [{ - id: 'abc', - atype: 1 - }] - } - ] - } - } - } - } - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(br)); - const ortbRequest = request.data; - expect(ortbRequest.user.ext.eids).to.deep.equal([ - { - source: 'blue.com', - uids: [{ - id: 'abc', - atype: 1 - }] - } - ]); - }); - - it('should properly build a publisherId request', function () { - const bidderRequest = { - refererInfo: { - page: refererUrl, - topmostLocation: refererUrl, - }, - timeout: 3000, - gdprConsent: { - gdprApplies: false, - consentString: undefined, - vendorData: { - vendorConsents: { - '1': 0 - }, - }, - }, - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - ortb2Imp: { - ext: { - tid: 'transaction-123', - }, - }, - mediaTypes: { - banner: { - sizes: [[300, 250], [728, 90]] - } - }, - params: { - networkId: 456, - }, - }, - ]; - - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - expect(request.url).to.contain('https://bidder-us-east-1.getblue.io/engine/?src=prebid'); - expect(request.method).to.equal('POST'); - const ortbRequest = request.data; - expect(ortbRequest.site.page).to.equal(refererUrl); - expect(ortbRequest.imp).to.have.lengthOf(1); - expect(ortbRequest.imp[0].tagid).to.equal('bid-123'); - expect(ortbRequest.imp[0].banner.format).to.have.lengthOf(2); - expect(ortbRequest.imp[0].banner.format[0].w).to.equal(300); - expect(ortbRequest.imp[0].banner.format[0].h).to.equal(250); - expect(ortbRequest.imp[0].banner.format[1].w).to.equal(728); - expect(ortbRequest.imp[0].banner.format[1].h).to.equal(90); - expect(ortbRequest.user?.ext?.consent).to.equal(undefined); - expect(ortbRequest.regs.ext.gdpr).to.equal(0); - }); - - it('should properly build a request with undefined gdpr consent fields when they are not provided', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - timeout: 3000, - gdprConsent: {}, - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.user?.ext?.consent).to.equal(undefined); - expect(ortbRequest.regs?.ext?.gdpr).to.equal(undefined); - }); - - it('should properly build a request with ccpa consent field', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - timeout: 3000, - uspConsent: '1YNY', - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.regs.ext.us_privacy).to.equal('1YNY'); - }); - - it('should properly build a request with overridden tmax', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - timeout: 1234 - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.tmax).to.equal(1234); - }); - - it('should properly build a request with device sua field', function () { - const sua = { - platform: { - brand: 'abc' - } - } - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - timeout: 3000, - uspConsent: '1YNY', - ortb2: { - device: { - sua: sua - } - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.device.ext.sua).not.to.be.null; - expect(ortbRequest.device.ext.sua.platform.brand).to.equal('abc'); - }); - - it('should properly build a request with gpp consent field', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const ortb2 = { - regs: { - gpp: 'gpp_consent_string', - gpp_sid: [0, 1, 2], - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; - expect(ortbRequest.regs.ext.gpp).to.equal('gpp_consent_string'); - expect(ortbRequest.regs.ext.gpp_sid).to.deep.equal([0, 1, 2]); - }); - - it('should properly build a request with dsa object', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - let dsa = { - required: 3, - pubrender: 0, - datatopub: 2, - transparency: [{ - domain: 'platform1domain.com', - params: [1] - }, { - domain: 'SSP2domain.com', - params: [1, 2] - }] - }; - const ortb2 = { - regs: { - ext: { - dsa: dsa - } - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; - expect(ortbRequest.regs.ext.dsa).to.deep.equal(dsa); - }); - - it('should properly build a request with schain object', function () { - const expectedSchain = { - someProperty: 'someValue' - }; - const bidRequests = [ - { - bidder: 'blue', - schain: expectedSchain, - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.source.ext.schain).to.equal(expectedSchain); - }); - - it('should properly build a request with bcat field', function () { - const bcat = ['IAB1', 'IAB2']; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - ortb2: { - bcat - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.bcat).to.deep.equal(bcat); - }); - - it('should properly build a request with badv field', function () { - const badv = ['ford.com']; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - ortb2: { - badv - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.badv).to.deep.equal(badv); - }); - - it('should properly build a request with bapp field', function () { - const bapp = ['com.foo.mygame']; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - ]; - const bidderRequest = { - ortb2: { - bapp - } - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.bapp).to.deep.equal(bapp); - }); - - it('should properly build a request without first party data', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2: {} })).data; - expect(ortbRequest.site.page).to.equal(refererUrl); - expect(ortbRequest.imp).to.have.lengthOf(1); - expect(ortbRequest.imp[0].tagid).to.equal('bid-123'); - expect(ortbRequest.imp[0].banner.format).to.have.lengthOf(1); - expect(ortbRequest.imp[0].banner.format[0].w).to.equal(728); - expect(ortbRequest.imp[0].banner.format[0].h).to.equal(90); - expect(ortbRequest.imp[0].ext.bidder.zoneid).to.equal(123); - expect(ortbRequest.user.ext.consent).to.equal('consentDataString'); - expect(ortbRequest.regs.ext.gdpr).to.equal(1); - expect(ortbRequest.regs.ext.gdprversion).to.equal(1); - }); - - it('should properly build a request with first party data', function () { - const siteData = { - keywords: ['power tools'], - content: { - data: [{ - name: 'some_provider', - ext: { - segtax: 3 - }, - segment: [ - { 'id': '1001' }, - { 'id': '1002' } - ] - }] - }, - ext: { - data: { - pageType: 'article' - } - } - }; - const userData = { - gender: 'M', - data: [{ - name: 'some_provider', - ext: { - segtax: 3 - }, - segment: [ - { 'id': '1001' }, - { 'id': '1002' } - ] - }], - ext: { - data: { - registered: true - } - } - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - ext: { - bidfloor: 0.75 - } - }, - ortb2Imp: { - ext: { - data: { - someContextAttribute: 'abc' - } - } - } - }, - ]; - - const ortb2 = { - site: siteData, - user: userData - }; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest({ ...bidderRequest, ortb2 })).data; - expect(ortbRequest.user).to.deep.equal({ ...userData, ext: { ...userData.ext, consent: 'consentDataString' } }); - expect(ortbRequest.site).to.deep.equal({ ...siteData, page: refererUrl, domain: 'blue.com', publisher: { ...ortbRequest.site.publisher, domain: 'blue.com' } }); - expect(ortbRequest.imp[0].ext.bidfloor).to.equal(0.75); - expect(ortbRequest.imp[0].ext.data.someContextAttribute).to.equal('abc') - }); - - it('should properly build a request when coppa flag is true', function () { - const bidRequests = []; - const bidderRequest = {}; - config.setConfig({ coppa: true }); - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.regs.coppa).to.equal(1); - }); - - it('should properly build a request when coppa flag is false', function () { - const bidRequests = []; - const bidderRequest = {}; - config.setConfig({ coppa: false }); - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.regs.coppa).to.equal(0); - }); - - it('should properly build a request when coppa flag is not defined', function () { - const bidRequests = []; - const bidderRequest = {}; - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.regs?.coppa).to.be.undefined; - }); - - it('should properly build a banner request with floors', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[300, 250], [728, 90]] - } - }, - params: { - networkId: 456, - }, - - getFloor: inputParams => { - if (inputParams.mediaType === BANNER && inputParams.size[0] === 300 && inputParams.size[1] === 250) { - return { - currency: 'USD', - floor: 1.0 - }; - } else if (inputParams.mediaType === BANNER && inputParams.size[0] === 728 && inputParams.size[1] === 90) { - return { - currency: 'USD', - floor: 2.0 - }; - } else { - return {} - } - } - }, - ]; - const bidderRequest = {}; - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.floors).to.deep.equal({ - 'banner': { - '300x250': { 'currency': 'USD', 'floor': 1 }, - '728x90': { 'currency': 'USD', 'floor': 2 } - } - }); - }); - - it('should properly build a request with static floors', function () { - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[300, 250], [728, 90]] - } - }, - params: { - networkId: 456, - bidFloor: 1, - bidFloorCur: 'EUR' - }, - }, - ]; - const bidderRequest = {}; - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.floors).to.deep.equal({ - 'banner': { - '300x250': { 'currency': 'EUR', 'floor': 1 }, - '728x90': { 'currency': 'EUR', 'floor': 1 } - } - }); - }); - - it('should properly build a request when imp.rwdd is present', function () { - const bidderRequest = {}; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - rwdd: 1 - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.rwdd).to.equal(1); - }); - - it('should properly build a request when imp.rwdd is false', function () { - const bidderRequest = {}; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - rwdd: 0 - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext?.rwdd).to.equal(0); - }); - - it('should properly build a request when FLEDGE is enabled', function () { - const bidderRequest = { - paapi: { - enabled: true - } - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - ext: { - igs: { - ae: 1 - } - } - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.igs.ae).to.equal(1); - }); - - it('should properly build a request when FLEDGE is disabled', function () { - const bidderRequest = { - paapi: { - enabled: false - }, - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123 - }, - ortb2Imp: { - ext: { - igs: { - ae: 1 - } - } - } - }, - ]; - - const ortbRequest = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)).data; - expect(ortbRequest.imp[0].ext.igs?.ae).to.be.undefined; - }); - - it('should properly transmit the pubid and slot uid if available', function () { - const bidderRequest = { - ortb2: { - site: { - publisher: { - id: 'pub-777' - } - } - } - }; - const bidRequests = [ - { - bidder: 'blue', - adUnitCode: 'bid-123', - ortb2Imp: { - ext: { - tid: 'transaction-123', - }, - }, - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - zoneId: 123, - }, - }, - { - bidder: 'blue', - adUnitCode: 'bid-234', - ortb2Imp: { - ext: { - tid: 'transaction-234', - }, - }, - mediaTypes: { - banner: { - sizes: [[300, 250], [728, 90]] - } - }, - params: { - networkId: 456, - pubid: 'pub-888', - uid: 888 - }, - }, - ]; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.site.publisher.id).to.equal('pub-888'); - expect(ortbRequest.imp[0].ext.bidder.uid).to.be.undefined; - expect(ortbRequest.imp[1].ext.bidder.uid).to.equal(888); - }); - - it('should properly transmit device.ext.cdep if available', function () { - const bidderRequest = { - ortb2: { - device: { - ext: { - cdep: 'cookieDeprecationLabel' - } - } - } - }; - const bidRequests = []; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const ortbRequest = request.data; - expect(ortbRequest.device.ext.cdep).to.equal('cookieDeprecationLabel'); - }); - }); - - describe('interpretResponse', function () { - const refererUrl = 'https://blue.com?pbt_debug=1&pbt_nolog=1'; const bidderRequest = { refererInfo: { - page: refererUrl, - topmostLocation: refererUrl - }, - timeout: 3000, - gdprConsent: { - gdprApplies: true, - consentString: 'consentDataString', - vendorData: { - vendorConsents: { - '91': 1 - }, - }, - apiVersion: 1, + referer: 'https://example.com', }, }; - function mockResponse(winningBidId, mediaType) { - return { - id: 'test-requestId', - seatbid: [ - { - seat: 'blue', - bid: [ - { - id: 'test-bidderId', - impid: winningBidId, - price: 1.23, - adomain: ['blue.com'], - bundle: '', - iurl: 'http://some_image/', - cid: '123456', - crid: 'test-crId', - dealid: 'deal-code', - w: 728, - h: 90, - adm: 'test-ad', - adm_native: mediaType === NATIVE ? { - ver: '1.2', - assets: [ - { - id: 10, - title: { - text: 'Some product' - } - }, - { - id: 11, - img: { - type: 3, - url: 'https://main_image_url.com', - w: 400, - h: 400 - } - }, - { - id: 12, - data: { - value: 'Some product' - } - }, - { - id: 13, - data: { - value: '1,499 TL' - } - }, - { - id: 15, - data: { - value: 'CTA' - }, - link: { - url: 'https://cta_url.com' - } - }, - { - id: 17, - img: { - type: 1, - url: 'https://main_image_url.com', - w: 200, - h: 200 - }, - link: { - url: 'https://icon_image_url.com' - } - }, - { - id: 16, - data: { - value: 'Some brand' - } - } - ], - eventtrackers: [ - { - event: 1, - method: 1, - url: 'https://eventtrackers.com' - }, - { - event: 1, - method: 1, - url: 'https://test_in_isolation.blue.com/tpd?dd=HTlW9l9xTEZqRHVlSHFiSWx5Q2VQMlEwSTJhNCUyQkxNazQ1Y29LR3ZmS2VTSDFsUGdkRHNoWjQ2UWp0SGtVZ1RTbHI0TFRpTlVqNWxiUkZOeGVFNjVraW53R0loRVJQNDJOY2R1eWxVdjBBQ1BEdVFvTyUyRlg3aWJaeUFha3UyemNNVGpmJTJCS1prc0FwRjZRJTJCQ2dpaFBJeVhZRmQlMkZURVZocUFRdm03OTdFZHZSbURNZWt4Uzh2M1NSUUxmTmhaTnNnRXd4VkZlOTdJOXdnNGZjaVolMkZWYmdYVjJJMkQ0eGxQaFIwQmVtWk1sQ09tNXlGY0Nwc09GTDladzExJTJGVExGNXJsdGpneERDeTMlMkJuNUlUcEU4NDFLMTZPc2ZoWFUwMmpGbDFpVjBPZUVtTlEwaWNOeHRyRFYyenRKd0lpJTJGTTElMkY1WGZ3Smo3aTh0bUJzdzZRdlZUSXppanNkamo3ekZNZjhKdjl2VDJ5eHV1YnVzdmdRdk5iWnprNXVFMVdmbGs0QU1QY0ozZQ' - } - ], - privacy: 'https://cta_url.com', - ext: { - privacy: { - imageurl: 'https://icon_image_url.com', - clickurl: 'https://cta_url.com', - longlegaltext: '' - } - } - } : undefined, - ext: { - mediatype: mediaType, - displayurl: mediaType === VIDEO ? 'http://test-ad' : undefined, - dsa: { - adrender: 1 - }, - meta: { - networkName: 'Blue' - }, - videoPlayerType: mediaType === VIDEO ? 'RadiantMediaPlayer' : undefined, - videoPlayerConfig: mediaType === VIDEO ? {} : undefined, - cur: 'CUR' - } - } - ] - } - ] - }; - } - - it('should return an empty array when parsing an empty bid response', function () { - const bidRequests = []; - const response = {}; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const bids = spec.interpretResponse(response, request); - expect(bids).to.have.lengthOf(0); - }); - - it('should return an empty array when parsing a well-formed no bid response', function () { - const bidRequests = []; - const response = { seatbid: [] }; - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const bids = spec.interpretResponse({ body: response }, request); - expect(bids).to.have.lengthOf(0); - }); + it('should include cookie ID if available', function () { + const cookieStub = sinon.stub(storage, 'getCookie').returns('test-cookie-id'); + const request = spec.buildRequests([bidRequest], bidderRequest); + const payload = request.data; - it('should properly parse a banner bid response', function () { - const bidRequests = [{ - adUnitCode: 'test-requestId', - bidId: 'test-bidId', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - networkId: 456, - } - }]; - const response = mockResponse('test-bidId', BANNER); - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const bids = spec.interpretResponse({ body: response }, request); - expect(bids).to.have.lengthOf(1); - expect(bids[0].mediaType).to.equal(BANNER); - expect(bids[0].requestId).to.equal('test-bidId'); - expect(bids[0].seatBidId).to.equal('test-bidderId') - expect(bids[0].cpm).to.equal(1.23); - expect(bids[0].currency).to.equal('CUR'); - expect(bids[0].width).to.equal(728); - expect(bids[0].height).to.equal(90); - expect(bids[0].ad).to.equal('test-ad'); - expect(bids[0].creativeId).to.equal('test-crId'); - expect(bids[0].dealId).to.equal('deal-code'); - expect(bids[0].meta.advertiserDomains[0]).to.equal('blue.com'); - expect(bids[0].meta.networkName).to.equal('Blue'); - expect(bids[0].meta.dsa.adrender).to.equal(1); + expect(payload.user.ext.buyerid).to.equal('test-cookie-id'); + cookieStub.restore(); }); + }); - it('should properly parse a bid response when banner win with twin ad units', function () { - const bidRequests = [{ - adUnitCode: 'test-requestId', - bidId: 'test-bidId', - mediaTypes: { - video: { - context: 'instream', - mimes: ['video/mpeg'], - playerSize: [640, 480], - protocols: [5, 6], - maxduration: 30, - api: [1, 2] - } - }, - params: { - networkId: 456, - }, - }, { - adUnitCode: 'test-requestId', - bidId: 'test-bidId2', - mediaTypes: { - banner: { - sizes: [[728, 90]] - } - }, - params: { - networkId: 456, - } - }]; - const response = mockResponse('test-bidId2', BANNER); - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const bids = spec.interpretResponse({ body: response }, request); - expect(bids).to.have.lengthOf(1); - expect(bids[0].mediaType).to.equal(BANNER); - expect(bids[0].requestId).to.equal('test-bidId2'); - expect(bids[0].seatBidId).to.equal('test-bidderId') - expect(bids[0].cpm).to.equal(1.23); - expect(bids[0].currency).to.equal('CUR'); - expect(bids[0].width).to.equal(728); - expect(bids[0].height).to.equal(90); - expect(bids[0].ad).to.equal('test-ad'); - expect(bids[0].creativeId).to.equal('test-crId'); - expect(bids[0].dealId).to.equal('deal-code'); - expect(bids[0].meta.advertiserDomains[0]).to.equal('blue.com'); - expect(bids[0].meta.networkName).to.equal('Blue'); - expect(bids[0].meta.dsa.adrender).to.equal(1); + describe('Additional Tests', function () { + it('should support banner media type', function () { + expect(spec.supportedMediaTypes).to.include('banner'); }); - - [{ - hasBidResponseLevelPafData: true, - hasBidResponseBidLevelPafData: true, - shouldContainsBidMetaPafData: true - }, - { - hasBidResponseLevelPafData: false, - hasBidResponseBidLevelPafData: true, - shouldContainsBidMetaPafData: false - }, - { - hasBidResponseLevelPafData: true, - hasBidResponseBidLevelPafData: false, - shouldContainsBidMetaPafData: false - }, - { - hasBidResponseLevelPafData: false, - hasBidResponseBidLevelPafData: false, - shouldContainsBidMetaPafData: false - }].forEach(testCase => - it('should properly forward or not meta paf data', () => { - const bidPafContentId = 'abcdef'; - const pafTransmission = { - version: '12' - }; - const bidRequests = [{ - bidId: 'test-bidId', - adUnitCode: 'adUnitId', - sizes: [[300, 250]], - params: { - networkId: 456, - } - }]; - const response = { - id: 'test-requestId', - seatbid: [{ - seat: 'blue', - bid: [ - { - id: 'test-bidderId', - impid: 'test-bidId', - w: 728, - h: 90, - ext: { - mediatype: BANNER, - paf: testCase.hasBidResponseBidLevelPafData ? { - content_id: bidPafContentId - } : undefined - } - } - ] - }], - ext: (testCase.hasBidResponseLevelPafData ? { - paf: { - transmission: pafTransmission - } - } : undefined) - }; - - const request = spec.buildRequests(bidRequests, syncAddFPDToBidderRequest(bidderRequest)); - const bids = spec.interpretResponse({ body: response }, request); - - expect(bids).to.have.lengthOf(1); - - const expectedBidMetaPafData = { - paf: { - content_id: bidPafContentId, - transmission: pafTransmission - } - }; - - if (testCase.shouldContainsBidMetaPafData) { - expect(bids[0].meta).to.deep.equal(expectedBidMetaPafData); - } else { - expect(bids[0].meta).not.to.deep.equal(expectedBidMetaPafData); - } - }) - ) }); }); From 21d5b272865ae686ad45bf75ef8f542ec5f9d2d8 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 12:41:25 -0300 Subject: [PATCH 11/20] blue adapter --- modules/blueBidAdapter.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/blueBidAdapter.md b/modules/blueBidAdapter.md index 80c05019d52..7b59131ea7b 100644 --- a/modules/blueBidAdapter.md +++ b/modules/blueBidAdapter.md @@ -18,7 +18,10 @@ Module that connects to Blue's demand sources. { bidder: 'blue', params: { - publisherId: "xpto" + publisherId: "xpto", + bidFloor: 0.5, + currency: "USD", + placementId: "xpto", } } ] From 7df2bdd3112d3b4213b07afb33106b86011d84d8 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:15:30 -0300 Subject: [PATCH 12/20] blue adapter --- package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index d30d4c26462..133c5a7a632 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7616,9 +7616,9 @@ "dev": true }, "node_modules/caniuse-lite": { - "version": "1.0.30001688", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", - "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==", + "version": "1.0.30001633", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", + "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==", "funding": [ { "type": "opencollective", @@ -33565,9 +33565,9 @@ "dev": true }, "caniuse-lite": { - "version": "1.0.30001688", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001688.tgz", - "integrity": "sha512-Nmqpru91cuABu/DTCXbM2NSRHzM2uVHfPnhJ/1zEAJx/ILBRVmz3pzH4N7DZqbdG0gWClsCC05Oj0mJ/1AWMbA==" + "version": "1.0.30001633", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001633.tgz", + "integrity": "sha512-6sT0yf/z5jqf8tISAgpJDrmwOpLsrpnyCdD/lOZKvKkkJK4Dn0X5i7KF7THEZhOq+30bmhwBlNEaqPUiHiKtZg==" }, "caseless": { "version": "0.12.0", From 7647cc60464a7b98e18d9d559b31cda0c1f1e8c9 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:16:09 -0300 Subject: [PATCH 13/20] blue adapter --- integrationExamples/gpt/hello_world.html | 42 ++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 589d43f9bda..d68e65011be 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -8,7 +8,6 @@ --> - @@ -20,21 +19,18 @@ code: 'div-gpt-ad-1460505748561-0', mediaTypes: { banner: { - sizes: [[300, 250]], + sizes: [[300, 250], [300,600]], } }, // Replace this object to test a new Adapter! bids: [{ - bidder: 'blue', + bidder: 'appnexus', params: { - bidFloor: 0.05, - currency: 'USD', - placementId: 13144370, - publisherId: 13144370 + placementId: 13144370 } }] - }, - ]; + + }]; var pbjs = pbjs || {}; pbjs.que = pbjs.que || []; @@ -44,13 +40,12 @@ - +

Prebid.js Test

+
Div-1
+
+ +
- - \ No newline at end of file + From 51faf456dc26c7da70abe955bca004d6f821a7bf Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:17:34 -0300 Subject: [PATCH 14/20] blue adapter --- integrationExamples/gpt/hello_world.html | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index d68e65011be..345be189d40 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -19,7 +19,7 @@ code: 'div-gpt-ad-1460505748561-0', mediaTypes: { banner: { - sizes: [[300, 250], [300,600]], + sizes: [[300, 250]], } }, // Replace this object to test a new Adapter! @@ -40,7 +40,7 @@ - +

Prebid.js Test

+
Div-1
+
+ +
From 1998e5c9020e1d4b0517c4e8c80af159e12e3932 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:19:04 -0300 Subject: [PATCH 15/20] blue adapter --- integrationExamples/gpt/hello_world.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 345be189d40..89f45e97ef8 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -8,6 +8,7 @@ --> + @@ -22,6 +23,7 @@ sizes: [[300, 250]], } }, + // Replace this object to test a new Adapter! bids: [{ bidder: 'appnexus', @@ -44,7 +46,7 @@ googletag.pubads().disableInitialLoad(); }); - pbjs.que.push(function() { + pbjs.que.push(function () { pbjs.addAdUnits(adUnits); pbjs.requestBids({ bidsBackHandler: sendAdserverRequest, From 53334f3e380dd12e754b564be334901f47e4596d Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:19:46 -0300 Subject: [PATCH 16/20] blue adapter --- integrationExamples/gpt/hello_world.html | 2 ++ 1 file changed, 2 insertions(+) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index 89f45e97ef8..bcf0c2fa1f2 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -48,6 +48,7 @@ pbjs.que.push(function () { pbjs.addAdUnits(adUnits); + pbjs.requestBids({ bidsBackHandler: sendAdserverRequest, timeout: PREBID_TIMEOUT @@ -90,4 +91,5 @@
Div-1
+ From 8e42e5a62c7915cd943cbd3352cd1df25b4b74ae Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:20:08 -0300 Subject: [PATCH 17/20] blue adapter --- integrationExamples/gpt/hello_world.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html index bcf0c2fa1f2..03a2356f0ef 100644 --- a/integrationExamples/gpt/hello_world.html +++ b/integrationExamples/gpt/hello_world.html @@ -92,4 +92,4 @@
Div-1
- + \ No newline at end of file From dacf41ce1226b09283e669164a04e629610d2e59 Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:21:03 -0300 Subject: [PATCH 18/20] blue adapter --- modules/blueBidAdapter.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 5f7c598bd51..7a08e21b9b9 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -28,8 +28,6 @@ function request(buildRequest, imps, bidderRequest, context) { function imp(buildImp, bidRequest, context) { let imp = buildImp(bidRequest, context); - // eslint-disable-next-line no-console - console.log(JSON.stringify(imp, null, 2)); imp.bidfloor = bidRequest.params.bidFloor; imp.bidfloorcur = bidRequest.params.currency; imp.tagid = bidRequest.params.placementId; @@ -43,8 +41,6 @@ export const spec = { // Validate bid request isBidRequestValid: function (bid) { - // eslint-disable-next-line no-console - console.log(bid); return ( !!bid.params.placementId && !!bid.params.publisherId // !!bid.params.params.bidFloor && From 824e59f97eb9980bf91f4963a80195dda4fa2f1e Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:22:30 -0300 Subject: [PATCH 19/20] blue adapter --- modules/blueBidAdapter.js | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 7a08e21b9b9..6bd5177a111 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -16,7 +16,7 @@ const converter = ortbConverter({ ttl: 100, // Default time-to-live for bid responses }, imp, - request + request, }); function request(buildRequest, imps, bidderRequest, context) { @@ -42,22 +42,25 @@ export const spec = { // Validate bid request isBidRequestValid: function (bid) { return ( - !!bid.params.placementId && !!bid.params.publisherId - // !!bid.params.params.bidFloor && - // !!bid.params.params.currency + !!bid.params.placementId && + !!bid.params.publisherId && + !!bid.params.params.bidFloor && + !!bid.params.params.currency ); }, // Build OpenRTB requests using `ortbConverter` buildRequests: function (validBidRequests, bidderRequest) { const context = { - publisherId: validBidRequests.find(bidRequest => bidRequest.params?.publisherId)?.params.publisherId, - } + publisherId: validBidRequests.find( + (bidRequest) => bidRequest.params?.publisherId + )?.params.publisherId, + }; const ortbRequest = converter.toORTB({ bidRequests: validBidRequests, bidderRequest, - context + context, }); // Add GVLID and cookie ID to the request From 2c9cbe4b7dc9f79a1efb9b187c6b0852563947ff Mon Sep 17 00:00:00 2001 From: Tulio Duarte Date: Fri, 13 Dec 2024 15:28:32 -0300 Subject: [PATCH 20/20] blue adapter --- modules/blueBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/blueBidAdapter.js b/modules/blueBidAdapter.js index 6bd5177a111..aab7b51cbd5 100644 --- a/modules/blueBidAdapter.js +++ b/modules/blueBidAdapter.js @@ -44,8 +44,8 @@ export const spec = { return ( !!bid.params.placementId && !!bid.params.publisherId && - !!bid.params.params.bidFloor && - !!bid.params.params.currency + !!bid.params.bidFloor && + !!bid.params.currency ); },