From 6545a9c1b4a0a3c97751b9075a3136a93b076f8f Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Fri, 2 May 2025 12:13:48 +0530 Subject: [PATCH 01/29] RM-845 : Initial implementation for risemediatech bid adapter --- modules/risemediatechBidAdapter.js | 129 +++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 modules/risemediatechBidAdapter.js diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js new file mode 100644 index 00000000000..554ce38ac1a --- /dev/null +++ b/modules/risemediatechBidAdapter.js @@ -0,0 +1,129 @@ +import { registerBidder } from '../src/adapters/bidderFactory.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; + +const BIDDER_CODE = 'risemediatech'; +const ENDPOINT_URL = 'http://localhost:8082/ads/rtb/prebid/js'; +const SYNC_URL_IFRAME = 'https://sync.risemediatech.com/iframe'; +const SYNC_URL_IMAGE = 'https://sync.risemediatech.com/image'; +const DEFAULT_CURRENCY = 'USD'; +const DEFAULT_TTL = 300; + +const converter = ortbConverter({ + context: { + netRevenue: true, + ttl: DEFAULT_TTL, + currency: DEFAULT_CURRENCY, + }, + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + const { mediaTypes } = bidRequest; + + if (mediaTypes[BANNER]) { + imp.banner = { format: mediaTypes[BANNER].sizes.map(([w, h]) => ({ w, h })) }; + } else if (mediaTypes[VIDEO]) { + imp.video = { ...mediaTypes[VIDEO] }; + } + + return imp; + }, + request(buildRequest, imps, bidderRequest, context) { + const request = buildRequest(imps, bidderRequest, context); + request.cur = [DEFAULT_CURRENCY]; + request.tmax = bidderRequest.timeout; + request.test = bidderRequest.test || 0; + + if (bidderRequest.gdprConsent) { + request.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; + request.user = { ext: { consent: bidderRequest.gdprConsent.consentString } }; + } + + if (bidderRequest.uspConsent) { + request.regs = request.regs || {}; + request.regs.ext = request.regs.ext || {}; + request.regs.ext.us_privacy = bidderRequest.uspConsent; + } + + return request; + }, + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + bidResponse.meta = bidResponse.meta || {}; + bidResponse.meta.advertiserDomains = bid.adomain || []; + return bidResponse; + }, +}); + +/** + * Validates the bid request. + * @param {Object} bid - The bid request object. + * @returns {boolean} True if the bid request is valid. + */ +const isBidRequestValid = (bid) => { + return !!bid.params?.placementId; +}; + +/** + * Builds the server request for the bid. + * @param {Array} validBidRequests - Array of valid bid requests. + * @param {Object} bidderRequest - Additional information about the bid request. + * @returns {Object} Server request object. + */ +const buildRequests = (validBidRequests, bidderRequest) => { + const request = converter.toORTB({ bidRequests: validBidRequests, bidderRequest }); + return { + method: 'POST', + url: ENDPOINT_URL, + data: request, + }; +}; + +/** + * Interprets the server response and extracts bid information. + * @param {Object} serverResponse - The response from the server. + * @param {Object} request - The original request sent to the server. + * @returns {Array} Array of bid objects. + */ +const interpretResponse = (serverResponse, request) => { + const { bids } = converter.fromORTB({ response: serverResponse.body, request: request.data }); + return bids; +}; + +/** + * Handles user syncs for GDPR, CCPA, and GPP compliance. + * @param {Object} syncOptions - Options for user sync. + * @param {Array} serverResponses - Server responses. + * @param {Object} gdprConsent - GDPR consent information. + * @param {Object} uspConsent - CCPA consent information. + * @param {Object} gppConsent - GPP consent information. + * @returns {Array} Array of user sync objects. + */ +const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { + const type = syncOptions.iframeEnabled ? 'iframe' : 'image'; + let url = type === 'iframe' ? SYNC_URL_IFRAME : SYNC_URL_IMAGE; + + if (gdprConsent?.consentString) { + url += `?gdpr=${Number(gdprConsent.gdprApplies || 0)}&gdpr_consent=${gdprConsent.consentString}`; + } + + if (uspConsent) { + url += `&us_privacy=${uspConsent}`; + } + + if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { + url += `&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections.join(',')}`; + } + + return [{ type, url }]; +}; + +export const spec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid, + buildRequests, + interpretResponse, + getUserSyncs, +}; + +registerBidder(spec); \ No newline at end of file From 7ba98f5d66d875ece39bf9afd3e4fe8086d23258 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Sun, 4 May 2025 19:33:50 +0530 Subject: [PATCH 02/29] RM-845 : Added bidder parameter documentation for risemediatech Bid Adapter --- modules/risemediatechBidAdapter.md | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 modules/risemediatechBidAdapter.md diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md new file mode 100644 index 00000000000..40a2e201c33 --- /dev/null +++ b/modules/risemediatechBidAdapter.md @@ -0,0 +1,63 @@ +# Overview + +Module Name : RisemediaTech Bidder Adapter +Module Type : Bid Adapter +Maintainer : prebid@risemediatech.io + +# Description +Connects to RisemediaTech Exchange for bids +RisemediaTech supports Display & Video(Instream) currently. + +# Sample Ad Unit : Banner +``` + var adUnits = [ + { + code: 'test-banner-div', + mediatypes: { + banner: { + sizes:[ + [300,250] + ] + } + }, + bids:[ + { + bidder: 'risemediatech', + params: { + placementId: 1452398, + publisherId: p-1489231, + floorPrice: 0.5, + currency: 'USD', + domain: 'exampleDomain.com', + pageUrl: 'https://exampleDomain.com/ad' + } + } + ] + } + ] +``` + +# Sample Ad Unit : Video +``` + var videoAdUnit = [ + { + code: 'risemediatech', + mediatypes: { + video: { + playerSize: [640, 480], // required + context: 'instream' + } + }, + bids:[ + { + mimes: ['video/mp4','video/webm'], + minduration: 5, + maxduration: 30, + startdelay: 30, + maxseq: 2, + poddur: 30, + protocols: [1,3,4] + } + ] + } + ] From 994737c8170c6056e16f0b7a9aeb5e4aaf4984d5 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Sun, 4 May 2025 19:34:19 +0530 Subject: [PATCH 03/29] RM-845 : minor modifications --- modules/risemediatechBidAdapter.js | 59 +++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 554ce38ac1a..c7a7d489ab6 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -16,29 +16,44 @@ const converter = ortbConverter({ currency: DEFAULT_CURRENCY, }, imp(buildImp, bidRequest, context) { + console.log('Building impression object for bidRequest:', bidRequest); const imp = buildImp(bidRequest, context); const { mediaTypes } = bidRequest; if (mediaTypes[BANNER]) { + console.log('Adding banner media type to impression:', mediaTypes[BANNER]); imp.banner = { format: mediaTypes[BANNER].sizes.map(([w, h]) => ({ w, h })) }; } else if (mediaTypes[VIDEO]) { - imp.video = { ...mediaTypes[VIDEO] }; + console.log('Adding video media type to impression:', mediaTypes[VIDEO]); + imp.video = { + ...mediaTypes[VIDEO], + mimes: bidRequest.params.mimes, + minduration: bidRequest.params.minduration, + maxduration: bidRequest.params.maxduration, + startdelay: bidRequest.params.startdelay, + maxseq: bidRequest.params.maxseq, + poddur: bidRequest.params.poddur, + protocols: bidRequest.params.protocols + }; } return imp; }, request(buildRequest, imps, bidderRequest, context) { + console.log('Building server request with impressions:', imps); const request = buildRequest(imps, bidderRequest, context); request.cur = [DEFAULT_CURRENCY]; request.tmax = bidderRequest.timeout; request.test = bidderRequest.test || 0; if (bidderRequest.gdprConsent) { + console.log('Adding GDPR consent information to request:', bidderRequest.gdprConsent); request.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; request.user = { ext: { consent: bidderRequest.gdprConsent.consentString } }; } if (bidderRequest.uspConsent) { + console.log('Adding USP consent information to request:', bidderRequest.uspConsent); request.regs = request.regs || {}; request.regs.ext = request.regs.ext || {}; request.regs.ext.us_privacy = bidderRequest.uspConsent; @@ -47,6 +62,7 @@ const converter = ortbConverter({ return request; }, bidResponse(buildBidResponse, bid, context) { + console.log('Building bid response for bid:', bid); const bidResponse = buildBidResponse(bid, context); bidResponse.meta = bidResponse.meta || {}; bidResponse.meta.advertiserDomains = bid.adomain || []; @@ -60,7 +76,28 @@ const converter = ortbConverter({ * @returns {boolean} True if the bid request is valid. */ const isBidRequestValid = (bid) => { - return !!bid.params?.placementId; + console.log('Validating bid request:', bid); + const { mediaTypes } = bid; + + if (mediaTypes?.[VIDEO]) { + const video = mediaTypes[VIDEO]; + + // Validate required fields for Video + if (!video.mimes || !Array.isArray(video.mimes) || video.mimes.length === 0) { + console.warn('Invalid video bid request: Missing or invalid mimes.'); + return false; + } + if (video.w != null && video.w <= 0) { + console.warn('Invalid video bid request: Invalid width.'); + return false; + } + if (video.h != null && video.h <= 0) { + console.warn('Invalid video bid request: Invalid height.'); + return false; + } + } + + return true; }; /** @@ -70,6 +107,7 @@ const isBidRequestValid = (bid) => { * @returns {Object} Server request object. */ const buildRequests = (validBidRequests, bidderRequest) => { + console.log('Building server request for valid bid requests:', validBidRequests); const request = converter.toORTB({ bidRequests: validBidRequests, bidderRequest }); return { method: 'POST', @@ -85,7 +123,20 @@ const buildRequests = (validBidRequests, bidderRequest) => { * @returns {Array} Array of bid objects. */ const interpretResponse = (serverResponse, request) => { + console.log('Interpreting server response:', serverResponse); + + if (!serverResponse || !serverResponse.body) { + console.warn('Server response is empty or invalid.'); + return []; + } + const { bids } = converter.fromORTB({ response: serverResponse.body, request: request.data }); + + if (!bids || !Array.isArray(bids)) { + console.warn('No valid bids found in server response.'); + return []; + } + return bids; }; @@ -99,18 +150,22 @@ const interpretResponse = (serverResponse, request) => { * @returns {Array} Array of user sync objects. */ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { + console.log('Handling user syncs with options:', syncOptions); const type = syncOptions.iframeEnabled ? 'iframe' : 'image'; let url = type === 'iframe' ? SYNC_URL_IFRAME : SYNC_URL_IMAGE; if (gdprConsent?.consentString) { + console.log('Adding GDPR consent information to user sync URL:', gdprConsent); url += `?gdpr=${Number(gdprConsent.gdprApplies || 0)}&gdpr_consent=${gdprConsent.consentString}`; } if (uspConsent) { + console.log('Adding USP consent information to user sync URL:', uspConsent); url += `&us_privacy=${uspConsent}`; } if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { + console.log('Adding GPP consent information to user sync URL:', gppConsent); url += `&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections.join(',')}`; } From 21e69ac929b1aba8e9955d72f201d6a27973e1b2 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 8 May 2025 11:26:00 +0530 Subject: [PATCH 04/29] RM-845 : Handled es lint errors --- modules/risemediatechBidAdapter.js | 45 +++++++++++++++--------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index c7a7d489ab6..a6388e75c97 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -1,6 +1,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; +import { logInfo, logWarn } from '../src/utils.js'; const BIDDER_CODE = 'risemediatech'; const ENDPOINT_URL = 'http://localhost:8082/ads/rtb/prebid/js'; @@ -16,16 +17,16 @@ const converter = ortbConverter({ currency: DEFAULT_CURRENCY, }, imp(buildImp, bidRequest, context) { - console.log('Building impression object for bidRequest:', bidRequest); + logInfo('Building impression object for bidRequest:', bidRequest); const imp = buildImp(bidRequest, context); const { mediaTypes } = bidRequest; if (mediaTypes[BANNER]) { - console.log('Adding banner media type to impression:', mediaTypes[BANNER]); + logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); imp.banner = { format: mediaTypes[BANNER].sizes.map(([w, h]) => ({ w, h })) }; } else if (mediaTypes[VIDEO]) { - console.log('Adding video media type to impression:', mediaTypes[VIDEO]); - imp.video = { + logInfo('Adding video media type to impression:', mediaTypes[VIDEO]); + imp.video = { ...mediaTypes[VIDEO], mimes: bidRequest.params.mimes, minduration: bidRequest.params.minduration, @@ -33,27 +34,27 @@ const converter = ortbConverter({ startdelay: bidRequest.params.startdelay, maxseq: bidRequest.params.maxseq, poddur: bidRequest.params.poddur, - protocols: bidRequest.params.protocols + protocols: bidRequest.params.protocols }; } return imp; }, request(buildRequest, imps, bidderRequest, context) { - console.log('Building server request with impressions:', imps); + logInfo('Building server request with impressions:', imps); const request = buildRequest(imps, bidderRequest, context); request.cur = [DEFAULT_CURRENCY]; request.tmax = bidderRequest.timeout; request.test = bidderRequest.test || 0; if (bidderRequest.gdprConsent) { - console.log('Adding GDPR consent information to request:', bidderRequest.gdprConsent); + logInfo('Adding GDPR consent information to request:', bidderRequest.gdprConsent); request.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; request.user = { ext: { consent: bidderRequest.gdprConsent.consentString } }; } if (bidderRequest.uspConsent) { - console.log('Adding USP consent information to request:', bidderRequest.uspConsent); + logInfo('Adding USP consent information to request:', bidderRequest.uspConsent); request.regs = request.regs || {}; request.regs.ext = request.regs.ext || {}; request.regs.ext.us_privacy = bidderRequest.uspConsent; @@ -62,7 +63,7 @@ const converter = ortbConverter({ return request; }, bidResponse(buildBidResponse, bid, context) { - console.log('Building bid response for bid:', bid); + logInfo('Building bid response for bid:', bid); const bidResponse = buildBidResponse(bid, context); bidResponse.meta = bidResponse.meta || {}; bidResponse.meta.advertiserDomains = bid.adomain || []; @@ -76,7 +77,7 @@ const converter = ortbConverter({ * @returns {boolean} True if the bid request is valid. */ const isBidRequestValid = (bid) => { - console.log('Validating bid request:', bid); + logInfo('Validating bid request:', bid); const { mediaTypes } = bid; if (mediaTypes?.[VIDEO]) { @@ -84,15 +85,15 @@ const isBidRequestValid = (bid) => { // Validate required fields for Video if (!video.mimes || !Array.isArray(video.mimes) || video.mimes.length === 0) { - console.warn('Invalid video bid request: Missing or invalid mimes.'); + logWarn('Invalid video bid request: Missing or invalid mimes.'); return false; } if (video.w != null && video.w <= 0) { - console.warn('Invalid video bid request: Invalid width.'); + logWarn('Invalid video bid request: Invalid width.'); return false; } if (video.h != null && video.h <= 0) { - console.warn('Invalid video bid request: Invalid height.'); + logWarn('Invalid video bid request: Invalid height.'); return false; } } @@ -107,7 +108,7 @@ const isBidRequestValid = (bid) => { * @returns {Object} Server request object. */ const buildRequests = (validBidRequests, bidderRequest) => { - console.log('Building server request for valid bid requests:', validBidRequests); + logInfo('Building server request for valid bid requests:', validBidRequests); const request = converter.toORTB({ bidRequests: validBidRequests, bidderRequest }); return { method: 'POST', @@ -123,17 +124,17 @@ const buildRequests = (validBidRequests, bidderRequest) => { * @returns {Array} Array of bid objects. */ const interpretResponse = (serverResponse, request) => { - console.log('Interpreting server response:', serverResponse); + logInfo('Interpreting server response:', serverResponse); if (!serverResponse || !serverResponse.body) { - console.warn('Server response is empty or invalid.'); + logWarn('Server response is empty or invalid.'); return []; } const { bids } = converter.fromORTB({ response: serverResponse.body, request: request.data }); if (!bids || !Array.isArray(bids)) { - console.warn('No valid bids found in server response.'); + logWarn('No valid bids found in server response.'); return []; } @@ -150,22 +151,22 @@ const interpretResponse = (serverResponse, request) => { * @returns {Array} Array of user sync objects. */ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { - console.log('Handling user syncs with options:', syncOptions); + logInfo('Handling user syncs with options:', syncOptions); const type = syncOptions.iframeEnabled ? 'iframe' : 'image'; let url = type === 'iframe' ? SYNC_URL_IFRAME : SYNC_URL_IMAGE; if (gdprConsent?.consentString) { - console.log('Adding GDPR consent information to user sync URL:', gdprConsent); + logInfo('Adding GDPR consent information to user sync URL:', gdprConsent); url += `?gdpr=${Number(gdprConsent.gdprApplies || 0)}&gdpr_consent=${gdprConsent.consentString}`; } if (uspConsent) { - console.log('Adding USP consent information to user sync URL:', uspConsent); + logInfo('Adding USP consent information to user sync URL:', uspConsent); url += `&us_privacy=${uspConsent}`; } if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { - console.log('Adding GPP consent information to user sync URL:', gppConsent); + logInfo('Adding GPP consent information to user sync URL:', gppConsent); url += `&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections.join(',')}`; } @@ -181,4 +182,4 @@ export const spec = { getUserSyncs, }; -registerBidder(spec); \ No newline at end of file +registerBidder(spec); From bc0dbf6ef503b4977313f8df03f7061056d7d1aa Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 8 May 2025 20:20:34 +0530 Subject: [PATCH 05/29] RM-847 : Unit Test for Risemediatech Bid Adapter --- test/spec/modules/risemediaBidAdapter_spec.js | 157 ++++++++++++++++++ 1 file changed, 157 insertions(+) create mode 100644 test/spec/modules/risemediaBidAdapter_spec.js diff --git a/test/spec/modules/risemediaBidAdapter_spec.js b/test/spec/modules/risemediaBidAdapter_spec.js new file mode 100644 index 00000000000..61bffea7cd8 --- /dev/null +++ b/test/spec/modules/risemediaBidAdapter_spec.js @@ -0,0 +1,157 @@ +import { expect } from 'chai'; +import { spec } from 'modules/risemediatechBidAdapter.js'; + +describe('RiseMediaTech adapter', () => { + const validBidRequest = { + bidder: 'risemediatech', + params: { + publisherId: '12345', + adSlot: '/1234567/adunit', + }, + mediaTypes: { + banner: { + sizes: [[300, 250], [728, 90]], + }, + }, + bidId: '1abc', + auctionId: '2def', + }; + + const bidderRequest = { + refererInfo: { + page: 'https://example.com', + }, + timeout: 3000, + gdprConsent: { + gdprApplies: true, + consentString: 'consent123', + }, + uspConsent: '1YNN', + }; + + const serverResponse = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'], + }, + ], + }, + ], + }, + }; + + describe('isBidRequestValid', () => { + it('should return true for valid bid request', () => { + expect(spec.isBidRequestValid(validBidRequest)).to.equal(true); + }); + + it('should return false if publisherId is missing', () => { + const invalidBidRequest = { ...validBidRequest }; + delete invalidBidRequest.params.publisherId; + expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); + }); + + it('should return false if adSlot is missing', () => { + const invalidBidRequest = { ...validBidRequest }; + delete invalidBidRequest.params.adSlot; + expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); + }); + + it('should return false for invalid video bid request', () => { + const invalidVideoRequest = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: [], + }, + }, + }; + expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); + }); + }); + + describe('buildRequests', () => { + it('should build a valid server request', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + expect(request).to.be.an('object'); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal('http://localhost:8082/ads/rtb/prebid/js'); + expect(request.data).to.be.an('object'); + }); + + it('should include GDPR and USP consent in the request', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const { regs, user } = request.data; + expect(regs.ext).to.have.property('gdpr', 1); + expect(user.ext).to.have.property('consent', 'consent123'); + expect(regs.ext).to.have.property('us_privacy', '1YNN'); + }); + + it('should include banner impressions in the request', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const { imp } = request.data; + expect(imp).to.be.an('array'); + expect(imp[0]).to.have.property('banner'); + expect(imp[0].banner).to.have.property('format').with.lengthOf(2); + }); + }); + + describe('interpretResponse', () => { + it('should interpret the server response correctly', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.an('array').with.lengthOf(1); + const bid = bids[0]; + expect(bid).to.have.property('requestId', '1abc'); + expect(bid).to.have.property('cpm', 1.5); + expect(bid).to.have.property('width', 300); + expect(bid).to.have.property('height', 250); + expect(bid).to.have.property('creativeId', 'creative123'); + expect(bid).to.have.property('currency', 'USD'); + expect(bid).to.have.property('netRevenue', true); + expect(bid).to.have.property('ttl', 300); + }); + + it('should return an empty array if no bids are present', () => { + const emptyResponse = { body: { seatbid: [] } }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(emptyResponse, request); + expect(bids).to.be.an('array').with.lengthOf(0); + }); + }); + + describe('getUserSyncs', () => { + it('should return iframe sync if iframeEnabled is true', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); + expect(syncs).to.be.an('array').with.lengthOf(1); + expect(syncs[0]).to.have.property('type', 'iframe'); + expect(syncs[0]).to.have.property('url').that.includes('https://sync.risemediatech.com/iframe'); + }); + + it('should return image sync if iframeEnabled is false', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: false }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); + expect(syncs).to.be.an('array').with.lengthOf(1); + expect(syncs[0]).to.have.property('type', 'image'); + expect(syncs[0]).to.have.property('url').that.includes('https://sync.risemediatech.com/image'); + }); + + it('should include GDPR and USP consent in the sync URL', () => { + const syncs = spec.getUserSyncs({ iframeEnabled: true }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); + const syncUrl = syncs[0].url; + expect(syncUrl).to.include('gdpr=1'); + expect(syncUrl).to.include('gdpr_consent=consent123'); + expect(syncUrl).to.include('us_privacy=1YNN'); + }); + }); +}); \ No newline at end of file From 04fc23dd71d1dd17e12af8b4fa1f7aeb36f94e58 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 14 May 2025 11:04:51 +0530 Subject: [PATCH 06/29] Updated unit tests --- modules/risemediatechBidAdapter.js | 39 ++++- test/spec/modules/risemediaBidAdapter_spec.js | 156 +++++++++++++++++- 2 files changed, 189 insertions(+), 6 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index a6388e75c97..7d3fdb94599 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -78,12 +78,19 @@ const converter = ortbConverter({ */ const isBidRequestValid = (bid) => { logInfo('Validating bid request:', bid); + + // Validate params + if (!bid.params || !bid.params.publisherId || !bid.params.adSlot) { + logWarn('Invalid bid request: Missing required params (publisherId or adSlot).'); + return false; + } + const { mediaTypes } = bid; + // Validate video-specific fields if mediaTypes includes VIDEO if (mediaTypes?.[VIDEO]) { const video = mediaTypes[VIDEO]; - // Validate required fields for Video if (!video.mimes || !Array.isArray(video.mimes) || video.mimes.length === 0) { logWarn('Invalid video bid request: Missing or invalid mimes.'); return false; @@ -133,12 +140,34 @@ const interpretResponse = (serverResponse, request) => { const { bids } = converter.fromORTB({ response: serverResponse.body, request: request.data }); - if (!bids || !Array.isArray(bids)) { - logWarn('No valid bids found in server response.'); - return []; + if (bids && Array.isArray(bids) && bids.length > 0) { + return bids; } - return bids; + // Fallback: manually parse OpenRTB response + const resp = serverResponse.body; + if (!resp.seatbid || !Array.isArray(resp.seatbid)) return []; + + const result = []; + resp.seatbid.forEach(seat => { + if (seat.bid && Array.isArray(seat.bid)) { + seat.bid.forEach(bid => { + result.push({ + requestId: bid.impid, + cpm: bid.price, + width: bid.w, + height: bid.h, + creativeId: bid.crid || bid.id, + currency: DEFAULT_CURRENCY, + netRevenue: true, + ttl: DEFAULT_TTL, + ad: bid.adm, + meta: { advertiserDomains: bid.adomain || [] } + }); + }); + } + }); + return result; }; /** diff --git a/test/spec/modules/risemediaBidAdapter_spec.js b/test/spec/modules/risemediaBidAdapter_spec.js index 61bffea7cd8..9a83ab4489a 100644 --- a/test/spec/modules/risemediaBidAdapter_spec.js +++ b/test/spec/modules/risemediaBidAdapter_spec.js @@ -79,6 +79,49 @@ describe('RiseMediaTech adapter', () => { }; expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); }); + + // Add to: describe('isBidRequestValid', ...) + it('should return false for video bid request with missing mimes', () => { + const invalidVideoRequest = { + ...validBidRequest, + mediaTypes: { + video: { + w: 640, + h: 480 + // mimes missing + } + } + }; + expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); + }); + + it('should return false for video bid request with invalid width', () => { + const invalidVideoRequest = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: ['video/mp4'], + w: 0, + h: 480 + } + } + }; + expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); + }); + + it('should return false for video bid request with invalid height', () => { + const invalidVideoRequest = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: ['video/mp4'], + w: 640, + h: 0 + } + } + }; + expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); + }); }); describe('buildRequests', () => { @@ -105,6 +148,71 @@ describe('RiseMediaTech adapter', () => { expect(imp[0]).to.have.property('banner'); expect(imp[0].banner).to.have.property('format').with.lengthOf(2); }); + + it('should set request.test to 0 if bidderRequest.test is not provided', () => { + const request = spec.buildRequests([validBidRequest], { ...bidderRequest }); + expect(request.data.test).to.equal(0); + }); + + it('should set request.test to bidderRequest.test if provided', () => { + const testBidderRequest = { ...bidderRequest, test: 1 }; + const request = spec.buildRequests([validBidRequest], testBidderRequest); + expect(request.data.test).to.equal(1); + }); + + it('should build a video impression if only video mediaType is present', () => { + const videoBidRequest = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: ['video/mp4'], + w: 640, + h: 480 + } + }, + params: { + ...validBidRequest.params, + mimes: ['video/mp4'], + minduration: 5, + maxduration: 30, + startdelay: 0, + maxseq: 1, + poddur: 60, + protocols: [2, 3] + } + }; + const request = spec.buildRequests([videoBidRequest], bidderRequest); + const { imp } = request.data; + expect(imp[0]).to.have.property('video'); + expect(imp[0]).to.not.have.property('banner'); + expect(imp[0].video).to.include({ w: 640, h: 480 }); + expect(imp[0].video.mimes).to.include('video/mp4'); + }); + + it('should set gdpr to 0 if gdprApplies is false', () => { + const noGdprBidderRequest = { + ...bidderRequest, + gdprConsent: { + gdprApplies: false, + consentString: 'consent123' + } + }; + const request = spec.buildRequests([validBidRequest], noGdprBidderRequest); + expect(request.data.regs.ext).to.have.property('gdpr', 0); + expect(request.data.user.ext).to.have.property('consent', 'consent123'); + }); + + it('should set regs and regs.ext to {} if not already set when only USP consent is present', () => { + const onlyUspBidderRequest = { + ...bidderRequest, + gdprConsent: undefined, + uspConsent: '1YNN' + }; + const request = spec.buildRequests([validBidRequest], onlyUspBidderRequest); + expect(request.data.regs).to.be.an('object'); + expect(request.data.regs.ext).to.be.an('object'); + expect(request.data.regs.ext).to.have.property('us_privacy', '1YNN'); + }); }); describe('interpretResponse', () => { @@ -129,6 +237,52 @@ describe('RiseMediaTech adapter', () => { const bids = spec.interpretResponse(emptyResponse, request); expect(bids).to.be.an('array').with.lengthOf(0); }); + + + it('should set meta.advertiserDomains to an empty array if adomain is missing', () => { + const responseWithoutAdomain = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123' + // adomain is missing + } + ] + } + ] + } + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(responseWithoutAdomain, request); + expect(bids[0].meta.advertiserDomains).to.be.an('array').that.is.empty; + }); + + it('should return an empty array and warn if server response is undefined', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(undefined, request); + expect(bids).to.be.an('array').that.is.empty; + }); + + it('should return an empty array and warn if server response body is missing', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse({}, request); + expect(bids).to.be.an('array').that.is.empty; + }); + + it('should return bids from converter if present', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(serverResponse, request); + expect(bids).to.be.an('array').with.lengthOf(1); + }); }); describe('getUserSyncs', () => { @@ -154,4 +308,4 @@ describe('RiseMediaTech adapter', () => { expect(syncUrl).to.include('us_privacy=1YNN'); }); }); -}); \ No newline at end of file +}); From 1dbbfb9047cf73265f90810f7df4831a7a5017b2 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Mon, 26 May 2025 11:16:44 +0530 Subject: [PATCH 07/29] Modified the bid adapter code and unit tests --- modules/risemediatechBidAdapter.js | 89 +++++++----- test/spec/modules/risemediaBidAdapter_spec.js | 136 +++++++++++++++++- 2 files changed, 186 insertions(+), 39 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 7d3fdb94599..fb9dd3a028a 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -62,13 +62,6 @@ const converter = ortbConverter({ return request; }, - bidResponse(buildBidResponse, bid, context) { - logInfo('Building bid response for bid:', bid); - const bidResponse = buildBidResponse(bid, context); - bidResponse.meta = bidResponse.meta || {}; - bidResponse.meta.advertiserDomains = bid.adomain || []; - return bidResponse; - }, }); /** @@ -80,7 +73,7 @@ const isBidRequestValid = (bid) => { logInfo('Validating bid request:', bid); // Validate params - if (!bid.params || !bid.params.publisherId || !bid.params.adSlot) { + if (!bid.params || !bid.params.publisherId) { logWarn('Invalid bid request: Missing required params (publisherId or adSlot).'); return false; } @@ -117,6 +110,7 @@ const isBidRequestValid = (bid) => { const buildRequests = (validBidRequests, bidderRequest) => { logInfo('Building server request for valid bid requests:', validBidRequests); const request = converter.toORTB({ bidRequests: validBidRequests, bidderRequest }); + logInfo('Converted to ORTB request:', request); return { method: 'POST', url: ENDPOINT_URL, @@ -133,41 +127,60 @@ const buildRequests = (validBidRequests, bidderRequest) => { const interpretResponse = (serverResponse, request) => { logInfo('Interpreting server response:', serverResponse); - if (!serverResponse || !serverResponse.body) { - logWarn('Server response is empty or invalid.'); + const bidResp = serverResponse && serverResponse.body; + if (!bidResp || !Array.isArray(bidResp.seatbid)) { + logWarn('Server response is empty, invalid, or does not contain seatbid array.'); return []; } - const { bids } = converter.fromORTB({ response: serverResponse.body, request: request.data }); - - if (bids && Array.isArray(bids) && bids.length > 0) { - return bids; - } - - // Fallback: manually parse OpenRTB response - const resp = serverResponse.body; - if (!resp.seatbid || !Array.isArray(resp.seatbid)) return []; - - const result = []; - resp.seatbid.forEach(seat => { - if (seat.bid && Array.isArray(seat.bid)) { - seat.bid.forEach(bid => { - result.push({ - requestId: bid.impid, - cpm: bid.price, - width: bid.w, - height: bid.h, - creativeId: bid.crid || bid.id, - currency: DEFAULT_CURRENCY, - netRevenue: true, - ttl: DEFAULT_TTL, - ad: bid.adm, - meta: { advertiserDomains: bid.adomain || [] } - }); - }); + const responses = []; + bidResp.seatbid.forEach(seatbid => { + if (Array.isArray(seatbid.bid) && seatbid.bid.length > 0) { + const bid = seatbid.bid[0]; + logInfo('Processing bid response:', bid); + const bidResponse = { + requestId: bid.impid, + cpm: bid.price, + currency: bidResp.cur || DEFAULT_CURRENCY, + width: bid.w, + height: bid.h, + ad: bid.adm, + creativeId: bid.crid, + netRevenue: true, + ttl: DEFAULT_TTL, + meta: { + advertiserDomains: bid.adomain || [], + } + } + + //Set media type based on bid.mtype + if (bid.mtype == null) { + logWarn('Bid response does not contain media type for bidId: ', bid.id); + bidResponse.meta.mediaType = BANNER; + } + switch (bid.mtype) { + case 1: + bidResponse.meta.mediaType = BANNER; + break; + case 2: + bidResponse.meta.mediaType = VIDEO; + break; + default: + logWarn('Unknown media type: ', bid.mtype, ' for bidId: ', bid.id); + break; + } + + //set dealId if present + if (bid.dealid) { + bidResponse.dealId = bid.dealid; + } + logInfo('Interpreted response:', bidResponse, ' for bidId: ', bid.id); + responses.push(bidResponse); } }); - return result; + + logInfo('Interpreted bid responses:', responses); + return responses; }; /** diff --git a/test/spec/modules/risemediaBidAdapter_spec.js b/test/spec/modules/risemediaBidAdapter_spec.js index 9a83ab4489a..09015f48d24 100644 --- a/test/spec/modules/risemediaBidAdapter_spec.js +++ b/test/spec/modules/risemediaBidAdapter_spec.js @@ -80,7 +80,6 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); }); - // Add to: describe('isBidRequestValid', ...) it('should return false for video bid request with missing mimes', () => { const invalidVideoRequest = { ...validBidRequest, @@ -95,6 +94,65 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(invalidVideoRequest)).to.equal(false); }); + it('should return false for video request with invalid mimes (not an array)', () => { + const invalidBid = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: 'video/mp4', // Not an array + w: 640, + h: 480 + } + } + }; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + it('should return false for video request with empty mimes array', () => { + const invalidBid = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: [], + w: 640, + h: 480 + } + } + }; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + + it('should return false for video request with width <= 0', () => { + const invalidBid = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: ['video/mp4'], + w: 0, + h: 480 + } + } + }; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + + it('should return false for video request with height <= 0', () => { + const invalidBid = { + ...validBidRequest, + mediaTypes: { + video: { + mimes: ['video/mp4'], + w: 640, + h: -10 + } + } + }; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + it('should return false for video bid request with invalid width', () => { const invalidVideoRequest = { ...validBidRequest, @@ -238,6 +296,82 @@ describe('RiseMediaTech adapter', () => { expect(bids).to.be.an('array').with.lengthOf(0); }); + it('should interpret multiple seatbids as multiple bids', () => { + const multiSeatbidResponse = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad1
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'], + mtype: 1 + }, + ], + }, + { + bid: [ + { + id: '2bcd', + impid: '2bcd', + price: 2.0, + adm: '
Ad2
', + w: 728, + h: 90, + crid: 'creative456', + adomain: ['another.com'], + mtype: 2 + }, + ], + }, + ], + }, + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(multiSeatbidResponse, request); + expect(bids).to.be.an('array').with.lengthOf(2); + expect(bids[0]).to.have.property('requestId', '1abc'); + expect(bids[1]).to.have.property('requestId', '2bcd'); + expect(bids[0].meta.mediaType).to.equal('banner'); + expect(bids[1].meta.mediaType).to.equal('video'); + expect(bids[0]).to.have.property('cpm', 1.5); + expect(bids[1]).to.have.property('cpm', 2.0); + }); + + it('should set meta.mediaType to banner if mtype is missing', () => { + const responseNoMtype = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'] + // mtype missing + } + ] + } + ] + } + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(responseNoMtype, request); + expect(bids[0].meta.mediaType).to.equal('banner'); + }); it('should set meta.advertiserDomains to an empty array if adomain is missing', () => { const responseWithoutAdomain = { From eeadcc4c0cc7d27266d56773de37db1ca3cd40e9 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Fri, 30 May 2025 10:50:39 +0530 Subject: [PATCH 08/29] Modified prebid js code to remove validations and also added bidfloor to the request. --- modules/risemediatechBidAdapter.js | 23 ++++++++++++++--------- modules/risemediatechBidAdapter.md | 2 +- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index fb9dd3a028a..57afab43de5 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -20,7 +20,10 @@ const converter = ortbConverter({ logInfo('Building impression object for bidRequest:', bidRequest); const imp = buildImp(bidRequest, context); const { mediaTypes } = bidRequest; - + if (bid.params && bid.params.bidfloor) { + logInfo('Setting bid floor for impression:', bid.params.bidfloor); + imp.bidfloor = bid.params.bidfloor; + } if (mediaTypes[BANNER]) { logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); imp.banner = { format: mediaTypes[BANNER].sizes.map(([w, h]) => ({ w, h })) }; @@ -72,11 +75,11 @@ const converter = ortbConverter({ const isBidRequestValid = (bid) => { logInfo('Validating bid request:', bid); - // Validate params - if (!bid.params || !bid.params.publisherId) { - logWarn('Invalid bid request: Missing required params (publisherId or adSlot).'); - return false; - } + // // Validate params + // if (!bid.params || !bid.params.publisherId) { + // logWarn('Invalid bid request: Missing required params (publisherId or adSlot).'); + // return false; + // } const { mediaTypes } = bid; @@ -153,7 +156,7 @@ const interpretResponse = (serverResponse, request) => { } } - //Set media type based on bid.mtype + // Set media type based on bid.mtype if (bid.mtype == null) { logWarn('Bid response does not contain media type for bidId: ', bid.id); bidResponse.meta.mediaType = BANNER; @@ -170,7 +173,7 @@ const interpretResponse = (serverResponse, request) => { break; } - //set dealId if present + // set dealId if present if (bid.dealid) { bidResponse.dealId = bid.dealid; } @@ -212,7 +215,9 @@ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gpp url += `&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections.join(',')}`; } - return [{ type, url }]; + // return [{ type, url }]; + logInfo('User syncs are not implemented in this adapter.'); + return null; }; export const spec = { diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 40a2e201c33..ada04ed7b1e 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -26,7 +26,7 @@ RisemediaTech supports Display & Video(Instream) currently. params: { placementId: 1452398, publisherId: p-1489231, - floorPrice: 0.5, + bidfloor: 0.5, currency: 'USD', domain: 'exampleDomain.com', pageUrl: 'https://exampleDomain.com/ad' From 30ad662f83e4666fee89b036f5e583485fd1045d Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Fri, 30 May 2025 17:29:30 +0530 Subject: [PATCH 09/29] added the vastxml field in the response for the video media type --- modules/risemediatechBidAdapter.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 57afab43de5..28525e38e0b 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -20,9 +20,9 @@ const converter = ortbConverter({ logInfo('Building impression object for bidRequest:', bidRequest); const imp = buildImp(bidRequest, context); const { mediaTypes } = bidRequest; - if (bid.params && bid.params.bidfloor) { - logInfo('Setting bid floor for impression:', bid.params.bidfloor); - imp.bidfloor = bid.params.bidfloor; + if (bidRequest.params && bidRequest.params.bidfloor) { + logInfo('Setting bid floor for impression:', bidRequest.params.bidfloor); + imp.bidfloor = bidRequest.params.bidfloor; } if (mediaTypes[BANNER]) { logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); @@ -167,6 +167,7 @@ const interpretResponse = (serverResponse, request) => { break; case 2: bidResponse.meta.mediaType = VIDEO; + bidResponse.vastXml = bid.adm; break; default: logWarn('Unknown media type: ', bid.mtype, ' for bidId: ', bid.id); From 5416c2f9df422a7ae263a0e19def9dd765f7c973 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Tue, 10 Jun 2025 09:52:57 +0530 Subject: [PATCH 10/29] Fixed incorrect media type issue --- modules/risemediatechBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 28525e38e0b..030a476316a 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -163,10 +163,10 @@ const interpretResponse = (serverResponse, request) => { } switch (bid.mtype) { case 1: - bidResponse.meta.mediaType = BANNER; + bidResponse.mediaType = BANNER; break; case 2: - bidResponse.meta.mediaType = VIDEO; + bidResponse.mediaType = VIDEO; bidResponse.vastXml = bid.adm; break; default: From bdf9ea6b71872d37242b2c55be4537c9e67e8672 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 26 Jun 2025 09:18:16 +0530 Subject: [PATCH 11/29] Added test mode impressions support --- modules/risemediatechBidAdapter.js | 36 ++++++++++++------------------ modules/risemediatechBidAdapter.md | 25 ++++++++++----------- 2 files changed, 26 insertions(+), 35 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 030a476316a..c78e894bb61 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -2,9 +2,10 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { logInfo, logWarn } from '../src/utils.js'; +import { log } from 'gulp-util'; const BIDDER_CODE = 'risemediatech'; -const ENDPOINT_URL = 'http://localhost:8082/ads/rtb/prebid/js'; +const ENDPOINT_URL = 'https://dev-ads.risemediatech.com/ads/rtb/prebid/js'; const SYNC_URL_IFRAME = 'https://sync.risemediatech.com/iframe'; const SYNC_URL_IMAGE = 'https://sync.risemediatech.com/image'; const DEFAULT_CURRENCY = 'USD'; @@ -20,9 +21,15 @@ const converter = ortbConverter({ logInfo('Building impression object for bidRequest:', bidRequest); const imp = buildImp(bidRequest, context); const { mediaTypes } = bidRequest; - if (bidRequest.params && bidRequest.params.bidfloor) { - logInfo('Setting bid floor for impression:', bidRequest.params.bidfloor); - imp.bidfloor = bidRequest.params.bidfloor; + if (bidRequest.params) { + if (bidRequest.params.bidfloor) { + logInfo('Setting bid floor for impression:', bidRequest.params.bidfloor); + imp.bidfloor = bidRequest.params.bidfloor; + } + if (bidRequest.params.testMode) { + logInfo('Invoking test impression:', bidRequest.params.testMode); + imp.ext.test = 0; + } } if (mediaTypes[BANNER]) { logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); @@ -118,6 +125,9 @@ const buildRequests = (validBidRequests, bidderRequest) => { method: 'POST', url: ENDPOINT_URL, data: request, + options: { + endpointCompression: true + }, }; }; @@ -197,24 +207,6 @@ const interpretResponse = (serverResponse, request) => { * @returns {Array} Array of user sync objects. */ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { - logInfo('Handling user syncs with options:', syncOptions); - const type = syncOptions.iframeEnabled ? 'iframe' : 'image'; - let url = type === 'iframe' ? SYNC_URL_IFRAME : SYNC_URL_IMAGE; - - if (gdprConsent?.consentString) { - logInfo('Adding GDPR consent information to user sync URL:', gdprConsent); - url += `?gdpr=${Number(gdprConsent.gdprApplies || 0)}&gdpr_consent=${gdprConsent.consentString}`; - } - - if (uspConsent) { - logInfo('Adding USP consent information to user sync URL:', uspConsent); - url += `&us_privacy=${uspConsent}`; - } - - if (gppConsent?.gppString && gppConsent?.applicableSections?.length) { - logInfo('Adding GPP consent information to user sync URL:', gppConsent); - url += `&gpp=${gppConsent.gppString}&gpp_sid=${gppConsent.applicableSections.join(',')}`; - } // return [{ type, url }]; logInfo('User syncs are not implemented in this adapter.'); diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index ada04ed7b1e..399f15059ea 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -16,7 +16,7 @@ RisemediaTech supports Display & Video(Instream) currently. mediatypes: { banner: { sizes:[ - [300,250] + [320,50] ] } }, @@ -24,12 +24,8 @@ RisemediaTech supports Display & Video(Instream) currently. { bidder: 'risemediatech', params: { - placementId: 1452398, - publisherId: p-1489231, bidfloor: 0.5, - currency: 'USD', - domain: 'exampleDomain.com', - pageUrl: 'https://exampleDomain.com/ad' + testMode: 0 } } ] @@ -50,13 +46,16 @@ RisemediaTech supports Display & Video(Instream) currently. }, bids:[ { - mimes: ['video/mp4','video/webm'], - minduration: 5, - maxduration: 30, - startdelay: 30, - maxseq: 2, - poddur: 30, - protocols: [1,3,4] + params: { + mimes: ['video/mp4','video/webm'], + minduration: 5, + maxduration: 30, + startdelay: 30, + maxseq: 2, + poddur: 30, + protocols: [1,3,4] + } + } ] } From d0f9c9c5cf74f27c749bb53f7c32d72fae402323 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 26 Jun 2025 09:18:57 +0530 Subject: [PATCH 12/29] Added test mode for video ad units --- modules/risemediatechBidAdapter.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 399f15059ea..a82c009a9c6 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -53,7 +53,8 @@ RisemediaTech supports Display & Video(Instream) currently. startdelay: 30, maxseq: 2, poddur: 30, - protocols: [1,3,4] + protocols: [1,3,4], + testMode: 0 } } From d9b5de59b9d59463d94b9037b402fa150ff712b9 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 26 Jun 2025 09:23:43 +0530 Subject: [PATCH 13/29] Added bidfloor for example video ad unit --- modules/risemediatechBidAdapter.md | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index a82c009a9c6..5f811c8ca48 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -47,6 +47,7 @@ RisemediaTech supports Display & Video(Instream) currently. bids:[ { params: { + bidfloor: 0.1 mimes: ['video/mp4','video/webm'], minduration: 5, maxduration: 30, From abf25107bd8af9b4d8530601deecd397eece93ad Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 3 Jul 2025 19:41:21 +0530 Subject: [PATCH 14/29] Updated default TTL --- modules/risemediatechBidAdapter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index c78e894bb61..204cb39b5fd 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -9,7 +9,7 @@ const ENDPOINT_URL = 'https://dev-ads.risemediatech.com/ads/rtb/prebid/js'; const SYNC_URL_IFRAME = 'https://sync.risemediatech.com/iframe'; const SYNC_URL_IMAGE = 'https://sync.risemediatech.com/image'; const DEFAULT_CURRENCY = 'USD'; -const DEFAULT_TTL = 300; +const DEFAULT_TTL = 60; const converter = ortbConverter({ context: { From e744c13831038e849c701872158e265ccdbf4a91 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 3 Jul 2025 19:42:13 +0530 Subject: [PATCH 15/29] Minro fixes --- modules/risemediatechBidAdapter.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 204cb39b5fd..443577625fc 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -2,7 +2,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { logInfo, logWarn } from '../src/utils.js'; -import { log } from 'gulp-util'; const BIDDER_CODE = 'risemediatech'; const ENDPOINT_URL = 'https://dev-ads.risemediatech.com/ads/rtb/prebid/js'; @@ -82,12 +81,6 @@ const converter = ortbConverter({ const isBidRequestValid = (bid) => { logInfo('Validating bid request:', bid); - // // Validate params - // if (!bid.params || !bid.params.publisherId) { - // logWarn('Invalid bid request: Missing required params (publisherId or adSlot).'); - // return false; - // } - const { mediaTypes } = bid; // Validate video-specific fields if mediaTypes includes VIDEO @@ -209,7 +202,7 @@ const interpretResponse = (serverResponse, request) => { const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { // return [{ type, url }]; - logInfo('User syncs are not implemented in this adapter.'); + logInfo('User syncs are not implemented in this adapter yet.'); return null; }; From 6b3479e7877ad7c2b59c83c31d7ebac1167a0065 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Mon, 7 Jul 2025 17:04:28 +0530 Subject: [PATCH 16/29] Update docs --- modules/risemediatechBidAdapter.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 5f811c8ca48..84af9e7677f 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -41,23 +41,23 @@ RisemediaTech supports Display & Video(Instream) currently. mediatypes: { video: { playerSize: [640, 480], // required - context: 'instream' + context: 'instream', + mimes: ['video/mp4','video/webm'], + minduration: 5, + maxduration: 30, + startdelay: 30, + maxseq: 2, + poddur: 30, + protocols: [1,3,4], } }, bids:[ - { + { + bidder: 'risemediatech', params: { bidfloor: 0.1 - mimes: ['video/mp4','video/webm'], - minduration: 5, - maxduration: 30, - startdelay: 30, - maxseq: 2, - poddur: 30, - protocols: [1,3,4], testMode: 0 } - } ] } From a60344bfe24cce063c43d4c43135ab1a435b1624 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 9 Jul 2025 13:01:33 +0530 Subject: [PATCH 17/29] Minor changes --- modules/risemediatechBidAdapter.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 443577625fc..68100394947 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -37,13 +37,7 @@ const converter = ortbConverter({ logInfo('Adding video media type to impression:', mediaTypes[VIDEO]); imp.video = { ...mediaTypes[VIDEO], - mimes: bidRequest.params.mimes, - minduration: bidRequest.params.minduration, - maxduration: bidRequest.params.maxduration, - startdelay: bidRequest.params.startdelay, - maxseq: bidRequest.params.maxseq, - poddur: bidRequest.params.poddur, - protocols: bidRequest.params.protocols + // all video parameters are mapped. }; } From e02c5ce72a93d386f5048a1a866715297a74fa74 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 9 Jul 2025 15:47:02 +0530 Subject: [PATCH 18/29] Minor changes --- modules/risemediatechBidAdapter.js | 17 +++++++++++++---- modules/risemediatechBidAdapter.md | 8 ++++---- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 68100394947..61185a4905f 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -25,10 +25,10 @@ const converter = ortbConverter({ logInfo('Setting bid floor for impression:', bidRequest.params.bidfloor); imp.bidfloor = bidRequest.params.bidfloor; } - if (bidRequest.params.testMode) { - logInfo('Invoking test impression:', bidRequest.params.testMode); - imp.ext.test = 0; - } + // if (bidRequest.params.testMode) { + // logInfo('Invoking test impression:', bidRequest.params.testMode); + // imp.ext.test = 1; + // } } if (mediaTypes[BANNER]) { logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); @@ -50,6 +50,15 @@ const converter = ortbConverter({ request.tmax = bidderRequest.timeout; request.test = bidderRequest.test || 0; + if (Array.isArray(bidderRequest.bids)) { + const hasTestMode = bidderRequest.bids.some(bid => bid.params && bid.params.testMode === 1); + if (hasTestMode) { + request.ext = request.ext || {}; + request.ext.test = 1; + logInfo('Test mode detected in bid params, setting test flag in request:', request.ext.test); + } + } + if (bidderRequest.gdprConsent) { logInfo('Adding GDPR consent information to request:', bidderRequest.gdprConsent); request.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } }; diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 84af9e7677f..d42ba9b2389 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -24,8 +24,8 @@ RisemediaTech supports Display & Video(Instream) currently. { bidder: 'risemediatech', params: { - bidfloor: 0.5, - testMode: 0 + bidfloor: 0.001, + testMode: 1 } } ] @@ -55,8 +55,8 @@ RisemediaTech supports Display & Video(Instream) currently. { bidder: 'risemediatech', params: { - bidfloor: 0.1 - testMode: 0 + bidfloor: 0.001 + testMode: 1 } } ] From 63983a68d5ea596ebfb0cb1423fe0a38161c15d9 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 9 Jul 2025 17:03:51 +0530 Subject: [PATCH 19/29] Code cleanup --- modules/risemediatechBidAdapter.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 61185a4905f..ec150e55994 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -25,10 +25,6 @@ const converter = ortbConverter({ logInfo('Setting bid floor for impression:', bidRequest.params.bidfloor); imp.bidfloor = bidRequest.params.bidfloor; } - // if (bidRequest.params.testMode) { - // logInfo('Invoking test impression:', bidRequest.params.testMode); - // imp.ext.test = 1; - // } } if (mediaTypes[BANNER]) { logInfo('Adding banner media type to impression:', mediaTypes[BANNER]); From 77e12d1dc72af5082e870b3836b411fbbdbbd434 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 9 Jul 2025 20:45:10 +0530 Subject: [PATCH 20/29] Changes as per review --- modules/risemediatechBidAdapter.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index d42ba9b2389..58f6bfcbed6 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -1,12 +1,12 @@ # Overview -Module Name : RisemediaTech Bidder Adapter +Module Name : RiseMediaTech Bidder Adapter Module Type : Bid Adapter Maintainer : prebid@risemediatech.io # Description -Connects to RisemediaTech Exchange for bids -RisemediaTech supports Display & Video(Instream) currently. +Connects to RiseMediaTech Exchange for bids +RiseMediaTech supports Display & Video(Instream) currently. # Sample Ad Unit : Banner ``` From 7094d28491856eac7da2177b639968b5244acaa3 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Wed, 9 Jul 2025 20:48:08 +0530 Subject: [PATCH 21/29] Semantic changes --- modules/risemediatechBidAdapter.md | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 58f6bfcbed6..b734d9c68e5 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -62,3 +62,4 @@ RiseMediaTech supports Display & Video(Instream) currently. ] } ] +``` From ae9d67e1bf5e72ad87f26ed220a848bf5006dbbb Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Mon, 14 Jul 2025 09:39:49 +0530 Subject: [PATCH 22/29] Added support for Http Status 204 No Bids Scenarios --- modules/risemediatechBidAdapter.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index ec150e55994..038ac165144 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -132,6 +132,11 @@ const buildRequests = (validBidRequests, bidderRequest) => { const interpretResponse = (serverResponse, request) => { logInfo('Interpreting server response:', serverResponse); + if (serverResponse && serverResponse.status === 204) { + logInfo('No bids returned from the server (HTTP 204).'); + return []; + } + const bidResp = serverResponse && serverResponse.body; if (!bidResp || !Array.isArray(bidResp.seatbid)) { logWarn('Server response is empty, invalid, or does not contain seatbid array.'); From af8c54aa8ff28c87649170d1ab0714243b464c7b Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Mon, 14 Jul 2025 11:07:21 +0530 Subject: [PATCH 23/29] Updated failing unit tests. --- modules/risemediatechBidAdapter.js | 2 +- ...pec.js => risemediatechBidAdapter_spec.js} | 131 +++++++++++++----- 2 files changed, 97 insertions(+), 36 deletions(-) rename test/spec/modules/{risemediaBidAdapter_spec.js => risemediatechBidAdapter_spec.js} (79%) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 038ac165144..46309513b73 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -166,7 +166,7 @@ const interpretResponse = (serverResponse, request) => { // Set media type based on bid.mtype if (bid.mtype == null) { logWarn('Bid response does not contain media type for bidId: ', bid.id); - bidResponse.meta.mediaType = BANNER; + bidResponse.mediaType = BANNER; } switch (bid.mtype) { case 1: diff --git a/test/spec/modules/risemediaBidAdapter_spec.js b/test/spec/modules/risemediatechBidAdapter_spec.js similarity index 79% rename from test/spec/modules/risemediaBidAdapter_spec.js rename to test/spec/modules/risemediatechBidAdapter_spec.js index 09015f48d24..3d1df0f09b2 100644 --- a/test/spec/modules/risemediaBidAdapter_spec.js +++ b/test/spec/modules/risemediatechBidAdapter_spec.js @@ -56,18 +56,6 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(validBidRequest)).to.equal(true); }); - it('should return false if publisherId is missing', () => { - const invalidBidRequest = { ...validBidRequest }; - delete invalidBidRequest.params.publisherId; - expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); - }); - - it('should return false if adSlot is missing', () => { - const invalidBidRequest = { ...validBidRequest }; - delete invalidBidRequest.params.adSlot; - expect(spec.isBidRequestValid(invalidBidRequest)).to.equal(false); - }); - it('should return false for invalid video bid request', () => { const invalidVideoRequest = { ...validBidRequest, @@ -187,7 +175,7 @@ describe('RiseMediaTech adapter', () => { const request = spec.buildRequests([validBidRequest], bidderRequest); expect(request).to.be.an('object'); expect(request.method).to.equal('POST'); - expect(request.url).to.equal('http://localhost:8082/ads/rtb/prebid/js'); + expect(request.url).to.equal('https://dev-ads.risemediatech.com/ads/rtb/prebid/js'); expect(request.data).to.be.an('object'); }); @@ -286,7 +274,7 @@ describe('RiseMediaTech adapter', () => { expect(bid).to.have.property('creativeId', 'creative123'); expect(bid).to.have.property('currency', 'USD'); expect(bid).to.have.property('netRevenue', true); - expect(bid).to.have.property('ttl', 300); + expect(bid).to.have.property('ttl', 60); }); it('should return an empty array if no bids are present', () => { @@ -339,13 +327,13 @@ describe('RiseMediaTech adapter', () => { expect(bids).to.be.an('array').with.lengthOf(2); expect(bids[0]).to.have.property('requestId', '1abc'); expect(bids[1]).to.have.property('requestId', '2bcd'); - expect(bids[0].meta.mediaType).to.equal('banner'); - expect(bids[1].meta.mediaType).to.equal('video'); + expect(bids[0].mediaType).to.equal('banner'); + expect(bids[1].mediaType).to.equal('video'); expect(bids[0]).to.have.property('cpm', 1.5); expect(bids[1]).to.have.property('cpm', 2.0); }); - it('should set meta.mediaType to banner if mtype is missing', () => { + it('should set mediaType to banner if mtype is missing', () => { const responseNoMtype = { body: { id: '2def', @@ -370,7 +358,7 @@ describe('RiseMediaTech adapter', () => { }; const request = spec.buildRequests([validBidRequest], bidderRequest); const bids = spec.interpretResponse(responseNoMtype, request); - expect(bids[0].meta.mediaType).to.equal('banner'); + expect(bids[0].mediaType).to.equal('banner'); }); it('should set meta.advertiserDomains to an empty array if adomain is missing', () => { @@ -417,29 +405,102 @@ describe('RiseMediaTech adapter', () => { const bids = spec.interpretResponse(serverResponse, request); expect(bids).to.be.an('array').with.lengthOf(1); }); - }); - describe('getUserSyncs', () => { - it('should return iframe sync if iframeEnabled is true', () => { - const syncs = spec.getUserSyncs({ iframeEnabled: true }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); - expect(syncs).to.be.an('array').with.lengthOf(1); - expect(syncs[0]).to.have.property('type', 'iframe'); - expect(syncs[0]).to.have.property('url').that.includes('https://sync.risemediatech.com/iframe'); + it('should return an empty array for HTTP 204 response', () => { + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse({ status: 204 }, request); + expect(bids).to.be.an('array').that.is.empty; }); - it('should return image sync if iframeEnabled is false', () => { - const syncs = spec.getUserSyncs({ iframeEnabled: false }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); - expect(syncs).to.be.an('array').with.lengthOf(1); - expect(syncs[0]).to.have.property('type', 'image'); - expect(syncs[0]).to.have.property('url').that.includes('https://sync.risemediatech.com/image'); + it('should log a warning and not set mediaType for unknown mtype', () => { + const responseWithUnknownMtype = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'], + mtype: 999, // Unknown mtype + }, + ], + }, + ], + }, + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(responseWithUnknownMtype, request); + expect(bids).to.be.an('array').with.lengthOf(1); + expect(bids[0].meta).to.not.have.property('mediaType'); }); - it('should include GDPR and USP consent in the sync URL', () => { + it('should include dealId if present in the bid response', () => { + const responseWithDealId = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + price: 1.5, + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'], + dealid: 'deal123', + }, + ], + }, + ], + }, + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(responseWithDealId, request); + expect(bids).to.be.an('array').with.lengthOf(1); + expect(bids[0]).to.have.property('dealId', 'deal123'); + }); + + it('should handle bids with missing price gracefully', () => { + const responseWithoutPrice = { + body: { + id: '2def', + seatbid: [ + { + bid: [ + { + id: '1abc', + impid: '1abc', + adm: '
Ad
', + w: 300, + h: 250, + crid: 'creative123', + adomain: ['example.com'], + }, + ], + }, + ], + }, + }; + const request = spec.buildRequests([validBidRequest], bidderRequest); + const bids = spec.interpretResponse(responseWithoutPrice, request); + expect(bids).to.be.an('array').that.is.not.empty; + }); + }); + + describe('getUserSyncs', () => { + it('should return null as user syncs are not implemented', () => { const syncs = spec.getUserSyncs({ iframeEnabled: true }, [], bidderRequest.gdprConsent, bidderRequest.uspConsent); - const syncUrl = syncs[0].url; - expect(syncUrl).to.include('gdpr=1'); - expect(syncUrl).to.include('gdpr_consent=consent123'); - expect(syncUrl).to.include('us_privacy=1YNN'); + expect(syncs).to.be.null; }); }); }); From 44b7d07da118c41f47b524b321778b7a5055eaad Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Mon, 14 Jul 2025 13:26:02 +0530 Subject: [PATCH 24/29] Modified the check for no bids --- modules/risemediatechBidAdapter.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 46309513b73..dfbed19e563 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -132,8 +132,8 @@ const buildRequests = (validBidRequests, bidderRequest) => { const interpretResponse = (serverResponse, request) => { logInfo('Interpreting server response:', serverResponse); - if (serverResponse && serverResponse.status === 204) { - logInfo('No bids returned from the server (HTTP 204).'); + if (serverResponse && serverResponse.status !== 200) { + logInfo(`No bids returned from the server (HTTP ${serverResponse.status}).`); return []; } From 7f53fd899217292a9401545257a21427b4dcd09a Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Tue, 15 Jul 2025 10:10:32 +0530 Subject: [PATCH 25/29] Reverted the status check --- modules/risemediatechBidAdapter.js | 5 ----- test/spec/modules/risemediatechBidAdapter_spec.js | 6 ------ 2 files changed, 11 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index dfbed19e563..31ffba2f6e0 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -132,11 +132,6 @@ const buildRequests = (validBidRequests, bidderRequest) => { const interpretResponse = (serverResponse, request) => { logInfo('Interpreting server response:', serverResponse); - if (serverResponse && serverResponse.status !== 200) { - logInfo(`No bids returned from the server (HTTP ${serverResponse.status}).`); - return []; - } - const bidResp = serverResponse && serverResponse.body; if (!bidResp || !Array.isArray(bidResp.seatbid)) { logWarn('Server response is empty, invalid, or does not contain seatbid array.'); diff --git a/test/spec/modules/risemediatechBidAdapter_spec.js b/test/spec/modules/risemediatechBidAdapter_spec.js index 3d1df0f09b2..dc2a62c8fd9 100644 --- a/test/spec/modules/risemediatechBidAdapter_spec.js +++ b/test/spec/modules/risemediatechBidAdapter_spec.js @@ -406,12 +406,6 @@ describe('RiseMediaTech adapter', () => { expect(bids).to.be.an('array').with.lengthOf(1); }); - it('should return an empty array for HTTP 204 response', () => { - const request = spec.buildRequests([validBidRequest], bidderRequest); - const bids = spec.interpretResponse({ status: 204 }, request); - expect(bids).to.be.an('array').that.is.empty; - }); - it('should log a warning and not set mediaType for unknown mtype', () => { const responseWithUnknownMtype = { body: { From ff3a8002a9e2f5d124fee178c6343d60e8b60408 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Tue, 15 Jul 2025 11:48:58 +0530 Subject: [PATCH 26/29] linter modifications --- modules/risemediatechBidAdapter.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index 31ffba2f6e0..dba5b390a50 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -5,8 +5,6 @@ import { logInfo, logWarn } from '../src/utils.js'; const BIDDER_CODE = 'risemediatech'; const ENDPOINT_URL = 'https://dev-ads.risemediatech.com/ads/rtb/prebid/js'; -const SYNC_URL_IFRAME = 'https://sync.risemediatech.com/iframe'; -const SYNC_URL_IMAGE = 'https://sync.risemediatech.com/image'; const DEFAULT_CURRENCY = 'USD'; const DEFAULT_TTL = 60; @@ -199,7 +197,6 @@ const interpretResponse = (serverResponse, request) => { * @returns {Array} Array of user sync objects. */ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) => { - // return [{ type, url }]; logInfo('User syncs are not implemented in this adapter yet.'); return null; From b0ed498a7049d09824e81ff3cfffbc62a3d194d1 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Thu, 17 Jul 2025 11:36:09 +0530 Subject: [PATCH 27/29] Updated the documentation for the adapter and formatted adapter --- modules/risemediatechBidAdapter.js | 4 ++-- modules/risemediatechBidAdapter.md | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/risemediatechBidAdapter.js b/modules/risemediatechBidAdapter.js index dba5b390a50..e3709722ae0 100644 --- a/modules/risemediatechBidAdapter.js +++ b/modules/risemediatechBidAdapter.js @@ -116,8 +116,8 @@ const buildRequests = (validBidRequests, bidderRequest) => { url: ENDPOINT_URL, data: request, options: { - endpointCompression: true - }, + endpointCompression: true + }, }; }; diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index b734d9c68e5..7c3bf2e38f2 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -7,6 +7,7 @@ Maintainer : prebid@risemediatech.io # Description Connects to RiseMediaTech Exchange for bids RiseMediaTech supports Display & Video(Instream) currently. +Our legal entity named Rise Media Technologies owns the domain risemediatech.io # Sample Ad Unit : Banner ``` From 71de14d9c49f450da5f68dfab099e91745e318d2 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Fri, 18 Jul 2025 11:03:52 +0530 Subject: [PATCH 28/29] Modified the documentation as per discussion --- modules/risemediatechBidAdapter.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/risemediatechBidAdapter.md b/modules/risemediatechBidAdapter.md index 7c3bf2e38f2..4eefdf8710c 100644 --- a/modules/risemediatechBidAdapter.md +++ b/modules/risemediatechBidAdapter.md @@ -7,8 +7,9 @@ Maintainer : prebid@risemediatech.io # Description Connects to RiseMediaTech Exchange for bids RiseMediaTech supports Display & Video(Instream) currently. -Our legal entity named Rise Media Technologies owns the domain risemediatech.io +This adapter is maintained by Rise Media Technologies, the legal entity behind this implementation. Our official domain is risemediatech.io, which currently redirects to pubrise.ai for operational convenience. We also own the domain risemediatech.com. +Rise Media Technologies and PubRise are part of the same parent organization. # Sample Ad Unit : Banner ``` var adUnits = [ From 4d909b33840f9e72508ec4ef5dc9d37847af1928 Mon Sep 17 00:00:00 2001 From: pritishmd-talentica Date: Tue, 5 Aug 2025 10:12:28 +0530 Subject: [PATCH 29/29] Resolved linter errors from upstream repo PR --- test/spec/modules/risemediatechBidAdapter_spec.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/spec/modules/risemediatechBidAdapter_spec.js b/test/spec/modules/risemediatechBidAdapter_spec.js index dc2a62c8fd9..d4d70017ceb 100644 --- a/test/spec/modules/risemediatechBidAdapter_spec.js +++ b/test/spec/modules/risemediatechBidAdapter_spec.js @@ -110,7 +110,6 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); - it('should return false for video request with width <= 0', () => { const invalidBid = { ...validBidRequest, @@ -125,7 +124,6 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); - it('should return false for video request with height <= 0', () => { const invalidBid = { ...validBidRequest, @@ -140,7 +138,6 @@ describe('RiseMediaTech adapter', () => { expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); - it('should return false for video bid request with invalid width', () => { const invalidVideoRequest = { ...validBidRequest,