From 219e3c73f7aa7620bd3a953b2c7548d14172eb6e Mon Sep 17 00:00:00 2001 From: Pavlo Kavulych <72217414+Chucky-choo@users.noreply.github.com> Date: Wed, 27 May 2026 05:05:46 +0300 Subject: [PATCH 001/124] Matterfull Bid Adapter: initial release (#14922) * Matterfull Bid Adapter: initial release * Matterfull Bid Adapter: fix endpoint * Matterfull Bid Adapter: make params.env field required --- modules/matterfullBidAdapter.md | 50 ++ modules/matterfullBidAdapter.ts | 29 ++ .../spec/modules/matterfullBidAdapter_spec.js | 443 ++++++++++++++++++ 3 files changed, 522 insertions(+) create mode 100644 modules/matterfullBidAdapter.md create mode 100644 modules/matterfullBidAdapter.ts create mode 100644 test/spec/modules/matterfullBidAdapter_spec.js diff --git a/modules/matterfullBidAdapter.md b/modules/matterfullBidAdapter.md new file mode 100644 index 00000000000..5f8401b7423 --- /dev/null +++ b/modules/matterfullBidAdapter.md @@ -0,0 +1,50 @@ +# Overview + +``` +Module Name: Matterfull Bidder Adapter +Module Type: Matterfull Bidder Adapter +Maintainer: adops@bematterfull.com +``` + +# Test Parameters +``` +var adUnits = [ + { + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'matterfull', + params: { + env: 'matterfull', + pid: 'aa8217e20131c095fe9dba67981040b0', + ext: {} + } + } + ] + }, + { + code: 'test-video', + sizes: [ [ 640, 480 ] ], + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream', + skipppable: true + } + }, + bids: [{ + bidder: 'matterfull', + params: { + env: 'matterfull', + pid: 'aa8217e20131c095fe9dba67981040b0', + ext: {} + } + }] + } +]; +``` diff --git a/modules/matterfullBidAdapter.ts b/modules/matterfullBidAdapter.ts new file mode 100644 index 00000000000..adf33dfc3d7 --- /dev/null +++ b/modules/matterfullBidAdapter.ts @@ -0,0 +1,29 @@ +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { registerBidder, type AdapterRequest, type BidderSpec, type ServerResponse } from '../src/adapters/bidderFactory.js'; +import { buildRequests as xeBuildRequests, getUserSyncs, interpretResponse as xeInterpretResponse, isBidRequestValid } from '../libraries/xeUtils/bidderUtils.js'; + +const BIDDER_CODE = 'matterfull'; +const ENDPOINT = 'https://pbjs.bematterfull.com'; + +export type MatterfullBidParams = { + pid: string; + env: string; + ext?: Record; +} + +declare module '../src/adUnits' { + interface BidderParams { + [BIDDER_CODE]: MatterfullBidParams; + } +} + +export const spec: BidderSpec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid: bid => isBidRequestValid(bid), + buildRequests: (validBidRequests, bidderRequest) => xeBuildRequests(validBidRequests, bidderRequest, ENDPOINT) as AdapterRequest, + interpretResponse: (response: ServerResponse, request: AdapterRequest) => xeInterpretResponse(response, request as any), + getUserSyncs +} + +registerBidder(spec); diff --git a/test/spec/modules/matterfullBidAdapter_spec.js b/test/spec/modules/matterfullBidAdapter_spec.js new file mode 100644 index 00000000000..f64b96fb320 --- /dev/null +++ b/test/spec/modules/matterfullBidAdapter_spec.js @@ -0,0 +1,443 @@ +import { expect } from 'chai'; +import { config } from 'src/config.js'; +import { spec } from 'modules/matterfullBidAdapter.ts'; +import { deepClone } from 'src/utils'; +import { getBidFloor } from '../../../libraries/xeUtils/bidderUtils.js'; + +const ENDPOINT = 'https://pbjs.bematterfull.com'; + +const defaultRequest = { + tmax: 0, + adUnitCode: 'test', + bidId: '1', + requestId: 'qwerty', + ortb2: { + source: { + tid: 'auctionId' + } + }, + ortb2Imp: { + ext: { + tid: 'tr1', + } + }, + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 200] + ] + } + }, + bidder: 'matterfull', + params: { + pid: 'aa8217e20131c095fe9dba67981040b0', + env: 'matterfull', + ext: {} + }, + bidRequestsCount: 1 +}; + +const defaultRequestVideo = deepClone(defaultRequest); +defaultRequestVideo.mediaTypes = { + video: { + playerSize: [640, 480], + context: 'instream', + skipppable: true + } +}; + +const videoBidderRequest = { + bidderCode: 'matterfull', + bids: [{ mediaTypes: { video: {} }, bidId: 'qwerty' }] +}; + +const displayBidderRequest = { + bidderCode: 'matterfull', + bids: [{ bidId: 'qwerty' }] +}; + +describe('matterfullBidAdapter', () => { + describe('isBidRequestValid', function () { + it('should return false when request params is missing', function () { + const invalidRequest = deepClone(defaultRequest); + delete invalidRequest.params; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return false when required pid param is missing', function () { + const invalidRequest = deepClone(defaultRequest); + delete invalidRequest.params.pid; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return false when video.playerSize is missing', function () { + const invalidRequest = deepClone(defaultRequestVideo); + delete invalidRequest.mediaTypes.video.playerSize; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(defaultRequest)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + beforeEach(function () { + config.resetConfig(); + }); + + it('should send request with correct structure', function () { + const request = spec.buildRequests([defaultRequest], {}); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENDPOINT + '/bid'); + expect(request.options).to.have.property('contentType').and.to.equal('application/json'); + expect(request).to.have.property('data'); + }); + + it('should build basic request structure', function () { + const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0]; + expect(request).to.have.property('tmax').and.to.equal(defaultRequest.tmax); + expect(request).to.have.property('bidId').and.to.equal(defaultRequest.bidId); + expect(request).to.have.property('auctionId').and.to.equal(defaultRequest.ortb2.source.tid); + expect(request).to.have.property('transactionId').and.to.equal(defaultRequest.ortb2Imp.ext.tid); + expect(request).to.have.property('tz').and.to.equal(new Date().getTimezoneOffset()); + expect(request).to.have.property('bc').and.to.equal(1); + expect(request).to.have.property('floor').and.to.equal(null); + expect(request).to.have.property('banner').and.to.deep.equal({ sizes: [[300, 250], [300, 200]] }); + expect(request).to.have.property('gdprConsent').and.to.deep.equal({}); + expect(request).to.have.property('userEids').and.to.deep.equal([]); + expect(request).to.have.property('usPrivacy').and.to.equal(''); + expect(request).to.have.property('sizes').and.to.deep.equal(['300x250', '300x200']); + expect(request).to.have.property('ext').and.to.deep.equal({}); + expect(request).to.have.property('env').and.to.deep.equal({ + pid: 'aa8217e20131c095fe9dba67981040b0', + env: 'matterfull', + }); + expect(request).to.have.property('device').and.to.deep.equal({ + ua: navigator.userAgent, + lang: navigator.language + }); + }); + + it('should build request with schain', function () { + const schainRequest = deepClone(defaultRequest); + const bidderRequest = { + ortb2: { + source: { + ext: { + schain: { + ver: '1.0' + } + } + } + } + }; + const request = JSON.parse(spec.buildRequests([schainRequest], bidderRequest).data)[0]; + expect(request).to.have.property('schain').and.to.deep.equal({ + ver: '1.0' + }); + }); + + it('should build request with location', function () { + const bidderRequest = { + refererInfo: { + page: 'page', + location: 'location', + domain: 'domain', + ref: 'ref', + isAmp: false + } + }; + const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0]; + expect(request).to.have.property('location'); + const location = request.location; + expect(location).to.have.property('page').and.to.equal('page'); + expect(location).to.have.property('location').and.to.equal('location'); + expect(location).to.have.property('domain').and.to.equal('domain'); + expect(location).to.have.property('ref').and.to.equal('ref'); + expect(location).to.have.property('isAmp').and.to.equal(false); + }); + + it('should build request with ortb2 info', function () { + const ortb2Request = deepClone(defaultRequest); + ortb2Request.ortb2 = { + site: { + name: 'name' + } + }; + const request = JSON.parse(spec.buildRequests([ortb2Request], {}).data)[0]; + expect(request).to.have.property('ortb2').and.to.deep.equal({ + site: { + name: 'name' + } + }); + }); + + it('should build request with ortb2Imp info', function () { + const ortb2ImpRequest = deepClone(defaultRequest); + ortb2ImpRequest.ortb2Imp = { + ext: { + data: { + pbadslot: 'home1', + adUnitSpecificAttribute: '1' + } + } + }; + const request = JSON.parse(spec.buildRequests([ortb2ImpRequest], {}).data)[0]; + expect(request).to.have.property('ortb2Imp').and.to.deep.equal({ + ext: { + data: { + pbadslot: 'home1', + adUnitSpecificAttribute: '1' + } + } + }); + }); + + it('should build request with valid bidfloor', function () { + const bfRequest = deepClone(defaultRequest); + bfRequest.getFloor = () => ({ floor: 5, currency: 'USD' }); + const request = JSON.parse(spec.buildRequests([bfRequest], {}).data)[0]; + expect(request).to.have.property('floor').and.to.equal(5); + }); + + it('should build request with usp consent data if applies', function () { + const bidderRequest = { + uspConsent: '1YA-' + }; + const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0]; + expect(request).to.have.property('usPrivacy').and.equals('1YA-'); + }); + + it('should build request with extended ids', function () { + const idRequest = deepClone(defaultRequest); + idRequest.userIdAsEids = [ + { source: 'adserver.org', uids: [{ id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: { rtiPartner: 'TDID' } }] }, + { source: 'pubcid.org', uids: [{ id: 'pubCommonId_FROM_USER_ID_MODULE', atype: 1 }] } + ]; + const request = JSON.parse(spec.buildRequests([idRequest], {}).data)[0]; + expect(request).to.have.property('userEids').and.deep.equal(idRequest.userIdAsEids); + }); + + it('should build request with video', function () { + const request = JSON.parse(spec.buildRequests([defaultRequestVideo], {}).data)[0]; + expect(request).to.have.property('video').and.to.deep.equal({ + playerSize: [640, 480], + context: 'instream', + skipppable: true + }); + expect(request).to.have.property('sizes').and.to.deep.equal(['640x480']); + }); + }); + + describe('interpretResponse', function () { + it('should return empty bids', function () { + const serverResponse = { + body: { + data: null + } + }; + + const invalidResponse = spec.interpretResponse(serverResponse, {}); + expect(invalidResponse).to.be.an('array').that.is.empty; + }); + + it('should interpret valid response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 300, + height: 250, + ttl: 600, + meta: { + advertiserDomains: ['matterfull'] + }, + ext: { + pixels: [ + ['iframe', 'surl1'], + ['image', 'surl2'], + ] + } + }] + } + }; + + const validResponse = spec.interpretResponse(serverResponse, { bidderRequest: displayBidderRequest }); + const bid = validResponse[0]; + expect(validResponse).to.be.an('array').that.is.not.empty; + expect(bid.requestId).to.equal('qwerty'); + expect(bid.cpm).to.equal(1); + expect(bid.currency).to.equal('USD'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.ttl).to.equal(600); + expect(bid.meta).to.deep.equal({ advertiserDomains: ['matterfull'] }); + }); + + it('should interpret valid banner response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 300, + height: 250, + ttl: 600, + mediaType: 'banner', + creativeId: 'demo-banner', + ad: 'ad', + meta: {} + }] + } + }; + + const validResponseBanner = spec.interpretResponse(serverResponse, { bidderRequest: displayBidderRequest }); + const bid = validResponseBanner[0]; + expect(validResponseBanner).to.be.an('array').that.is.not.empty; + expect(bid.mediaType).to.equal('banner'); + expect(bid.creativeId).to.equal('demo-banner'); + expect(bid.ad).to.equal('ad'); + }); + + it('should interpret valid video response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 600, + height: 480, + ttl: 600, + mediaType: 'video', + creativeId: 'demo-video', + ad: 'vast-xml', + meta: {} + }] + } + }; + + const validResponseBanner = spec.interpretResponse(serverResponse, { bidderRequest: videoBidderRequest }); + const bid = validResponseBanner[0]; + expect(validResponseBanner).to.be.an('array').that.is.not.empty; + expect(bid.mediaType).to.equal('video'); + expect(bid.creativeId).to.equal('demo-video'); + expect(bid.ad).to.equal('vast-xml'); + }); + }); + + describe('getUserSyncs', function () { + it('shoukd handle no params', function () { + const opts = spec.getUserSyncs({}, []); + expect(opts).to.be.an('array').that.is.empty; + }); + + it('should return empty if sync is not allowed', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }); + expect(opts).to.be.an('array').that.is.empty; + }); + + it('should allow iframe sync', function () { + const opts = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: false }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }]); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('iframe'); + expect(opts[0].url).to.equal('surl1?a=b&us_privacy=&gdpr=0&gdpr_consent='); + }); + + it('should allow pixel sync', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }]); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('image'); + expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=0&gdpr_consent='); + }); + + it('should allow pixel sync and parse consent params', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }], { + gdprApplies: 1, + consentString: '1YA-' + }); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('image'); + expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=1&gdpr_consent=1YA-'); + }); + }); + + describe('getBidFloor', function () { + it('should return null when getFloor is not a function', () => { + const bid = { getFloor: 2 }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when getFloor doesnt return an object', () => { + const bid = { getFloor: () => 2 }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when floor is not a number', () => { + const bid = { + getFloor: () => ({ floor: 'string', currency: 'USD' }) + }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when currency is not USD', () => { + const bid = { + getFloor: () => ({ floor: 5, currency: 'EUR' }) + }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return floor value when everything is correct', () => { + const bid = { + getFloor: () => ({ floor: 5, currency: 'USD' }) + }; + const result = getBidFloor(bid); + expect(result).to.equal(5); + }); + }); +}); From 47e9e6553de61770d772a4f279b133f33e35b6dc Mon Sep 17 00:00:00 2001 From: Pavlo Kavulych <72217414+Chucky-choo@users.noreply.github.com> Date: Wed, 27 May 2026 05:06:50 +0300 Subject: [PATCH 002/124] AnzuDSP Bid Adapter: initial release (#14924) * AnzuDSP Bid Adapter: initial release * AnzuDSP Bid Adapter: make params.env field required --- modules/anzuDSPBidAdapter.md | 50 +++ modules/anzuDSPBidAdapter.ts | 29 ++ test/spec/modules/anzuDSPBidAdapter_spec.js | 443 ++++++++++++++++++++ 3 files changed, 522 insertions(+) create mode 100644 modules/anzuDSPBidAdapter.md create mode 100644 modules/anzuDSPBidAdapter.ts create mode 100644 test/spec/modules/anzuDSPBidAdapter_spec.js diff --git a/modules/anzuDSPBidAdapter.md b/modules/anzuDSPBidAdapter.md new file mode 100644 index 00000000000..507aaefdafb --- /dev/null +++ b/modules/anzuDSPBidAdapter.md @@ -0,0 +1,50 @@ +# Overview + +``` +Module Name: AnzuDSP Bidder Adapter +Module Type: AnzuDSP Bidder Adapter +Maintainer: prebid@anzu.io +``` + +# Test Parameters +``` +var adUnits = [ + { + code: 'test-banner', + mediaTypes: { + banner: { + sizes: [[300, 250]], + } + }, + bids: [ + { + bidder: 'anzuDSP', + params: { + env: 'anzuDSP', + pid: 'aa8217e20131c095fe9dba67981040b0', + ext: {} + } + } + ] + }, + { + code: 'test-video', + sizes: [ [ 640, 480 ] ], + mediaTypes: { + video: { + playerSize: [640, 480], + context: 'instream', + skipppable: true + } + }, + bids: [{ + bidder: 'anzuDSP', + params: { + env: 'anzuDSP', + pid: 'aa8217e20131c095fe9dba67981040b0', + ext: {} + } + }] + } +]; +``` diff --git a/modules/anzuDSPBidAdapter.ts b/modules/anzuDSPBidAdapter.ts new file mode 100644 index 00000000000..b6e9cccedf7 --- /dev/null +++ b/modules/anzuDSPBidAdapter.ts @@ -0,0 +1,29 @@ +import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { registerBidder, type AdapterRequest, type BidderSpec, type ServerResponse } from '../src/adapters/bidderFactory.js'; +import { buildRequests as xeBuildRequests, getUserSyncs, interpretResponse as xeInterpretResponse, isBidRequestValid } from '../libraries/xeUtils/bidderUtils.js'; + +const BIDDER_CODE = 'anzuDSP'; +const ENDPOINT = 'https://pbjs.anzu-rtb.live'; + +export type AnzuDSPBidParams = { + pid: string; + env: string; + ext?: Record; +} + +declare module '../src/adUnits' { + interface BidderParams { + [BIDDER_CODE]: AnzuDSPBidParams; + } +} + +export const spec: BidderSpec = { + code: BIDDER_CODE, + supportedMediaTypes: [BANNER, VIDEO], + isBidRequestValid: bid => isBidRequestValid(bid), + buildRequests: (validBidRequests, bidderRequest) => xeBuildRequests(validBidRequests, bidderRequest, ENDPOINT) as AdapterRequest, + interpretResponse: (response: ServerResponse, request: AdapterRequest) => xeInterpretResponse(response, request as any), + getUserSyncs +} + +registerBidder(spec); diff --git a/test/spec/modules/anzuDSPBidAdapter_spec.js b/test/spec/modules/anzuDSPBidAdapter_spec.js new file mode 100644 index 00000000000..a3f64b259de --- /dev/null +++ b/test/spec/modules/anzuDSPBidAdapter_spec.js @@ -0,0 +1,443 @@ +import { expect } from 'chai'; +import { config } from 'src/config.js'; +import { spec } from 'modules/anzuDSPBidAdapter.ts'; +import { deepClone } from 'src/utils'; +import { getBidFloor } from '../../../libraries/xeUtils/bidderUtils.js'; + +const ENDPOINT = 'https://pbjs.anzu-rtb.live'; + +const defaultRequest = { + tmax: 0, + adUnitCode: 'test', + bidId: '1', + requestId: 'qwerty', + ortb2: { + source: { + tid: 'auctionId' + } + }, + ortb2Imp: { + ext: { + tid: 'tr1', + } + }, + mediaTypes: { + banner: { + sizes: [ + [300, 250], + [300, 200] + ] + } + }, + bidder: 'anzuDSP', + params: { + pid: 'aa8217e20131c095fe9dba67981040b0', + env: 'anzuDSP', + ext: {} + }, + bidRequestsCount: 1 +}; + +const defaultRequestVideo = deepClone(defaultRequest); +defaultRequestVideo.mediaTypes = { + video: { + playerSize: [640, 480], + context: 'instream', + skipppable: true + } +}; + +const videoBidderRequest = { + bidderCode: 'anzuDSP', + bids: [{ mediaTypes: { video: {} }, bidId: 'qwerty' }] +}; + +const displayBidderRequest = { + bidderCode: 'anzuDSP', + bids: [{ bidId: 'qwerty' }] +}; + +describe('anzuDSPBidAdapter', () => { + describe('isBidRequestValid', function () { + it('should return false when request params is missing', function () { + const invalidRequest = deepClone(defaultRequest); + delete invalidRequest.params; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return false when required pid param is missing', function () { + const invalidRequest = deepClone(defaultRequest); + delete invalidRequest.params.pid; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return false when video.playerSize is missing', function () { + const invalidRequest = deepClone(defaultRequestVideo); + delete invalidRequest.mediaTypes.video.playerSize; + expect(spec.isBidRequestValid(invalidRequest)).to.equal(false); + }); + + it('should return true when required params found', function () { + expect(spec.isBidRequestValid(defaultRequest)).to.equal(true); + }); + }); + + describe('buildRequests', function () { + beforeEach(function () { + config.resetConfig(); + }); + + it('should send request with correct structure', function () { + const request = spec.buildRequests([defaultRequest], {}); + expect(request.method).to.equal('POST'); + expect(request.url).to.equal(ENDPOINT + '/bid'); + expect(request.options).to.have.property('contentType').and.to.equal('application/json'); + expect(request).to.have.property('data'); + }); + + it('should build basic request structure', function () { + const request = JSON.parse(spec.buildRequests([defaultRequest], {}).data)[0]; + expect(request).to.have.property('tmax').and.to.equal(defaultRequest.tmax); + expect(request).to.have.property('bidId').and.to.equal(defaultRequest.bidId); + expect(request).to.have.property('auctionId').and.to.equal(defaultRequest.ortb2.source.tid); + expect(request).to.have.property('transactionId').and.to.equal(defaultRequest.ortb2Imp.ext.tid); + expect(request).to.have.property('tz').and.to.equal(new Date().getTimezoneOffset()); + expect(request).to.have.property('bc').and.to.equal(1); + expect(request).to.have.property('floor').and.to.equal(null); + expect(request).to.have.property('banner').and.to.deep.equal({ sizes: [[300, 250], [300, 200]] }); + expect(request).to.have.property('gdprConsent').and.to.deep.equal({}); + expect(request).to.have.property('userEids').and.to.deep.equal([]); + expect(request).to.have.property('usPrivacy').and.to.equal(''); + expect(request).to.have.property('sizes').and.to.deep.equal(['300x250', '300x200']); + expect(request).to.have.property('ext').and.to.deep.equal({}); + expect(request).to.have.property('env').and.to.deep.equal({ + pid: 'aa8217e20131c095fe9dba67981040b0', + env: 'anzuDSP' + }); + expect(request).to.have.property('device').and.to.deep.equal({ + ua: navigator.userAgent, + lang: navigator.language + }); + }); + + it('should build request with schain', function () { + const schainRequest = deepClone(defaultRequest); + const bidderRequest = { + ortb2: { + source: { + ext: { + schain: { + ver: '1.0' + } + } + } + } + }; + const request = JSON.parse(spec.buildRequests([schainRequest], bidderRequest).data)[0]; + expect(request).to.have.property('schain').and.to.deep.equal({ + ver: '1.0' + }); + }); + + it('should build request with location', function () { + const bidderRequest = { + refererInfo: { + page: 'page', + location: 'location', + domain: 'domain', + ref: 'ref', + isAmp: false + } + }; + const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0]; + expect(request).to.have.property('location'); + const location = request.location; + expect(location).to.have.property('page').and.to.equal('page'); + expect(location).to.have.property('location').and.to.equal('location'); + expect(location).to.have.property('domain').and.to.equal('domain'); + expect(location).to.have.property('ref').and.to.equal('ref'); + expect(location).to.have.property('isAmp').and.to.equal(false); + }); + + it('should build request with ortb2 info', function () { + const ortb2Request = deepClone(defaultRequest); + ortb2Request.ortb2 = { + site: { + name: 'name' + } + }; + const request = JSON.parse(spec.buildRequests([ortb2Request], {}).data)[0]; + expect(request).to.have.property('ortb2').and.to.deep.equal({ + site: { + name: 'name' + } + }); + }); + + it('should build request with ortb2Imp info', function () { + const ortb2ImpRequest = deepClone(defaultRequest); + ortb2ImpRequest.ortb2Imp = { + ext: { + data: { + pbadslot: 'home1', + adUnitSpecificAttribute: '1' + } + } + }; + const request = JSON.parse(spec.buildRequests([ortb2ImpRequest], {}).data)[0]; + expect(request).to.have.property('ortb2Imp').and.to.deep.equal({ + ext: { + data: { + pbadslot: 'home1', + adUnitSpecificAttribute: '1' + } + } + }); + }); + + it('should build request with valid bidfloor', function () { + const bfRequest = deepClone(defaultRequest); + bfRequest.getFloor = () => ({ floor: 5, currency: 'USD' }); + const request = JSON.parse(spec.buildRequests([bfRequest], {}).data)[0]; + expect(request).to.have.property('floor').and.to.equal(5); + }); + + it('should build request with usp consent data if applies', function () { + const bidderRequest = { + uspConsent: '1YA-' + }; + const request = JSON.parse(spec.buildRequests([defaultRequest], bidderRequest).data)[0]; + expect(request).to.have.property('usPrivacy').and.equals('1YA-'); + }); + + it('should build request with extended ids', function () { + const idRequest = deepClone(defaultRequest); + idRequest.userIdAsEids = [ + { source: 'adserver.org', uids: [{ id: 'TTD_ID_FROM_USER_ID_MODULE', atype: 1, ext: { rtiPartner: 'TDID' } }] }, + { source: 'pubcid.org', uids: [{ id: 'pubCommonId_FROM_USER_ID_MODULE', atype: 1 }] } + ]; + const request = JSON.parse(spec.buildRequests([idRequest], {}).data)[0]; + expect(request).to.have.property('userEids').and.deep.equal(idRequest.userIdAsEids); + }); + + it('should build request with video', function () { + const request = JSON.parse(spec.buildRequests([defaultRequestVideo], {}).data)[0]; + expect(request).to.have.property('video').and.to.deep.equal({ + playerSize: [640, 480], + context: 'instream', + skipppable: true + }); + expect(request).to.have.property('sizes').and.to.deep.equal(['640x480']); + }); + }); + + describe('interpretResponse', function () { + it('should return empty bids', function () { + const serverResponse = { + body: { + data: null + } + }; + + const invalidResponse = spec.interpretResponse(serverResponse, {}); + expect(invalidResponse).to.be.an('array').that.is.empty; + }); + + it('should interpret valid response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 300, + height: 250, + ttl: 600, + meta: { + advertiserDomains: ['anzuDSP'] + }, + ext: { + pixels: [ + ['iframe', 'surl1'], + ['image', 'surl2'], + ] + } + }] + } + }; + + const validResponse = spec.interpretResponse(serverResponse, { bidderRequest: displayBidderRequest }); + const bid = validResponse[0]; + expect(validResponse).to.be.an('array').that.is.not.empty; + expect(bid.requestId).to.equal('qwerty'); + expect(bid.cpm).to.equal(1); + expect(bid.currency).to.equal('USD'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.ttl).to.equal(600); + expect(bid.meta).to.deep.equal({ advertiserDomains: ['anzuDSP'] }); + }); + + it('should interpret valid banner response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 300, + height: 250, + ttl: 600, + mediaType: 'banner', + creativeId: 'demo-banner', + ad: 'ad', + meta: {} + }] + } + }; + + const validResponseBanner = spec.interpretResponse(serverResponse, { bidderRequest: displayBidderRequest }); + const bid = validResponseBanner[0]; + expect(validResponseBanner).to.be.an('array').that.is.not.empty; + expect(bid.mediaType).to.equal('banner'); + expect(bid.creativeId).to.equal('demo-banner'); + expect(bid.ad).to.equal('ad'); + }); + + it('should interpret valid video response', function () { + const serverResponse = { + body: { + data: [{ + requestId: 'qwerty', + cpm: 1, + currency: 'USD', + width: 600, + height: 480, + ttl: 600, + mediaType: 'video', + creativeId: 'demo-video', + ad: 'vast-xml', + meta: {} + }] + } + }; + + const validResponseBanner = spec.interpretResponse(serverResponse, { bidderRequest: videoBidderRequest }); + const bid = validResponseBanner[0]; + expect(validResponseBanner).to.be.an('array').that.is.not.empty; + expect(bid.mediaType).to.equal('video'); + expect(bid.creativeId).to.equal('demo-video'); + expect(bid.ad).to.equal('vast-xml'); + }); + }); + + describe('getUserSyncs', function () { + it('shoukd handle no params', function () { + const opts = spec.getUserSyncs({}, []); + expect(opts).to.be.an('array').that.is.empty; + }); + + it('should return empty if sync is not allowed', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }); + expect(opts).to.be.an('array').that.is.empty; + }); + + it('should allow iframe sync', function () { + const opts = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: false }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }]); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('iframe'); + expect(opts[0].url).to.equal('surl1?a=b&us_privacy=&gdpr=0&gdpr_consent='); + }); + + it('should allow pixel sync', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }]); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('image'); + expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=0&gdpr_consent='); + }); + + it('should allow pixel sync and parse consent params', function () { + const opts = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, [{ + body: { + data: [{ + requestId: 'qwerty', + ext: { + pixels: [ + ['iframe', 'surl1?a=b'], + ['image', 'surl2?a=b'], + ] + } + }] + } + }], { + gdprApplies: 1, + consentString: '1YA-' + }); + expect(opts.length).to.equal(1); + expect(opts[0].type).to.equal('image'); + expect(opts[0].url).to.equal('surl2?a=b&us_privacy=&gdpr=1&gdpr_consent=1YA-'); + }); + }); + + describe('getBidFloor', function () { + it('should return null when getFloor is not a function', () => { + const bid = { getFloor: 2 }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when getFloor doesnt return an object', () => { + const bid = { getFloor: () => 2 }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when floor is not a number', () => { + const bid = { + getFloor: () => ({ floor: 'string', currency: 'USD' }) + }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return null when currency is not USD', () => { + const bid = { + getFloor: () => ({ floor: 5, currency: 'EUR' }) + }; + const result = getBidFloor(bid); + expect(result).to.be.null; + }); + + it('should return floor value when everything is correct', () => { + const bid = { + getFloor: () => ({ floor: 5, currency: 'USD' }) + }; + const result = getBidFloor(bid); + expect(result).to.equal(5); + }); + }); +}); From 109cf954f8fa143f131d255b85ab933a974f8eb5 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Wed, 27 May 2026 06:31:22 -0400 Subject: [PATCH 003/124] Bliink: Remove GVL_ID from bliinkBidAdapter.js (#14949) * Remove GVL_ID from bliinkBidAdapter.js * Delete gvlid exposure test from bliinkBidAdapter_spec Removed test case for exposing gvlid. --- modules/bliinkBidAdapter.js | 2 -- test/spec/modules/bliinkBidAdapter_spec.js | 5 ----- 2 files changed, 7 deletions(-) diff --git a/modules/bliinkBidAdapter.js b/modules/bliinkBidAdapter.js index be6faec70b6..02917d6d2e3 100644 --- a/modules/bliinkBidAdapter.js +++ b/modules/bliinkBidAdapter.js @@ -2,7 +2,6 @@ import { registerBidder } from '../src/adapters/bidderFactory.js' import { config } from '../src/config.js' import { _each, canAccessWindowTop, deepAccess, deepSetValue, getDomLoadingDuration, getWindowSelf, getWindowTop } from '../src/utils.js' export const BIDDER_CODE = 'bliink' -export const GVL_ID = 658 export const BLIINK_ENDPOINT_ENGINE = 'https://engine.bliink.io/prebid' export const BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME = 'https://tag.bliink.io/usersync.html' @@ -313,7 +312,6 @@ const getUserSyncs = (syncOptions, serverResponses, gdprConsent, uspConsent) => */ export const spec = { code: BIDDER_CODE, - gvlid: GVL_ID, aliases: aliasBidderCode, supportedMediaTypes: supportedMediaTypes, isBidRequestValid, diff --git a/test/spec/modules/bliinkBidAdapter_spec.js b/test/spec/modules/bliinkBidAdapter_spec.js index f0f82e4e846..e423966737d 100644 --- a/test/spec/modules/bliinkBidAdapter_spec.js +++ b/test/spec/modules/bliinkBidAdapter_spec.js @@ -7,7 +7,6 @@ import { BLIINK_ENDPOINT_COOKIE_SYNC_IFRAME, getEffectiveConnectionType, getUserIds, - GVL_ID, } from 'modules/bliinkBidAdapter.js'; import * as utils from 'src/utils.js'; import { config } from 'src/config.js'; @@ -1194,7 +1193,3 @@ describe('getEffectiveConnectionType', () => { }); } }); - -it('should expose gvlid', function () { - expect(spec.gvlid).to.equal(GVL_ID); -}); From 63221cea4302ab07cbde5fbf430d7ce1b0971b14 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Wed, 27 May 2026 07:07:44 -0400 Subject: [PATCH 004/124] RhythmOne Adapter: remove lint exception for size parsing (#14765) * RhythmOne Adapter: remove lint exception for size parsing * Marsmedia Bid Adapter: remove coffee-style lint suppression (#14771) * Core: fix typos in reducers comments (#14768) * Marsmedia Bid Adapter: remove coffee-style lint suppression * Update marsmediaBidAdapter.js --- modules/marsmediaBidAdapter.js | 3 +-- modules/rhythmoneBidAdapter.js | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/marsmediaBidAdapter.js b/modules/marsmediaBidAdapter.js index 074a96b6268..63dc803da9c 100644 --- a/modules/marsmediaBidAdapter.js +++ b/modules/marsmediaBidAdapter.js @@ -101,8 +101,7 @@ function MarsmediaAdapter() { function getValidSizeSet(dimensionList) { const w = parseInt(dimensionList[0]); const h = parseInt(dimensionList[1]); - // clever check for NaN - if (! (w !== w || h !== h)) { // eslint-disable-line + if (!Number.isNaN(w) && !Number.isNaN(h)) { return [w, h]; } return false; diff --git a/modules/rhythmoneBidAdapter.js b/modules/rhythmoneBidAdapter.js index f7518d0d916..869f02a1cec 100644 --- a/modules/rhythmoneBidAdapter.js +++ b/modules/rhythmoneBidAdapter.js @@ -79,8 +79,7 @@ function RhythmOneBidAdapter() { function getValidSizeSet(dimensionList) { const w = parseInt(dimensionList[0]); const h = parseInt(dimensionList[1]); - // clever check for NaN - if (! (w !== w || h !== h)) { // eslint-disable-line + if (!Number.isNaN(w) && !Number.isNaN(h)) { return [w, h]; } return false; From 13f53f297b580ca4ca57208255dc99b107261358 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 27 May 2026 12:20:53 +0000 Subject: [PATCH 005/124] Prebid 11.14.0 release --- .../codeql/queries/autogen_fpDOMMethod.qll | 4 +- .../queries/autogen_fpEventProperty.qll | 16 +-- .../queries/autogen_fpGlobalConstructor.qll | 10 +- .../autogen_fpGlobalObjectProperty0.qll | 52 ++++---- .../autogen_fpGlobalObjectProperty1.qll | 2 +- .../queries/autogen_fpGlobalTypeProperty0.qll | 6 +- .../queries/autogen_fpGlobalTypeProperty1.qll | 2 +- .../codeql/queries/autogen_fpGlobalVar.qll | 18 +-- .../autogen_fpRenderingContextProperty.qll | 30 ++--- .../queries/autogen_fpSensorProperty.qll | 2 +- metadata/modules.json | 30 ++++- metadata/modules/33acrossBidAdapter.json | 2 +- metadata/modules/33acrossIdSystem.json | 2 +- metadata/modules/abtshieldIdSystem.json | 2 +- metadata/modules/aceexBidAdapter.json | 2 +- metadata/modules/acuityadsBidAdapter.json | 2 +- metadata/modules/adagioBidAdapter.json | 2 +- metadata/modules/adagioRtdProvider.json | 2 +- metadata/modules/adbroBidAdapter.json | 2 +- metadata/modules/addefendBidAdapter.json | 2 +- metadata/modules/adfBidAdapter.json | 2 +- metadata/modules/adfusionBidAdapter.json | 2 +- metadata/modules/adkernelAdnBidAdapter.json | 2 +- metadata/modules/adkernelBidAdapter.json | 17 ++- metadata/modules/admaticBidAdapter.json | 4 +- metadata/modules/admixerBidAdapter.json | 2 +- metadata/modules/admixerIdSystem.json | 2 +- metadata/modules/adnowBidAdapter.json | 2 +- metadata/modules/adnuntiusBidAdapter.json | 2 +- metadata/modules/adnuntiusRtdProvider.json | 2 +- metadata/modules/adoceanBidAdapter.json | 2 +- metadata/modules/adotBidAdapter.json | 2 +- metadata/modules/adponeBidAdapter.json | 2 +- metadata/modules/adqueryBidAdapter.json | 2 +- metadata/modules/adqueryIdSystem.json | 2 +- metadata/modules/adrinoBidAdapter.json | 2 +- .../modules/ads_interactiveBidAdapter.json | 2 +- metadata/modules/adtargetBidAdapter.json | 2 +- metadata/modules/adtelligentBidAdapter.json | 4 +- metadata/modules/adtelligentIdSystem.json | 2 +- metadata/modules/aduptechBidAdapter.json | 2 +- metadata/modules/adyoulikeBidAdapter.json | 2 +- metadata/modules/airgridRtdProvider.json | 2 +- metadata/modules/alkimiBidAdapter.json | 2 +- metadata/modules/allegroBidAdapter.json | 2 +- .../modules/alliance_gravityBidAdapter.json | 2 +- metadata/modules/amxBidAdapter.json | 2 +- metadata/modules/amxIdSystem.json | 2 +- metadata/modules/aniviewBidAdapter.json | 2 +- metadata/modules/anonymisedRtdProvider.json | 2 +- metadata/modules/anzuDSPBidAdapter.json | 13 ++ metadata/modules/apesterBidAdapter.json | 2 +- metadata/modules/appStockSSPBidAdapter.json | 2 +- metadata/modules/appierBidAdapter.json | 2 +- metadata/modules/appnexusBidAdapter.json | 6 +- metadata/modules/appushBidAdapter.json | 2 +- metadata/modules/apsBidAdapter.json | 2 +- metadata/modules/apstreamBidAdapter.json | 2 +- metadata/modules/audiencerunBidAdapter.json | 2 +- metadata/modules/axisBidAdapter.json | 2 +- metadata/modules/azerionedgeRtdProvider.json | 2 +- metadata/modules/beachfrontBidAdapter.json | 2 +- metadata/modules/beopBidAdapter.json | 2 +- metadata/modules/betweenBidAdapter.json | 2 +- metadata/modules/bidfuseBidAdapter.json | 2 +- metadata/modules/bidmaticBidAdapter.json | 2 +- metadata/modules/bidtheatreBidAdapter.json | 2 +- metadata/modules/bliinkBidAdapter.json | 11 +- metadata/modules/blockthroughBidAdapter.json | 2 +- metadata/modules/blueBidAdapter.json | 2 +- metadata/modules/bmsBidAdapter.json | 2 +- metadata/modules/boldwinBidAdapter.json | 2 +- metadata/modules/bridBidAdapter.json | 2 +- metadata/modules/browsiBidAdapter.json | 2 +- metadata/modules/bucksenseBidAdapter.json | 2 +- metadata/modules/carodaBidAdapter.json | 2 +- metadata/modules/ceeIdSystem.json | 2 +- metadata/modules/chromeAiRtdProvider.json | 2 +- metadata/modules/clickioBidAdapter.json | 2 +- metadata/modules/compassBidAdapter.json | 2 +- metadata/modules/conceptxBidAdapter.json | 2 +- metadata/modules/connatixBidAdapter.json | 2 +- metadata/modules/connectIdSystem.json | 2 +- metadata/modules/connectadBidAdapter.json | 2 +- .../modules/contentexchangeBidAdapter.json | 2 +- metadata/modules/conversantBidAdapter.json | 2 +- metadata/modules/copper6sspBidAdapter.json | 2 +- metadata/modules/cpmstarBidAdapter.json | 6 +- metadata/modules/criteoBidAdapter.json | 2 +- metadata/modules/criteoIdSystem.json | 2 +- metadata/modules/cwireBidAdapter.json | 2 +- metadata/modules/czechAdIdSystem.json | 2 +- metadata/modules/dailymotionBidAdapter.json | 2 +- metadata/modules/debugging.json | 2 +- metadata/modules/deepintentBidAdapter.json | 2 +- metadata/modules/defineMediaBidAdapter.json | 2 +- metadata/modules/deltaprojectsBidAdapter.json | 2 +- metadata/modules/dianomiBidAdapter.json | 2 +- metadata/modules/digitalMatterBidAdapter.json | 2 +- metadata/modules/distroscaleBidAdapter.json | 2 +- .../modules/docereeAdManagerBidAdapter.json | 2 +- metadata/modules/docereeBidAdapter.json | 2 +- metadata/modules/dspxBidAdapter.json | 2 +- metadata/modules/edge226BidAdapter.json | 2 +- metadata/modules/empowerBidAdapter.json | 2 +- metadata/modules/equativBidAdapter.json | 2 +- metadata/modules/eskimiBidAdapter.json | 2 +- metadata/modules/etargetBidAdapter.json | 2 +- metadata/modules/euidIdSystem.json | 2 +- metadata/modules/exadsBidAdapter.json | 16 +-- metadata/modules/feedadBidAdapter.json | 2 +- metadata/modules/fwsspBidAdapter.json | 2 +- metadata/modules/gamoshiBidAdapter.json | 2 +- metadata/modules/gemiusIdSystem.json | 2 +- metadata/modules/glomexBidAdapter.json | 11 +- metadata/modules/goldbachBidAdapter.json | 120 ++++++++++++++++-- metadata/modules/gridBidAdapter.json | 2 +- metadata/modules/gumgumBidAdapter.json | 2 +- metadata/modules/hadronIdSystem.json | 2 +- metadata/modules/hadronRtdProvider.json | 2 +- metadata/modules/harionBidAdapter.json | 2 +- metadata/modules/holidBidAdapter.json | 2 +- metadata/modules/hubvisorBidAdapter.json | 64 ++++++++++ metadata/modules/hybridBidAdapter.json | 2 +- metadata/modules/id5IdSystem.json | 2 +- metadata/modules/identityLinkIdSystem.json | 2 +- metadata/modules/illuminBidAdapter.json | 2 +- metadata/modules/impactifyBidAdapter.json | 2 +- .../modules/improvedigitalBidAdapter.json | 2 +- metadata/modules/inmobiBidAdapter.json | 2 +- metadata/modules/insticatorBidAdapter.json | 2 +- metadata/modules/insuradsBidAdapter.json | 2 +- metadata/modules/insuradsRtdProvider.json | 2 +- metadata/modules/intentIqIdSystem.json | 2 +- metadata/modules/invibesBidAdapter.json | 2 +- metadata/modules/ipromBidAdapter.json | 2 +- metadata/modules/ixBidAdapter.json | 2 +- metadata/modules/jixieBidAdapter.json | 2 +- metadata/modules/jixieIdSystem.json | 2 +- metadata/modules/justIdSystem.json | 2 +- metadata/modules/justpremiumBidAdapter.json | 2 +- metadata/modules/jwplayerBidAdapter.json | 2 +- metadata/modules/kargoBidAdapter.json | 2 +- metadata/modules/kueezRtbBidAdapter.json | 2 +- .../modules/limelightDigitalBidAdapter.json | 4 +- metadata/modules/liveIntentIdSystem.json | 2 +- metadata/modules/liveIntentRtdProvider.json | 2 +- metadata/modules/livewrappedBidAdapter.json | 2 +- metadata/modules/loopmeBidAdapter.json | 2 +- metadata/modules/lotamePanoramaIdSystem.json | 2 +- metadata/modules/luponmediaBidAdapter.json | 2 +- metadata/modules/madvertiseBidAdapter.json | 2 +- metadata/modules/magniteBidAdapter.json | 2 +- metadata/modules/marsmediaBidAdapter.json | 2 +- metadata/modules/matterfullBidAdapter.json | 13 ++ .../modules/mediaConsortiumBidAdapter.json | 2 +- metadata/modules/mediaforceBidAdapter.json | 2 +- metadata/modules/mediafuseBidAdapter.json | 2 +- metadata/modules/mediagoBidAdapter.json | 2 +- metadata/modules/mediakeysBidAdapter.json | 2 +- metadata/modules/medianetBidAdapter.json | 4 +- metadata/modules/mediasquareBidAdapter.json | 2 +- metadata/modules/mgidBidAdapter.json | 2 +- metadata/modules/mgidRtdProvider.json | 2 +- metadata/modules/mgidXBidAdapter.json | 2 +- metadata/modules/minutemediaBidAdapter.json | 2 +- metadata/modules/missenaBidAdapter.json | 2 +- metadata/modules/mobianRtdProvider.json | 2 +- metadata/modules/mobkoiBidAdapter.json | 2 +- metadata/modules/mobkoiIdSystem.json | 2 +- metadata/modules/msftBidAdapter.json | 2 +- metadata/modules/nativeryBidAdapter.json | 2 +- metadata/modules/nativoBidAdapter.json | 2 +- metadata/modules/newspassidBidAdapter.json | 6 +- .../modules/nextMillenniumBidAdapter.json | 2 +- metadata/modules/nextrollBidAdapter.json | 2 +- metadata/modules/nexx360BidAdapter.json | 70 ++++++++-- metadata/modules/nobidBidAdapter.json | 2 +- metadata/modules/nodalsAiRtdProvider.json | 2 +- metadata/modules/novatiqIdSystem.json | 2 +- metadata/modules/oguryBidAdapter.json | 2 +- metadata/modules/omnidexBidAdapter.json | 2 +- metadata/modules/omsBidAdapter.json | 2 +- metadata/modules/onetagBidAdapter.json | 2 +- metadata/modules/openwebBidAdapter.json | 2 +- metadata/modules/openxBidAdapter.json | 2 +- metadata/modules/operaadsBidAdapter.json | 2 +- metadata/modules/optidigitalBidAdapter.json | 2 +- metadata/modules/optoutBidAdapter.json | 2 +- metadata/modules/orbidderBidAdapter.json | 2 +- metadata/modules/outbrainBidAdapter.json | 2 +- metadata/modules/ozoneBidAdapter.json | 2 +- metadata/modules/pairIdSystem.json | 2 +- metadata/modules/panxoBidAdapter.json | 2 +- metadata/modules/performaxBidAdapter.json | 2 +- .../permutiveIdentityManagerIdSystem.json | 2 +- metadata/modules/permutiveRtdProvider.json | 2 +- metadata/modules/pgamdirectBidAdapter.json | 2 +- metadata/modules/pixfutureBidAdapter.json | 2 +- metadata/modules/playdigoBidAdapter.json | 2 +- metadata/modules/prebid-core.json | 4 +- metadata/modules/precisoBidAdapter.json | 2 +- metadata/modules/prismaBidAdapter.json | 2 +- metadata/modules/programmaticXBidAdapter.json | 2 +- metadata/modules/proxistoreBidAdapter.json | 2 +- metadata/modules/publinkIdSystem.json | 2 +- metadata/modules/pubmaticBidAdapter.json | 2 +- metadata/modules/pubmaticIdSystem.json | 2 +- metadata/modules/pubstackBidAdapter.json | 2 +- metadata/modules/pulsepointBidAdapter.json | 2 +- metadata/modules/r2b2BidAdapter.json | 2 +- metadata/modules/readpeakBidAdapter.json | 2 +- .../modules/relevantdigitalBidAdapter.json | 2 +- metadata/modules/resetdigitalBidAdapter.json | 2 +- metadata/modules/responsiveAdsBidAdapter.json | 2 +- metadata/modules/revantageBidAdapter.json | 2 +- metadata/modules/revcontentBidAdapter.json | 2 +- metadata/modules/revnewBidAdapter.json | 2 +- metadata/modules/rhythmoneBidAdapter.json | 2 +- metadata/modules/richaudienceBidAdapter.json | 2 +- metadata/modules/riseBidAdapter.json | 4 +- metadata/modules/rixengineBidAdapter.json | 2 +- metadata/modules/rtbhouseBidAdapter.json | 108 +++++++++++++++- metadata/modules/rubiconBidAdapter.json | 2 +- metadata/modules/scaliburBidAdapter.json | 2 +- metadata/modules/screencoreBidAdapter.json | 2 +- .../modules/seedingAllianceBidAdapter.json | 2 +- metadata/modules/seedtagBidAdapter.json | 2 +- metadata/modules/selectmediaBidAdapter.json | 2 +- metadata/modules/semantiqRtdProvider.json | 2 +- metadata/modules/setupadBidAdapter.json | 2 +- metadata/modules/sevioBidAdapter.json | 2 +- metadata/modules/sharedIdSystem.json | 2 +- metadata/modules/sharethroughBidAdapter.json | 2 +- metadata/modules/showheroes-bsBidAdapter.json | 2 +- metadata/modules/showheroesBidAdapter.json | 2 +- metadata/modules/silvermobBidAdapter.json | 2 +- metadata/modules/sirdataRtdProvider.json | 2 +- metadata/modules/smaatoBidAdapter.json | 2 +- metadata/modules/smartadserverBidAdapter.json | 2 +- metadata/modules/smartxBidAdapter.json | 2 +- metadata/modules/smartyadsBidAdapter.json | 2 +- metadata/modules/smilewantedBidAdapter.json | 2 +- metadata/modules/snigelBidAdapter.json | 2 +- metadata/modules/sonaradsBidAdapter.json | 2 +- metadata/modules/sonobiBidAdapter.json | 2 +- metadata/modules/sovrnBidAdapter.json | 2 +- metadata/modules/sparteoBidAdapter.json | 2 +- metadata/modules/ssmasBidAdapter.json | 2 +- metadata/modules/sspBCBidAdapter.json | 2 +- metadata/modules/stackadaptBidAdapter.json | 2 +- metadata/modules/startioBidAdapter.json | 2 +- metadata/modules/startioIdSystem.json | 2 +- metadata/modules/stroeerCoreBidAdapter.json | 2 +- metadata/modules/stvBidAdapter.json | 2 +- metadata/modules/sublimeBidAdapter.json | 2 +- metadata/modules/taboolaBidAdapter.json | 2 +- metadata/modules/taboolaIdSystem.json | 2 +- metadata/modules/tadvertisingBidAdapter.json | 2 +- metadata/modules/tappxBidAdapter.json | 2 +- metadata/modules/targetVideoBidAdapter.json | 2 +- metadata/modules/teadsBidAdapter.json | 2 +- metadata/modules/teadsIdSystem.json | 2 +- metadata/modules/tealBidAdapter.json | 2 +- metadata/modules/tncIdSystem.json | 2 +- metadata/modules/tne_catalystBidAdapter.json | 2 +- metadata/modules/topicsFpdModule.json | 2 +- metadata/modules/toponBidAdapter.json | 2 +- metadata/modules/tripleliftBidAdapter.json | 2 +- metadata/modules/ttdBidAdapter.json | 2 +- metadata/modules/twistDigitalBidAdapter.json | 2 +- metadata/modules/underdogmediaBidAdapter.json | 2 +- metadata/modules/undertoneBidAdapter.json | 2 +- metadata/modules/unifiedIdSystem.json | 2 +- metadata/modules/unrulyBidAdapter.json | 2 +- metadata/modules/userId.json | 2 +- metadata/modules/utiqIdSystem.json | 2 +- metadata/modules/utiqMtpIdSystem.json | 2 +- metadata/modules/validationFpdModule.json | 2 +- metadata/modules/valuadBidAdapter.json | 2 +- metadata/modules/vidazooBidAdapter.json | 2 +- metadata/modules/vidoomyBidAdapter.json | 2 +- metadata/modules/viouslyBidAdapter.json | 2 +- metadata/modules/visxBidAdapter.json | 2 +- metadata/modules/vlybyBidAdapter.json | 2 +- metadata/modules/voxBidAdapter.json | 2 +- metadata/modules/vrtcalBidAdapter.json | 2 +- metadata/modules/vuukleBidAdapter.json | 2 +- metadata/modules/weboramaRtdProvider.json | 2 +- metadata/modules/welectBidAdapter.json | 2 +- metadata/modules/wurflRtdProvider.json | 2 +- metadata/modules/yahooAdsBidAdapter.json | 2 +- metadata/modules/yaleoBidAdapter.json | 2 +- metadata/modules/yieldlabBidAdapter.json | 2 +- metadata/modules/yieldloveBidAdapter.json | 2 +- metadata/modules/yieldmoBidAdapter.json | 2 +- metadata/modules/zeotapIdPlusIdSystem.json | 2 +- metadata/modules/zeta_globalBidAdapter.json | 2 +- .../modules/zeta_global_sspBidAdapter.json | 2 +- package-lock.json | 4 +- package.json | 2 +- 301 files changed, 790 insertions(+), 411 deletions(-) create mode 100644 metadata/modules/anzuDSPBidAdapter.json create mode 100644 metadata/modules/hubvisorBidAdapter.json create mode 100644 metadata/modules/matterfullBidAdapter.json diff --git a/.github/codeql/queries/autogen_fpDOMMethod.qll b/.github/codeql/queries/autogen_fpDOMMethod.qll index 23f12571485..e58e7d386d6 100644 --- a/.github/codeql/queries/autogen_fpDOMMethod.qll +++ b/.github/codeql/queries/autogen_fpDOMMethod.qll @@ -7,9 +7,9 @@ class DOMMethod extends string { DOMMethod() { - ( this = "getChannelData" and weight = 1083.37 and type = "AudioBuffer" ) + ( this = "getChannelData" and weight = 961.14 and type = "AudioBuffer" ) or - ( this = "toDataURL" and weight = 27.64 and type = "HTMLCanvasElement" ) + ( this = "toDataURL" and weight = 29.48 and type = "HTMLCanvasElement" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpEventProperty.qll b/.github/codeql/queries/autogen_fpEventProperty.qll index d0a78338953..64387e2fb6b 100644 --- a/.github/codeql/queries/autogen_fpEventProperty.qll +++ b/.github/codeql/queries/autogen_fpEventProperty.qll @@ -7,21 +7,21 @@ class EventProperty extends string { EventProperty() { - ( this = "accelerationIncludingGravity" and weight = 159.98 and event = "devicemotion" ) + ( this = "beta" and weight = 825.35 and event = "deviceorientation" ) or - ( this = "beta" and weight = 851.21 and event = "deviceorientation" ) + ( this = "gamma" and weight = 277.66 and event = "deviceorientation" ) or - ( this = "gamma" and weight = 303.39 and event = "deviceorientation" ) + ( this = "alpha" and weight = 797.61 and event = "deviceorientation" ) or - ( this = "alpha" and weight = 768.07 and event = "deviceorientation" ) + ( this = "accelerationIncludingGravity" and weight = 85.16 and event = "devicemotion" ) or - ( this = "candidate" and weight = 45.34 and event = "icecandidate" ) + ( this = "candidate" and weight = 46.81 and event = "icecandidate" ) or - ( this = "acceleration" and weight = 63.39 and event = "devicemotion" ) + ( this = "acceleration" and weight = 37.23 and event = "devicemotion" ) or - ( this = "rotationRate" and weight = 63.13 and event = "devicemotion" ) + ( this = "rotationRate" and weight = 37.29 and event = "devicemotion" ) or - ( this = "absolute" and weight = 402.37 and event = "deviceorientation" ) + ( this = "absolute" and weight = 282.58 and event = "deviceorientation" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalConstructor.qll b/.github/codeql/queries/autogen_fpGlobalConstructor.qll index 9c898c369d9..7729f4556e4 100644 --- a/.github/codeql/queries/autogen_fpGlobalConstructor.qll +++ b/.github/codeql/queries/autogen_fpGlobalConstructor.qll @@ -6,15 +6,15 @@ class GlobalConstructor extends string { GlobalConstructor() { - ( this = "OfflineAudioContext" and weight = 225.31 ) + ( this = "OfflineAudioContext" and weight = 190.93 ) or - ( this = "RTCPeerConnection" and weight = 34.53 ) + ( this = "RTCPeerConnection" and weight = 34.85 ) or - ( this = "SharedWorker" and weight = 75.74 ) + ( this = "SharedWorker" and weight = 85.13 ) or - ( this = "Gyroscope" and weight = 50.8 ) + ( this = "Gyroscope" and weight = 55.85 ) or - ( this = "AudioWorkletNode" and weight = 119.39 ) + ( this = "AudioWorkletNode" and weight = 99.28 ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll b/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll index dfa86fe9d3f..5ba326f0abe 100644 --- a/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll +++ b/.github/codeql/queries/autogen_fpGlobalObjectProperty0.qll @@ -7,57 +7,57 @@ class GlobalObjectProperty0 extends string { GlobalObjectProperty0() { - ( this = "availHeight" and weight = 89.13 and global0 = "screen" ) + ( this = "availHeight" and weight = 92.62 and global0 = "screen" ) or - ( this = "availWidth" and weight = 84.67 and global0 = "screen" ) + ( this = "availWidth" and weight = 87.21 and global0 = "screen" ) or - ( this = "colorDepth" and weight = 42.61 and global0 = "screen" ) + ( this = "colorDepth" and weight = 42.11 and global0 = "screen" ) or - ( this = "availTop" and weight = 1275.07 and global0 = "screen" ) + ( this = "availTop" and weight = 1177.28 and global0 = "screen" ) or - ( this = "permissions" and weight = 70.37 and global0 = "navigator" ) + ( this = "deviceMemory" and weight = 58.68 and global0 = "navigator" ) or - ( this = "deviceMemory" and weight = 59.45 and global0 = "navigator" ) + ( this = "getBattery" and weight = 36.33 and global0 = "navigator" ) or - ( this = "onLine" and weight = 19.95 and global0 = "navigator" ) + ( this = "webdriver" and weight = 26.58 and global0 = "navigator" ) or - ( this = "mediaCapabilities" and weight = 33.73 and global0 = "navigator" ) + ( this = "permission" and weight = 26.35 and global0 = "Notification" ) or - ( this = "pixelDepth" and weight = 49.23 and global0 = "screen" ) + ( this = "storage" and weight = 40.24 and global0 = "navigator" ) or - ( this = "permission" and weight = 24.75 and global0 = "Notification" ) + ( this = "orientation" and weight = 35.31 and global0 = "screen" ) or - ( this = "webdriver" and weight = 26.06 and global0 = "navigator" ) + ( this = "onLine" and weight = 20.53 and global0 = "navigator" ) or - ( this = "getBattery" and weight = 36.56 and global0 = "navigator" ) + ( this = "permissions" and weight = 68.24 and global0 = "navigator" ) or - ( this = "availLeft" and weight = 653.43 and global0 = "screen" ) + ( this = "productSub" and weight = 372.57 and global0 = "navigator" ) or - ( this = "mediaDevices" and weight = 148 and global0 = "navigator" ) + ( this = "hardwareConcurrency" and weight = 71.26 and global0 = "navigator" ) or - ( this = "hardwareConcurrency" and weight = 69.85 and global0 = "navigator" ) + ( this = "mediaCapabilities" and weight = 35.37 and global0 = "navigator" ) or - ( this = "keyboard" and weight = 2171.11 and global0 = "navigator" ) + ( this = "availLeft" and weight = 597.75 and global0 = "screen" ) or - ( this = "appCodeName" and weight = 167.15 and global0 = "navigator" ) + ( this = "mediaDevices" and weight = 147.52 and global0 = "navigator" ) or - ( this = "webkitTemporaryStorage" and weight = 38.32 and global0 = "navigator" ) + ( this = "keyboard" and weight = 2226.57 and global0 = "navigator" ) or - ( this = "vendorSub" and weight = 2404.06 and global0 = "navigator" ) + ( this = "appCodeName" and weight = 163.59 and global0 = "navigator" ) or - ( this = "productSub" and weight = 372.86 and global0 = "navigator" ) + ( this = "pixelDepth" and weight = 54 and global0 = "screen" ) or - ( this = "webkitPersistentStorage" and weight = 129.8 and global0 = "navigator" ) + ( this = "requestMediaKeySystemAccess" and weight = 34.75 and global0 = "navigator" ) or - ( this = "storage" and weight = 39.68 and global0 = "navigator" ) + ( this = "webkitTemporaryStorage" and weight = 38.03 and global0 = "navigator" ) or - ( this = "presentation" and weight = 30.64 and global0 = "navigator" ) + ( this = "vendorSub" and weight = 2115.03 and global0 = "navigator" ) or - ( this = "orientation" and weight = 35.14 and global0 = "screen" ) + ( this = "webkitPersistentStorage" and weight = 118.76 and global0 = "navigator" ) or - ( this = "getGamepads" and weight = 214.18 and global0 = "navigator" ) + ( this = "presentation" and weight = 32.7 and global0 = "navigator" ) or - ( this = "requestMediaKeySystemAccess" and weight = 35.23 and global0 = "navigator" ) + ( this = "getGamepads" and weight = 187.64 and global0 = "navigator" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll b/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll index 55bf499c839..a39291b76d9 100644 --- a/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll +++ b/.github/codeql/queries/autogen_fpGlobalObjectProperty1.qll @@ -8,7 +8,7 @@ class GlobalObjectProperty1 extends string { GlobalObjectProperty1() { - ( this = "enumerateDevices" and weight = 652.16 and global0 = "navigator" and global1 = "mediaDevices" ) + ( this = "enumerateDevices" and weight = 703.57 and global0 = "navigator" and global1 = "mediaDevices" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll b/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll index 2336aed35f0..1053bde4e19 100644 --- a/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll +++ b/.github/codeql/queries/autogen_fpGlobalTypeProperty0.qll @@ -7,11 +7,11 @@ class GlobalTypeProperty0 extends string { GlobalTypeProperty0() { - ( this = "x" and weight = 4676.46 and global0 = "Gyroscope" ) + ( this = "x" and weight = 2790.72 and global0 = "Gyroscope" ) or - ( this = "y" and weight = 4676.46 and global0 = "Gyroscope" ) + ( this = "y" and weight = 2790.72 and global0 = "Gyroscope" ) or - ( this = "z" and weight = 4676.46 and global0 = "Gyroscope" ) + ( this = "z" and weight = 2790.72 and global0 = "Gyroscope" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll b/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll index aa09218f981..94263afd9df 100644 --- a/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll +++ b/.github/codeql/queries/autogen_fpGlobalTypeProperty1.qll @@ -8,7 +8,7 @@ class GlobalTypeProperty1 extends string { GlobalTypeProperty1() { - ( this = "resolvedOptions" and weight = 21.29 and global0 = "Intl" and global1 = "DateTimeFormat" ) + ( this = "resolvedOptions" and weight = 21.19 and global0 = "Intl" and global1 = "DateTimeFormat" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpGlobalVar.qll b/.github/codeql/queries/autogen_fpGlobalVar.qll index dfa18ca9f42..003bfdaf4c4 100644 --- a/.github/codeql/queries/autogen_fpGlobalVar.qll +++ b/.github/codeql/queries/autogen_fpGlobalVar.qll @@ -6,23 +6,23 @@ class GlobalVar extends string { GlobalVar() { - ( this = "devicePixelRatio" and weight = 16.11 ) + ( this = "devicePixelRatio" and weight = 15.26 ) or - ( this = "screenX" and weight = 378.78 ) + ( this = "screenX" and weight = 391.09 ) or - ( this = "screenY" and weight = 349.03 ) + ( this = "screenY" and weight = 359.23 ) or - ( this = "outerWidth" and weight = 110.41 ) + ( this = "outerWidth" and weight = 115.95 ) or - ( this = "outerHeight" and weight = 160.29 ) + ( this = "outerHeight" and weight = 174.07 ) or - ( this = "screenLeft" and weight = 380.11 ) + ( this = "screenLeft" and weight = 379.3 ) or - ( this = "screenTop" and weight = 381.44 ) + ( this = "screenTop" and weight = 377.73 ) or - ( this = "indexedDB" and weight = 22.05 ) + ( this = "indexedDB" and weight = 21.74 ) or - ( this = "openDatabase" and weight = 32.51 ) + ( this = "openDatabase" and weight = 33.54 ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpRenderingContextProperty.qll b/.github/codeql/queries/autogen_fpRenderingContextProperty.qll index 1a99f02d32e..7dac3f11e55 100644 --- a/.github/codeql/queries/autogen_fpRenderingContextProperty.qll +++ b/.github/codeql/queries/autogen_fpRenderingContextProperty.qll @@ -7,35 +7,35 @@ class RenderingContextProperty extends string { RenderingContextProperty() { - ( this = "getExtension" and weight = 27.52 and contextType = "webgl" ) + ( this = "getExtension" and weight = 25.36 and contextType = "webgl" ) or - ( this = "getParameter" and weight = 30.5 and contextType = "webgl" ) + ( this = "getParameter" and weight = 28.29 and contextType = "webgl" ) or - ( this = "isPointInPath" and weight = 4676.46 and contextType = "2d" ) + ( this = "getImageData" and weight = 59.7 and contextType = "2d" ) or - ( this = "getSupportedExtensions" and weight = 1324.74 and contextType = "webgl" ) + ( this = "readPixels" and weight = 57.25 and contextType = "webgl" ) or - ( this = "getContextAttributes" and weight = 2060.8 and contextType = "webgl" ) + ( this = "getExtension" and weight = 79.37 and contextType = "webgl2" ) or - ( this = "getShaderPrecisionFormat" and weight = 1194.85 and contextType = "webgl" ) + ( this = "getParameter" and weight = 73.14 and contextType = "webgl2" ) or - ( this = "getExtension" and weight = 75.32 and contextType = "webgl2" ) + ( this = "getSupportedExtensions" and weight = 285.4 and contextType = "webgl2" ) or - ( this = "getParameter" and weight = 74.54 and contextType = "webgl2" ) + ( this = "getContextAttributes" and weight = 188.52 and contextType = "webgl2" ) or - ( this = "getSupportedExtensions" and weight = 340.32 and contextType = "webgl2" ) + ( this = "getShaderPrecisionFormat" and weight = 134.03 and contextType = "webgl2" ) or - ( this = "getContextAttributes" and weight = 176.36 and contextType = "webgl2" ) + ( this = "getSupportedExtensions" and weight = 1478.73 and contextType = "webgl" ) or - ( this = "getShaderPrecisionFormat" and weight = 127.49 and contextType = "webgl2" ) + ( this = "isPointInPath" and weight = 2790.72 and contextType = "2d" ) or - ( this = "getImageData" and weight = 60.04 and contextType = "2d" ) + ( this = "getContextAttributes" and weight = 2323.65 and contextType = "webgl" ) or - ( this = "readPixels" and weight = 40.63 and contextType = "webgl" ) + ( this = "getShaderPrecisionFormat" and weight = 1379.72 and contextType = "webgl" ) or - ( this = "readPixels" and weight = 805.02 and contextType = "webgl2" ) + ( this = "readPixels" and weight = 1032.99 and contextType = "webgl2" ) or - ( this = "measureText" and weight = 37.13 and contextType = "2d" ) + ( this = "measureText" and weight = 52.44 and contextType = "2d" ) } float getWeight() { diff --git a/.github/codeql/queries/autogen_fpSensorProperty.qll b/.github/codeql/queries/autogen_fpSensorProperty.qll index 9984b83b315..bb0f892a251 100644 --- a/.github/codeql/queries/autogen_fpSensorProperty.qll +++ b/.github/codeql/queries/autogen_fpSensorProperty.qll @@ -6,7 +6,7 @@ class SensorProperty extends string { SensorProperty() { - ( this = "start" and weight = 52.76 ) + ( this = "start" and weight = 51.87 ) } float getWeight() { diff --git a/metadata/modules.json b/metadata/modules.json index b7897c6a115..00d78021fe8 100644 --- a/metadata/modules.json +++ b/metadata/modules.json @@ -547,6 +547,13 @@ "gvlid": null, "disclosureURL": null }, + { + "componentType": "bidder", + "componentName": "reload", + "aliasOf": "adkernel", + "gvlid": null, + "disclosureURL": null + }, { "componentType": "bidder", "componentName": "admaru", @@ -1198,6 +1205,13 @@ "gvlid": null, "disclosureURL": null }, + { + "componentType": "bidder", + "componentName": "anzuDSP", + "aliasOf": null, + "gvlid": null, + "disclosureURL": null + }, { "componentType": "bidder", "componentName": "anzuSSP", @@ -1636,7 +1650,7 @@ "componentType": "bidder", "componentName": "bliink", "aliasOf": null, - "gvlid": 658, + "gvlid": null, "disclosureURL": null }, { @@ -2619,6 +2633,13 @@ "gvlid": 1177, "disclosureURL": null }, + { + "componentType": "bidder", + "componentName": "hubvisor", + "aliasOf": null, + "gvlid": 1112, + "disclosureURL": null + }, { "componentType": "bidder", "componentName": "hybrid", @@ -3207,6 +3228,13 @@ "gvlid": null, "disclosureURL": null }, + { + "componentType": "bidder", + "componentName": "matterfull", + "aliasOf": null, + "gvlid": null, + "disclosureURL": null + }, { "componentType": "bidder", "componentName": "mediaConsortium", diff --git a/metadata/modules/33acrossBidAdapter.json b/metadata/modules/33acrossBidAdapter.json index 1a48f257c99..e20d4086224 100644 --- a/metadata/modules/33acrossBidAdapter.json +++ b/metadata/modules/33acrossBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://platform.33across.com/disclosures.json": { - "timestamp": "2026-05-18T20:03:46.498Z", + "timestamp": "2026-05-27T12:17:29.215Z", "disclosures": [] } }, diff --git a/metadata/modules/33acrossIdSystem.json b/metadata/modules/33acrossIdSystem.json index 91ca50da896..ad5a9a33c35 100644 --- a/metadata/modules/33acrossIdSystem.json +++ b/metadata/modules/33acrossIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://platform.33across.com/disclosures.json": { - "timestamp": "2026-05-18T20:03:46.540Z", + "timestamp": "2026-05-27T12:17:29.317Z", "disclosures": [] } }, diff --git a/metadata/modules/abtshieldIdSystem.json b/metadata/modules/abtshieldIdSystem.json index a2038467deb..b831496b214 100644 --- a/metadata/modules/abtshieldIdSystem.json +++ b/metadata/modules/abtshieldIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d1.abtshield.com/disclosures.json": { - "timestamp": "2026-05-18T20:03:46.542Z", + "timestamp": "2026-05-27T12:17:29.319Z", "disclosures": [] } }, diff --git a/metadata/modules/aceexBidAdapter.json b/metadata/modules/aceexBidAdapter.json index 2803725870a..4bd6be65eba 100644 --- a/metadata/modules/aceexBidAdapter.json +++ b/metadata/modules/aceexBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://aceex.io/tcf.json": { - "timestamp": "2026-05-18T20:03:47.151Z", + "timestamp": "2026-05-27T12:17:29.956Z", "disclosures": [] } }, diff --git a/metadata/modules/acuityadsBidAdapter.json b/metadata/modules/acuityadsBidAdapter.json index f986dfebf73..f5a8f863f20 100644 --- a/metadata/modules/acuityadsBidAdapter.json +++ b/metadata/modules/acuityadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.acuityads.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:03:47.482Z", + "timestamp": "2026-05-27T12:17:30.166Z", "disclosures": [] } }, diff --git a/metadata/modules/adagioBidAdapter.json b/metadata/modules/adagioBidAdapter.json index ea55ceb2f16..27f5327db51 100644 --- a/metadata/modules/adagioBidAdapter.json +++ b/metadata/modules/adagioBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adagio.io/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:03:47.596Z", + "timestamp": "2026-05-27T12:17:30.215Z", "disclosures": [] } }, diff --git a/metadata/modules/adagioRtdProvider.json b/metadata/modules/adagioRtdProvider.json index feec6bd8594..e6d52808a44 100644 --- a/metadata/modules/adagioRtdProvider.json +++ b/metadata/modules/adagioRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adagio.io/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:03:47.663Z", + "timestamp": "2026-05-27T12:17:30.425Z", "disclosures": [] } }, diff --git a/metadata/modules/adbroBidAdapter.json b/metadata/modules/adbroBidAdapter.json index f28c46a9ac1..c24a36eb2ac 100644 --- a/metadata/modules/adbroBidAdapter.json +++ b/metadata/modules/adbroBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tag.adbro.me/privacy/devicestorage.json": { - "timestamp": "2026-05-18T20:03:47.663Z", + "timestamp": "2026-05-27T12:17:30.425Z", "disclosures": [] } }, diff --git a/metadata/modules/addefendBidAdapter.json b/metadata/modules/addefendBidAdapter.json index 7580390941b..fbb1a91cafc 100644 --- a/metadata/modules/addefendBidAdapter.json +++ b/metadata/modules/addefendBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.addefend.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:47.780Z", + "timestamp": "2026-05-27T12:17:30.460Z", "disclosures": [] } }, diff --git a/metadata/modules/adfBidAdapter.json b/metadata/modules/adfBidAdapter.json index bdd1805748f..24411d54d8d 100644 --- a/metadata/modules/adfBidAdapter.json +++ b/metadata/modules/adfBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://site.adform.com/assets/devicestorage.json": { - "timestamp": "2026-05-18T20:03:49.053Z", + "timestamp": "2026-05-27T12:17:31.287Z", "disclosures": [] } }, diff --git a/metadata/modules/adfusionBidAdapter.json b/metadata/modules/adfusionBidAdapter.json index 5a42c45181c..4004ccc6f87 100644 --- a/metadata/modules/adfusionBidAdapter.json +++ b/metadata/modules/adfusionBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://spicyrtb.com/static/iab-disclosure.json": { - "timestamp": "2026-05-18T20:03:49.053Z", + "timestamp": "2026-05-27T12:17:31.287Z", "disclosures": [] } }, diff --git a/metadata/modules/adkernelAdnBidAdapter.json b/metadata/modules/adkernelAdnBidAdapter.json index 2a3b3121eb1..a274b751c30 100644 --- a/metadata/modules/adkernelAdnBidAdapter.json +++ b/metadata/modules/adkernelAdnBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.adkernel.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:50.230Z", + "timestamp": "2026-05-27T12:18:05.688Z", "disclosures": [ { "identifier": "adk_rtb_conv_id", diff --git a/metadata/modules/adkernelBidAdapter.json b/metadata/modules/adkernelBidAdapter.json index 812751b86dd..ca4bf6e4fd2 100644 --- a/metadata/modules/adkernelBidAdapter.json +++ b/metadata/modules/adkernelBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.adkernel.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:50.325Z", + "timestamp": "2026-05-27T12:18:05.738Z", "disclosures": [ { "identifier": "adk_rtb_conv_id", @@ -17,19 +17,19 @@ ] }, "https://data.converge-digital.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:50.325Z", + "timestamp": "2026-05-27T12:18:05.738Z", "disclosures": [] }, "https://spinx.biz/tcf-spinx.json": { - "timestamp": "2026-05-18T20:03:50.496Z", + "timestamp": "2026-05-27T12:18:05.962Z", "disclosures": [] }, "https://gdpr.memob.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:51.242Z", + "timestamp": "2026-05-27T12:18:06.662Z", "disclosures": [] }, "https://appmonsta.ai/DeviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:03:51.378Z", + "timestamp": "2026-05-27T12:18:06.761Z", "disclosures": [] } }, @@ -355,6 +355,13 @@ "aliasOf": "adkernel", "gvlid": null, "disclosureURL": null + }, + { + "componentType": "bidder", + "componentName": "reload", + "aliasOf": "adkernel", + "gvlid": null, + "disclosureURL": null } ] } \ No newline at end of file diff --git a/metadata/modules/admaticBidAdapter.json b/metadata/modules/admaticBidAdapter.json index 61ec2422b4f..d9f31267986 100644 --- a/metadata/modules/admaticBidAdapter.json +++ b/metadata/modules/admaticBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.admatic.de/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-18T20:03:53.201Z", + "timestamp": "2026-05-27T12:18:07.811Z", "disclosures": [ { "identifier": "px_pbjs", @@ -12,7 +12,7 @@ ] }, "https://adtarget.com.tr/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:53.201Z", + "timestamp": "2026-05-27T12:18:07.811Z", "disclosures": [ { "identifier": "adt_pbjs", diff --git a/metadata/modules/admixerBidAdapter.json b/metadata/modules/admixerBidAdapter.json index cc588a6e056..b5fac8daebb 100644 --- a/metadata/modules/admixerBidAdapter.json +++ b/metadata/modules/admixerBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admixer.com/tcf.json": { - "timestamp": "2026-05-18T20:03:53.201Z", + "timestamp": "2026-05-27T12:18:07.812Z", "disclosures": [] } }, diff --git a/metadata/modules/admixerIdSystem.json b/metadata/modules/admixerIdSystem.json index d719fd97325..bb56b549cdb 100644 --- a/metadata/modules/admixerIdSystem.json +++ b/metadata/modules/admixerIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admixer.com/tcf.json": { - "timestamp": "2026-05-18T20:03:53.867Z", + "timestamp": "2026-05-27T12:18:08.272Z", "disclosures": [] } }, diff --git a/metadata/modules/adnowBidAdapter.json b/metadata/modules/adnowBidAdapter.json index 75c80430850..82cdb641292 100644 --- a/metadata/modules/adnowBidAdapter.json +++ b/metadata/modules/adnowBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adnow.com/vdsod.json": { - "timestamp": "2026-05-18T20:03:53.867Z", + "timestamp": "2026-05-27T12:18:08.272Z", "disclosures": [ { "identifier": "SC_unique_*", diff --git a/metadata/modules/adnuntiusBidAdapter.json b/metadata/modules/adnuntiusBidAdapter.json index 090367b20ac..5089bb4149d 100644 --- a/metadata/modules/adnuntiusBidAdapter.json +++ b/metadata/modules/adnuntiusBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.adnuntius.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:54.206Z", + "timestamp": "2026-05-27T12:18:08.534Z", "disclosures": [ { "identifier": "adn.metaData", diff --git a/metadata/modules/adnuntiusRtdProvider.json b/metadata/modules/adnuntiusRtdProvider.json index 0bdc946d731..9dd74cd4a36 100644 --- a/metadata/modules/adnuntiusRtdProvider.json +++ b/metadata/modules/adnuntiusRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.adnuntius.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:54.605Z", + "timestamp": "2026-05-27T12:18:08.864Z", "disclosures": [ { "identifier": "adn.metaData", diff --git a/metadata/modules/adoceanBidAdapter.json b/metadata/modules/adoceanBidAdapter.json index ccdb9df5ccf..3e07d220872 100644 --- a/metadata/modules/adoceanBidAdapter.json +++ b/metadata/modules/adoceanBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gemius.com/media/documents/Gemius_SA_Vendor_Device_Storage.json": { - "timestamp": "2026-05-18T20:03:54.605Z", + "timestamp": "2026-05-27T12:18:08.864Z", "disclosures": [ { "identifier": "__gsyncs_gdpr", diff --git a/metadata/modules/adotBidAdapter.json b/metadata/modules/adotBidAdapter.json index 2cee3f9dae1..da6babeb8eb 100644 --- a/metadata/modules/adotBidAdapter.json +++ b/metadata/modules/adotBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.adotmob.com/tcf/tcf.json": { - "timestamp": "2026-05-18T20:03:55.503Z", + "timestamp": "2026-05-27T12:18:09.650Z", "disclosures": [] } }, diff --git a/metadata/modules/adponeBidAdapter.json b/metadata/modules/adponeBidAdapter.json index d63a8f7e80a..ce1c8f6f6d7 100644 --- a/metadata/modules/adponeBidAdapter.json +++ b/metadata/modules/adponeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserver.adpone.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:55.579Z", + "timestamp": "2026-05-27T12:18:09.751Z", "disclosures": [] } }, diff --git a/metadata/modules/adqueryBidAdapter.json b/metadata/modules/adqueryBidAdapter.json index 041c5531c5a..f1a3ad5c617 100644 --- a/metadata/modules/adqueryBidAdapter.json +++ b/metadata/modules/adqueryBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.adquery.io/tcf/adQuery.json": { - "timestamp": "2026-05-18T20:03:55.710Z", + "timestamp": "2026-05-27T12:18:09.902Z", "disclosures": [] } }, diff --git a/metadata/modules/adqueryIdSystem.json b/metadata/modules/adqueryIdSystem.json index ad4592421ba..a8b20e4fbc4 100644 --- a/metadata/modules/adqueryIdSystem.json +++ b/metadata/modules/adqueryIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.adquery.io/tcf/adQuery.json": { - "timestamp": "2026-05-18T20:03:56.109Z", + "timestamp": "2026-05-27T12:18:10.244Z", "disclosures": [] } }, diff --git a/metadata/modules/adrinoBidAdapter.json b/metadata/modules/adrinoBidAdapter.json index 3ba0cf449b8..3b71a80623e 100644 --- a/metadata/modules/adrinoBidAdapter.json +++ b/metadata/modules/adrinoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.adrino.cloud/iab/device-storage.json": { - "timestamp": "2026-05-18T20:03:56.110Z", + "timestamp": "2026-05-27T12:18:10.245Z", "disclosures": [] } }, diff --git a/metadata/modules/ads_interactiveBidAdapter.json b/metadata/modules/ads_interactiveBidAdapter.json index 6c84813bd09..e263a9aeeac 100644 --- a/metadata/modules/ads_interactiveBidAdapter.json +++ b/metadata/modules/ads_interactiveBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adsinteractive.com/vendor.json": { - "timestamp": "2026-05-18T20:03:56.151Z", + "timestamp": "2026-05-27T12:18:10.328Z", "disclosures": [] } }, diff --git a/metadata/modules/adtargetBidAdapter.json b/metadata/modules/adtargetBidAdapter.json index 739e09a9cf1..899731be23e 100644 --- a/metadata/modules/adtargetBidAdapter.json +++ b/metadata/modules/adtargetBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtarget.com.tr/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:56.518Z", + "timestamp": "2026-05-27T12:18:10.642Z", "disclosures": [ { "identifier": "adt_pbjs", diff --git a/metadata/modules/adtelligentBidAdapter.json b/metadata/modules/adtelligentBidAdapter.json index 77eab212749..9dc3893a9c8 100644 --- a/metadata/modules/adtelligentBidAdapter.json +++ b/metadata/modules/adtelligentBidAdapter.json @@ -2,11 +2,11 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtelligent.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:56.519Z", + "timestamp": "2026-05-27T12:18:10.643Z", "disclosures": [] }, "https://orangeclickmedia.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:03:56.979Z", + "timestamp": "2026-05-27T12:18:10.660Z", "disclosures": [] } }, diff --git a/metadata/modules/adtelligentIdSystem.json b/metadata/modules/adtelligentIdSystem.json index 981cf66be2f..3f991204ae4 100644 --- a/metadata/modules/adtelligentIdSystem.json +++ b/metadata/modules/adtelligentIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtelligent.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:57.132Z", + "timestamp": "2026-05-27T12:18:10.796Z", "disclosures": [] } }, diff --git a/metadata/modules/aduptechBidAdapter.json b/metadata/modules/aduptechBidAdapter.json index e6d9fcce63c..7a65ce67ba4 100644 --- a/metadata/modules/aduptechBidAdapter.json +++ b/metadata/modules/aduptechBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.d.adup-tech.com/gdpr/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:57.133Z", + "timestamp": "2026-05-27T12:18:10.796Z", "disclosures": [] } }, diff --git a/metadata/modules/adyoulikeBidAdapter.json b/metadata/modules/adyoulikeBidAdapter.json index 98b2f800c1d..f8a327fd4c0 100644 --- a/metadata/modules/adyoulikeBidAdapter.json +++ b/metadata/modules/adyoulikeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adyoulike.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-18T20:03:57.233Z", + "timestamp": "2026-05-27T12:18:10.854Z", "disclosures": [] } }, diff --git a/metadata/modules/airgridRtdProvider.json b/metadata/modules/airgridRtdProvider.json index 6b739860344..aa5631a9a02 100644 --- a/metadata/modules/airgridRtdProvider.json +++ b/metadata/modules/airgridRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.wearemiq.com/privacy-and-compliance/devicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:03:57.863Z", + "timestamp": "2026-05-27T12:18:11.439Z", "disclosures": [] } }, diff --git a/metadata/modules/alkimiBidAdapter.json b/metadata/modules/alkimiBidAdapter.json index ae6a931d746..334f02524e8 100644 --- a/metadata/modules/alkimiBidAdapter.json +++ b/metadata/modules/alkimiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d1xjh92lb8fey3.cloudfront.net/tcf/alkimi_exchange_tcf.json": { - "timestamp": "2026-05-18T20:03:58.032Z", + "timestamp": "2026-05-27T12:18:11.580Z", "disclosures": [] } }, diff --git a/metadata/modules/allegroBidAdapter.json b/metadata/modules/allegroBidAdapter.json index e0d5dc82908..9a2fe9cd1fb 100644 --- a/metadata/modules/allegroBidAdapter.json +++ b/metadata/modules/allegroBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.allegrostatic.com/dsp-tcf-external/device-storage.json": { - "timestamp": "2026-05-18T20:03:58.446Z", + "timestamp": "2026-05-27T12:18:11.956Z", "disclosures": [] } }, diff --git a/metadata/modules/alliance_gravityBidAdapter.json b/metadata/modules/alliance_gravityBidAdapter.json index 40f8333441f..0f793ebb5f9 100644 --- a/metadata/modules/alliance_gravityBidAdapter.json +++ b/metadata/modules/alliance_gravityBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.alliancegravity.com/tcf-vendor-info.json": { - "timestamp": "2026-05-18T20:03:59.184Z", + "timestamp": "2026-05-27T12:18:12.415Z", "disclosures": [] } }, diff --git a/metadata/modules/amxBidAdapter.json b/metadata/modules/amxBidAdapter.json index 88d3364a934..81868e6e09a 100644 --- a/metadata/modules/amxBidAdapter.json +++ b/metadata/modules/amxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.a-mo.net/tcf/device-storage.json": { - "timestamp": "2026-05-18T20:03:59.852Z", + "timestamp": "2026-05-27T12:18:12.967Z", "disclosures": [ { "identifier": "amuid2", diff --git a/metadata/modules/amxIdSystem.json b/metadata/modules/amxIdSystem.json index cfebcb1a6c2..6105e7a2bdd 100644 --- a/metadata/modules/amxIdSystem.json +++ b/metadata/modules/amxIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.a-mo.net/tcf/device-storage.json": { - "timestamp": "2026-05-18T20:03:59.941Z", + "timestamp": "2026-05-27T12:18:13.076Z", "disclosures": [ { "identifier": "amuid2", diff --git a/metadata/modules/aniviewBidAdapter.json b/metadata/modules/aniviewBidAdapter.json index b540dfb36d5..7cee4d2e888 100644 --- a/metadata/modules/aniviewBidAdapter.json +++ b/metadata/modules/aniviewBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://player.aniview.com/gdpr/gdpr.json": { - "timestamp": "2026-05-18T20:03:59.941Z", + "timestamp": "2026-05-27T12:18:13.076Z", "disclosures": [ { "identifier": "av_*", diff --git a/metadata/modules/anonymisedRtdProvider.json b/metadata/modules/anonymisedRtdProvider.json index b326a6e0424..0ad41428f58 100644 --- a/metadata/modules/anonymisedRtdProvider.json +++ b/metadata/modules/anonymisedRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn1.anonymised.io/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:00.199Z", + "timestamp": "2026-05-27T12:18:13.226Z", "disclosures": [ { "identifier": "oidc.user*", diff --git a/metadata/modules/anzuDSPBidAdapter.json b/metadata/modules/anzuDSPBidAdapter.json new file mode 100644 index 00000000000..ced13a64540 --- /dev/null +++ b/metadata/modules/anzuDSPBidAdapter.json @@ -0,0 +1,13 @@ +{ + "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", + "disclosures": {}, + "components": [ + { + "componentType": "bidder", + "componentName": "anzuDSP", + "aliasOf": null, + "gvlid": null, + "disclosureURL": null + } + ] +} \ No newline at end of file diff --git a/metadata/modules/apesterBidAdapter.json b/metadata/modules/apesterBidAdapter.json index 4b12ac58590..2cb3747c47e 100644 --- a/metadata/modules/apesterBidAdapter.json +++ b/metadata/modules/apesterBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apester.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:00.498Z", + "timestamp": "2026-05-27T12:18:13.652Z", "disclosures": [] } }, diff --git a/metadata/modules/appStockSSPBidAdapter.json b/metadata/modules/appStockSSPBidAdapter.json index 2fa9fa1ef64..95401963f4b 100644 --- a/metadata/modules/appStockSSPBidAdapter.json +++ b/metadata/modules/appStockSSPBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://app-stock.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:00.719Z", + "timestamp": "2026-05-27T12:18:13.743Z", "disclosures": [] } }, diff --git a/metadata/modules/appierBidAdapter.json b/metadata/modules/appierBidAdapter.json index d9aed7f261d..b27b418ac70 100644 --- a/metadata/modules/appierBidAdapter.json +++ b/metadata/modules/appierBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.appier.com/deviceStorage2025.json": { - "timestamp": "2026-05-18T20:04:00.786Z", + "timestamp": "2026-05-27T12:18:13.907Z", "disclosures": [ { "identifier": "_atrk_ssid", diff --git a/metadata/modules/appnexusBidAdapter.json b/metadata/modules/appnexusBidAdapter.json index d15c29ad1d5..4b977e723a9 100644 --- a/metadata/modules/appnexusBidAdapter.json +++ b/metadata/modules/appnexusBidAdapter.json @@ -2,11 +2,11 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:04:01.836Z", + "timestamp": "2026-05-27T12:18:14.276Z", "disclosures": [] }, "https://beintoo-support.b-cdn.net/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:00.984Z", + "timestamp": "2026-05-27T12:18:14.056Z", "disclosures": [] }, "https://projectagora.net/1032_deviceStorageDisclosure.json": { @@ -14,7 +14,7 @@ "disclosures": [] }, "https://adzymic.com/tcf.json": { - "timestamp": "2026-05-18T20:04:01.836Z", + "timestamp": "2026-05-27T12:18:14.276Z", "disclosures": [] } }, diff --git a/metadata/modules/appushBidAdapter.json b/metadata/modules/appushBidAdapter.json index 245d3a7f4dd..306dea4f699 100644 --- a/metadata/modules/appushBidAdapter.json +++ b/metadata/modules/appushBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.thebiding.com/disclosures.json": { - "timestamp": "2026-05-18T20:04:02.139Z", + "timestamp": "2026-05-27T12:18:14.359Z", "disclosures": [] } }, diff --git a/metadata/modules/apsBidAdapter.json b/metadata/modules/apsBidAdapter.json index 1ce0c6b68c7..d8be8eca34f 100644 --- a/metadata/modules/apsBidAdapter.json +++ b/metadata/modules/apsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://m.media-amazon.com/images/G/01/adprefs/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:02.484Z", + "timestamp": "2026-05-27T12:18:14.500Z", "disclosures": [ { "identifier": "vendor-id", diff --git a/metadata/modules/apstreamBidAdapter.json b/metadata/modules/apstreamBidAdapter.json index 7696dcfe1d5..5a48736f3af 100644 --- a/metadata/modules/apstreamBidAdapter.json +++ b/metadata/modules/apstreamBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sak.userreport.com/tcf.json": { - "timestamp": "2026-05-18T20:04:02.523Z", + "timestamp": "2026-05-27T12:18:14.598Z", "disclosures": [ { "identifier": "apr_dsu", diff --git a/metadata/modules/audiencerunBidAdapter.json b/metadata/modules/audiencerunBidAdapter.json index ea80f8c30c8..4747a0fda9f 100644 --- a/metadata/modules/audiencerunBidAdapter.json +++ b/metadata/modules/audiencerunBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.audiencerun.com/tcf.json": { - "timestamp": "2026-05-18T20:04:02.668Z", + "timestamp": "2026-05-27T12:18:14.849Z", "disclosures": [] } }, diff --git a/metadata/modules/axisBidAdapter.json b/metadata/modules/axisBidAdapter.json index f3bd51bfdd5..7157daf1365 100644 --- a/metadata/modules/axisBidAdapter.json +++ b/metadata/modules/axisBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://axis-marketplace.com/tcf.json": { - "timestamp": "2026-05-18T20:04:02.809Z", + "timestamp": "2026-05-27T12:18:15.005Z", "disclosures": [] } }, diff --git a/metadata/modules/azerionedgeRtdProvider.json b/metadata/modules/azerionedgeRtdProvider.json index 55cb4200de2..b1712b7b2d9 100644 --- a/metadata/modules/azerionedgeRtdProvider.json +++ b/metadata/modules/azerionedgeRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sellers.improvedigital.com/tcf-cookies.json": { - "timestamp": "2026-05-18T20:04:02.997Z", + "timestamp": "2026-05-27T12:18:15.053Z", "disclosures": [ { "identifier": "tuuid", diff --git a/metadata/modules/beachfrontBidAdapter.json b/metadata/modules/beachfrontBidAdapter.json index 4b0f7a6dbd5..45feaffc826 100644 --- a/metadata/modules/beachfrontBidAdapter.json +++ b/metadata/modules/beachfrontBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.seedtag.com/vendor.json": { - "timestamp": "2026-05-18T20:04:03.444Z", + "timestamp": "2026-05-27T12:18:15.361Z", "disclosures": [] } }, diff --git a/metadata/modules/beopBidAdapter.json b/metadata/modules/beopBidAdapter.json index 068e7913b11..6e2e5f7f358 100644 --- a/metadata/modules/beopBidAdapter.json +++ b/metadata/modules/beopBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://beop.collectiveaudience.co/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:03.642Z", + "timestamp": "2026-05-27T12:18:15.505Z", "disclosures": [] } }, diff --git a/metadata/modules/betweenBidAdapter.json b/metadata/modules/betweenBidAdapter.json index b1586eecebb..1e1b0e8e60b 100644 --- a/metadata/modules/betweenBidAdapter.json +++ b/metadata/modules/betweenBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://en.betweenx.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:03.770Z", + "timestamp": "2026-05-27T12:18:15.677Z", "disclosures": [] } }, diff --git a/metadata/modules/bidfuseBidAdapter.json b/metadata/modules/bidfuseBidAdapter.json index 03636b75cc7..4b928a42a77 100644 --- a/metadata/modules/bidfuseBidAdapter.json +++ b/metadata/modules/bidfuseBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bidfuse.com/disclosure.json": { - "timestamp": "2026-05-18T20:04:03.963Z", + "timestamp": "2026-05-27T12:18:15.822Z", "disclosures": [] } }, diff --git a/metadata/modules/bidmaticBidAdapter.json b/metadata/modules/bidmaticBidAdapter.json index 85fccb51b54..c8ec29ed705 100644 --- a/metadata/modules/bidmaticBidAdapter.json +++ b/metadata/modules/bidmaticBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bidmatic.io/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:04.229Z", + "timestamp": "2026-05-27T12:18:18.434Z", "disclosures": [] } }, diff --git a/metadata/modules/bidtheatreBidAdapter.json b/metadata/modules/bidtheatreBidAdapter.json index 10904507075..5d4a1191b43 100644 --- a/metadata/modules/bidtheatreBidAdapter.json +++ b/metadata/modules/bidtheatreBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.bidtheatre.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:04.364Z", + "timestamp": "2026-05-27T12:18:18.488Z", "disclosures": [] } }, diff --git a/metadata/modules/bliinkBidAdapter.json b/metadata/modules/bliinkBidAdapter.json index 541ca19d04e..d3ba2675bcf 100644 --- a/metadata/modules/bliinkBidAdapter.json +++ b/metadata/modules/bliinkBidAdapter.json @@ -1,18 +1,13 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", - "disclosures": { - "https://bliink.io/disclosures.json": { - "timestamp": "2026-05-18T20:04:04.717Z", - "disclosures": [] - } - }, + "disclosures": {}, "components": [ { "componentType": "bidder", "componentName": "bliink", "aliasOf": null, - "gvlid": 658, - "disclosureURL": "https://bliink.io/disclosures.json" + "gvlid": null, + "disclosureURL": null }, { "componentType": "bidder", diff --git a/metadata/modules/blockthroughBidAdapter.json b/metadata/modules/blockthroughBidAdapter.json index e509dc0ae2e..de062103b1b 100644 --- a/metadata/modules/blockthroughBidAdapter.json +++ b/metadata/modules/blockthroughBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://blockthrough.com/tcf_disclosures.json": { - "timestamp": "2026-05-18T20:04:05.297Z", + "timestamp": "2026-05-27T12:18:18.781Z", "disclosures": [ { "identifier": "BT_AA_DETECTION", diff --git a/metadata/modules/blueBidAdapter.json b/metadata/modules/blueBidAdapter.json index 3132565b4ee..6858b1b75af 100644 --- a/metadata/modules/blueBidAdapter.json +++ b/metadata/modules/blueBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://getblue.io/iab/iab.json": { - "timestamp": "2026-05-18T20:04:05.544Z", + "timestamp": "2026-05-27T12:18:18.916Z", "disclosures": null } }, diff --git a/metadata/modules/bmsBidAdapter.json b/metadata/modules/bmsBidAdapter.json index 20bb166e8be..8b1ae8bbcdd 100644 --- a/metadata/modules/bmsBidAdapter.json +++ b/metadata/modules/bmsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bluems.com/iab.json": { - "timestamp": "2026-05-18T20:04:06.180Z", + "timestamp": "2026-05-27T12:18:19.441Z", "disclosures": [] } }, diff --git a/metadata/modules/boldwinBidAdapter.json b/metadata/modules/boldwinBidAdapter.json index bafc644c92e..5596dd44500 100644 --- a/metadata/modules/boldwinBidAdapter.json +++ b/metadata/modules/boldwinBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://magav.videowalldirect.com/iab/videowalldirectiab.json": { - "timestamp": "2026-05-18T20:04:06.259Z", + "timestamp": "2026-05-27T12:18:19.541Z", "disclosures": [] } }, diff --git a/metadata/modules/bridBidAdapter.json b/metadata/modules/bridBidAdapter.json index 8e724452852..8d742f5c84f 100644 --- a/metadata/modules/bridBidAdapter.json +++ b/metadata/modules/bridBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://target-video.com/vendors-device-storage-and-operational-disclosures.json": { - "timestamp": "2026-05-18T20:04:06.490Z", + "timestamp": "2026-05-27T12:18:19.811Z", "disclosures": [ { "identifier": "brid_location", diff --git a/metadata/modules/browsiBidAdapter.json b/metadata/modules/browsiBidAdapter.json index 0b1f316a8ca..11d4b18d696 100644 --- a/metadata/modules/browsiBidAdapter.json +++ b/metadata/modules/browsiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.browsiprod.com/ads/tcf.json": { - "timestamp": "2026-05-18T20:04:06.691Z", + "timestamp": "2026-05-27T12:18:20.102Z", "disclosures": [] } }, diff --git a/metadata/modules/bucksenseBidAdapter.json b/metadata/modules/bucksenseBidAdapter.json index bceda5f4312..e7415ea979f 100644 --- a/metadata/modules/bucksenseBidAdapter.json +++ b/metadata/modules/bucksenseBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://j.bksnimages.com/iab/devsto03.json": { - "timestamp": "2026-05-18T20:04:06.800Z", + "timestamp": "2026-05-27T12:18:20.193Z", "disclosures": [] } }, diff --git a/metadata/modules/carodaBidAdapter.json b/metadata/modules/carodaBidAdapter.json index bee1d5ee44a..e27a5838f49 100644 --- a/metadata/modules/carodaBidAdapter.json +++ b/metadata/modules/carodaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn2.caroda.io/tcfvds/2022-05-17/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:07.243Z", + "timestamp": "2026-05-27T12:18:20.333Z", "disclosures": [] } }, diff --git a/metadata/modules/ceeIdSystem.json b/metadata/modules/ceeIdSystem.json index fa3826c295d..276bd531b51 100644 --- a/metadata/modules/ceeIdSystem.json +++ b/metadata/modules/ceeIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.wp.pl/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:07.332Z", + "timestamp": "2026-05-27T12:18:20.597Z", "disclosures": [] } }, diff --git a/metadata/modules/chromeAiRtdProvider.json b/metadata/modules/chromeAiRtdProvider.json index 85c7ec5f322..a41a0d34245 100644 --- a/metadata/modules/chromeAiRtdProvider.json +++ b/metadata/modules/chromeAiRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/chromeAiRtdProvider.json": { - "timestamp": "2026-05-18T20:04:18.714Z", + "timestamp": "2026-05-27T12:18:21.010Z", "disclosures": [ { "identifier": "chromeAi_detected_data", diff --git a/metadata/modules/clickioBidAdapter.json b/metadata/modules/clickioBidAdapter.json index 3f369eb9931..a0bf1e464ea 100644 --- a/metadata/modules/clickioBidAdapter.json +++ b/metadata/modules/clickioBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://o.clickiocdn.com/tcf_storage_info.json": { - "timestamp": "2026-05-18T20:04:18.715Z", + "timestamp": "2026-05-27T12:18:21.011Z", "disclosures": [] } }, diff --git a/metadata/modules/compassBidAdapter.json b/metadata/modules/compassBidAdapter.json index c6cdc6f5f98..946c51b5da6 100644 --- a/metadata/modules/compassBidAdapter.json +++ b/metadata/modules/compassBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.marphezis.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-18T20:04:19.308Z", + "timestamp": "2026-05-27T12:18:21.470Z", "disclosures": [] } }, diff --git a/metadata/modules/conceptxBidAdapter.json b/metadata/modules/conceptxBidAdapter.json index 26be1cc67e4..2225c11962f 100644 --- a/metadata/modules/conceptxBidAdapter.json +++ b/metadata/modules/conceptxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cncptx.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:19.485Z", + "timestamp": "2026-05-27T12:18:21.652Z", "disclosures": [] } }, diff --git a/metadata/modules/connatixBidAdapter.json b/metadata/modules/connatixBidAdapter.json index b9a52cee8a6..5ec05310213 100644 --- a/metadata/modules/connatixBidAdapter.json +++ b/metadata/modules/connatixBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://connatix.com/iab-tcf-disclosure.json": { - "timestamp": "2026-05-18T20:04:19.874Z", + "timestamp": "2026-05-27T12:18:21.763Z", "disclosures": [ { "identifier": "cnx_userId", diff --git a/metadata/modules/connectIdSystem.json b/metadata/modules/connectIdSystem.json index abcb478ae44..e87695a02fc 100644 --- a/metadata/modules/connectIdSystem.json +++ b/metadata/modules/connectIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://meta.legal.yahoo.com/iab-tcf/v2/device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:04:20.052Z", + "timestamp": "2026-05-27T12:18:21.855Z", "disclosures": [ { "identifier": "vmcid", diff --git a/metadata/modules/connectadBidAdapter.json b/metadata/modules/connectadBidAdapter.json index d5763018b6f..eaee4cb09f1 100644 --- a/metadata/modules/connectadBidAdapter.json +++ b/metadata/modules/connectadBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.connectad.io/tcf_storage_info.json": { - "timestamp": "2026-05-18T20:04:20.166Z", + "timestamp": "2026-05-27T12:18:21.913Z", "disclosures": [] } }, diff --git a/metadata/modules/contentexchangeBidAdapter.json b/metadata/modules/contentexchangeBidAdapter.json index aacda4e528c..b047d283459 100644 --- a/metadata/modules/contentexchangeBidAdapter.json +++ b/metadata/modules/contentexchangeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://hb.contentexchange.me/template/device_storage.json": { - "timestamp": "2026-05-18T20:04:20.325Z", + "timestamp": "2026-05-27T12:18:22.362Z", "disclosures": [] } }, diff --git a/metadata/modules/conversantBidAdapter.json b/metadata/modules/conversantBidAdapter.json index 5ef2e11a249..5da24c2e6fa 100644 --- a/metadata/modules/conversantBidAdapter.json +++ b/metadata/modules/conversantBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s-usweb.dotomi.com/assets/js/taggy-js/2.18.13/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:20.888Z", + "timestamp": "2026-05-27T12:18:22.839Z", "disclosures": [ { "identifier": "dtm_status", diff --git a/metadata/modules/copper6sspBidAdapter.json b/metadata/modules/copper6sspBidAdapter.json index ed17747c623..48e18c8a286 100644 --- a/metadata/modules/copper6sspBidAdapter.json +++ b/metadata/modules/copper6sspBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.copper6.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:21.007Z", + "timestamp": "2026-05-27T12:18:22.861Z", "disclosures": [] } }, diff --git a/metadata/modules/cpmstarBidAdapter.json b/metadata/modules/cpmstarBidAdapter.json index 65218eece49..cdaacbf3a8a 100644 --- a/metadata/modules/cpmstarBidAdapter.json +++ b/metadata/modules/cpmstarBidAdapter.json @@ -1,8 +1,8 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { - "https://www.aditude.com/storageaccess.json": { - "timestamp": "2026-05-18T20:04:21.219Z", + "https://cdn-prod.aditude.com/storageaccess.json": { + "timestamp": "2026-05-27T12:18:22.921Z", "disclosures": [] } }, @@ -12,7 +12,7 @@ "componentName": "cpmstar", "aliasOf": null, "gvlid": 1317, - "disclosureURL": "https://www.aditude.com/storageaccess.json" + "disclosureURL": "https://cdn-prod.aditude.com/storageaccess.json" } ] } \ No newline at end of file diff --git a/metadata/modules/criteoBidAdapter.json b/metadata/modules/criteoBidAdapter.json index dc4e15ef48b..c414020d5f1 100644 --- a/metadata/modules/criteoBidAdapter.json +++ b/metadata/modules/criteoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.criteo.com/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-18T20:04:21.721Z", + "timestamp": "2026-05-27T12:18:23.048Z", "disclosures": [ { "identifier": "criteo_fast_bid", diff --git a/metadata/modules/criteoIdSystem.json b/metadata/modules/criteoIdSystem.json index 0b467e32ce3..3c733079a8e 100644 --- a/metadata/modules/criteoIdSystem.json +++ b/metadata/modules/criteoIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.criteo.com/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-18T20:04:21.902Z", + "timestamp": "2026-05-27T12:18:23.185Z", "disclosures": [ { "identifier": "criteo_fast_bid", diff --git a/metadata/modules/cwireBidAdapter.json b/metadata/modules/cwireBidAdapter.json index a7ba9667a8f..2cb1fb90385 100644 --- a/metadata/modules/cwireBidAdapter.json +++ b/metadata/modules/cwireBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.cwi.re/artifacts/iab/iab.json": { - "timestamp": "2026-05-18T20:04:21.902Z", + "timestamp": "2026-05-27T12:18:23.185Z", "disclosures": [] } }, diff --git a/metadata/modules/czechAdIdSystem.json b/metadata/modules/czechAdIdSystem.json index cb3a13e6987..ac0716f18a0 100644 --- a/metadata/modules/czechAdIdSystem.json +++ b/metadata/modules/czechAdIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cpex.cz/storagedisclosure.json": { - "timestamp": "2026-05-18T20:04:22.721Z", + "timestamp": "2026-05-27T12:18:23.280Z", "disclosures": [] } }, diff --git a/metadata/modules/dailymotionBidAdapter.json b/metadata/modules/dailymotionBidAdapter.json index 19ad6ba1e83..d46d095b6b3 100644 --- a/metadata/modules/dailymotionBidAdapter.json +++ b/metadata/modules/dailymotionBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://statics.dmcdn.net/a/vds.json": { - "timestamp": "2026-05-18T20:04:23.352Z", + "timestamp": "2026-05-27T12:18:24.044Z", "disclosures": [ { "identifier": "uid_dm", diff --git a/metadata/modules/debugging.json b/metadata/modules/debugging.json index 3e0eaeb54ac..a7a04bee20e 100644 --- a/metadata/modules/debugging.json +++ b/metadata/modules/debugging.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/debugging.json": { - "timestamp": "2026-05-18T20:03:46.494Z", + "timestamp": "2026-05-27T12:17:29.211Z", "disclosures": [ { "identifier": "__*_debugging__", diff --git a/metadata/modules/deepintentBidAdapter.json b/metadata/modules/deepintentBidAdapter.json index f8cf0359520..bfff44bdee4 100644 --- a/metadata/modules/deepintentBidAdapter.json +++ b/metadata/modules/deepintentBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://option.deepintent.com/iabeurope_vendor_disclosures.json": { - "timestamp": "2026-05-18T20:04:23.885Z", + "timestamp": "2026-05-27T12:18:24.506Z", "disclosures": [] } }, diff --git a/metadata/modules/defineMediaBidAdapter.json b/metadata/modules/defineMediaBidAdapter.json index 933eb8056b6..db9bc19c440 100644 --- a/metadata/modules/defineMediaBidAdapter.json +++ b/metadata/modules/defineMediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://definemedia.de/tcf/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-18T20:04:24.011Z", + "timestamp": "2026-05-27T12:18:24.554Z", "disclosures": [ { "identifier": "conative$dataGathering$Adex", diff --git a/metadata/modules/deltaprojectsBidAdapter.json b/metadata/modules/deltaprojectsBidAdapter.json index 60ec9c67d55..8aa75dbdef1 100644 --- a/metadata/modules/deltaprojectsBidAdapter.json +++ b/metadata/modules/deltaprojectsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.de17a.com/policy/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:24.477Z", + "timestamp": "2026-05-27T12:18:24.971Z", "disclosures": [] } }, diff --git a/metadata/modules/dianomiBidAdapter.json b/metadata/modules/dianomiBidAdapter.json index 20fe09740f7..c5dce0f7757 100644 --- a/metadata/modules/dianomiBidAdapter.json +++ b/metadata/modules/dianomiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.dianomi.com/device_storage.json": { - "timestamp": "2026-05-18T20:04:25.045Z", + "timestamp": "2026-05-27T12:18:25.476Z", "disclosures": [] } }, diff --git a/metadata/modules/digitalMatterBidAdapter.json b/metadata/modules/digitalMatterBidAdapter.json index 612f34430a4..6d43ca146d8 100644 --- a/metadata/modules/digitalMatterBidAdapter.json +++ b/metadata/modules/digitalMatterBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://digitalmatter.ai/disclosures.json": { - "timestamp": "2026-05-18T20:04:25.045Z", + "timestamp": "2026-05-27T12:18:25.477Z", "disclosures": [] } }, diff --git a/metadata/modules/distroscaleBidAdapter.json b/metadata/modules/distroscaleBidAdapter.json index 6d52ff89370..427c2c24fc6 100644 --- a/metadata/modules/distroscaleBidAdapter.json +++ b/metadata/modules/distroscaleBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://a.jsrdn.com/tcf/tcf-vendor-disclosure.json": { - "timestamp": "2026-05-18T20:04:25.447Z", + "timestamp": "2026-05-27T12:18:25.820Z", "disclosures": [] } }, diff --git a/metadata/modules/docereeAdManagerBidAdapter.json b/metadata/modules/docereeAdManagerBidAdapter.json index 81982a06e91..f0fc306fa03 100644 --- a/metadata/modules/docereeAdManagerBidAdapter.json +++ b/metadata/modules/docereeAdManagerBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://doceree.com/.well-known/iab/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:25.789Z", + "timestamp": "2026-05-27T12:18:25.974Z", "disclosures": [] } }, diff --git a/metadata/modules/docereeBidAdapter.json b/metadata/modules/docereeBidAdapter.json index 625e1748e08..842940a37c0 100644 --- a/metadata/modules/docereeBidAdapter.json +++ b/metadata/modules/docereeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://doceree.com/.well-known/iab/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:26.838Z", + "timestamp": "2026-05-27T12:18:26.868Z", "disclosures": [] } }, diff --git a/metadata/modules/dspxBidAdapter.json b/metadata/modules/dspxBidAdapter.json index 3a3e90c743c..6d67ae7a115 100644 --- a/metadata/modules/dspxBidAdapter.json +++ b/metadata/modules/dspxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.adtech.app/gen/deviceStorageDisclosure/os.json": { - "timestamp": "2026-05-18T20:04:26.839Z", + "timestamp": "2026-05-27T12:18:26.869Z", "disclosures": [] } }, diff --git a/metadata/modules/edge226BidAdapter.json b/metadata/modules/edge226BidAdapter.json index 78fc5848843..acd0054835a 100644 --- a/metadata/modules/edge226BidAdapter.json +++ b/metadata/modules/edge226BidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.serveteck.com/cdn_storage/tcf/tcf.json?a=1.io": { - "timestamp": "2026-05-18T20:04:28.353Z", + "timestamp": "2026-05-27T12:18:55.613Z", "disclosures": null } }, diff --git a/metadata/modules/empowerBidAdapter.json b/metadata/modules/empowerBidAdapter.json index 129254283c6..a59256a700b 100644 --- a/metadata/modules/empowerBidAdapter.json +++ b/metadata/modules/empowerBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.empower.net/vendor/vendor.json": { - "timestamp": "2026-05-18T20:04:28.700Z", + "timestamp": "2026-05-27T12:18:55.705Z", "disclosures": [] } }, diff --git a/metadata/modules/equativBidAdapter.json b/metadata/modules/equativBidAdapter.json index 77a3eaf4bb4..d110753884d 100644 --- a/metadata/modules/equativBidAdapter.json +++ b/metadata/modules/equativBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apps.smartadserver.com/device-storage-disclosures/equativDeviceStorageDisclosures.json": { - "timestamp": "2026-05-18T20:04:29.178Z", + "timestamp": "2026-05-27T12:18:55.818Z", "disclosures": [] } }, diff --git a/metadata/modules/eskimiBidAdapter.json b/metadata/modules/eskimiBidAdapter.json index fa0e6cad186..791f3cd6416 100644 --- a/metadata/modules/eskimiBidAdapter.json +++ b/metadata/modules/eskimiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://dsp-media.eskimi.com/deviceStorage.json": { - "timestamp": "2026-05-14T13:11:44.148Z", + "timestamp": "2026-05-27T12:18:56.518Z", "disclosures": [] } }, diff --git a/metadata/modules/etargetBidAdapter.json b/metadata/modules/etargetBidAdapter.json index 399a0fbc091..af93ce8844e 100644 --- a/metadata/modules/etargetBidAdapter.json +++ b/metadata/modules/etargetBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.etarget.sk/cookies3.json": { - "timestamp": "2026-05-18T20:04:33.352Z", + "timestamp": "2026-05-27T12:18:56.603Z", "disclosures": [] } }, diff --git a/metadata/modules/euidIdSystem.json b/metadata/modules/euidIdSystem.json index 488b81edbab..cd4026f8a26 100644 --- a/metadata/modules/euidIdSystem.json +++ b/metadata/modules/euidIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-18T20:04:34.202Z", + "timestamp": "2026-05-27T12:18:57.385Z", "disclosures": [] } }, diff --git a/metadata/modules/exadsBidAdapter.json b/metadata/modules/exadsBidAdapter.json index 78000e70c5a..b43d90c8e38 100644 --- a/metadata/modules/exadsBidAdapter.json +++ b/metadata/modules/exadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://a.native7.com/tcf/deviceStorage.php": { - "timestamp": "2026-05-18T20:04:34.485Z", + "timestamp": "2026-05-27T12:18:57.771Z", "disclosures": [ { "identifier": "pn-zone-*", @@ -10,20 +10,16 @@ "maxAgeSeconds": 3888000, "cookieRefresh": false, "purposes": [ - 1, - 2, - 4 + 1 ] }, { "identifier": "zone-cap-*", "type": "cookie", - "maxAgeSeconds": 21600, + "maxAgeSeconds": 86400, "cookieRefresh": true, "purposes": [ - 1, - 2, - 4 + 1 ] }, { @@ -32,9 +28,7 @@ "maxAgeSeconds": 86400, "cookieRefresh": false, "purposes": [ - 1, - 2, - 4 + 1 ] } ] diff --git a/metadata/modules/feedadBidAdapter.json b/metadata/modules/feedadBidAdapter.json index 6c6e2f7d6f1..9bdbbaec0dc 100644 --- a/metadata/modules/feedadBidAdapter.json +++ b/metadata/modules/feedadBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.feedad.com/tcf-device-disclosures.json": { - "timestamp": "2026-05-18T20:04:34.677Z", + "timestamp": "2026-05-27T12:18:58.105Z", "disclosures": [ { "identifier": "__fad_data", diff --git a/metadata/modules/fwsspBidAdapter.json b/metadata/modules/fwsspBidAdapter.json index 3b11c0fafce..b6226248f4d 100644 --- a/metadata/modules/fwsspBidAdapter.json +++ b/metadata/modules/fwsspBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab.fwmrm.net/g/devicedisclosure.json": { - "timestamp": "2026-05-18T20:04:34.919Z", + "timestamp": "2026-05-27T12:18:58.333Z", "disclosures": [] } }, diff --git a/metadata/modules/gamoshiBidAdapter.json b/metadata/modules/gamoshiBidAdapter.json index fa60af4c756..11d6dee0700 100644 --- a/metadata/modules/gamoshiBidAdapter.json +++ b/metadata/modules/gamoshiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resources.gamoshi.io/disclosures-client-storage.json": { - "timestamp": "2026-05-18T20:04:35.086Z", + "timestamp": "2026-05-27T12:18:58.450Z", "disclosures": [] } }, diff --git a/metadata/modules/gemiusIdSystem.json b/metadata/modules/gemiusIdSystem.json index cde7d0567dc..2a0a0e30e97 100644 --- a/metadata/modules/gemiusIdSystem.json +++ b/metadata/modules/gemiusIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gemius.com/media/documents/Gemius_SA_Vendor_Device_Storage.json": { - "timestamp": "2026-05-18T20:04:35.172Z", + "timestamp": "2026-05-27T12:18:58.748Z", "disclosures": [ { "identifier": "__gsyncs_gdpr", diff --git a/metadata/modules/glomexBidAdapter.json b/metadata/modules/glomexBidAdapter.json index 53cb5476e9d..7bb9b3d2e8c 100644 --- a/metadata/modules/glomexBidAdapter.json +++ b/metadata/modules/glomexBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://player.glomex.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:35.173Z", + "timestamp": "2026-05-27T12:18:58.749Z", "disclosures": [ { "identifier": "glomexUser", @@ -20,6 +20,15 @@ 10 ] }, + { + "identifier": "turboPlayerProfile", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, { "identifier": "ET_EventCollector_SessionInstallationId", "type": "web", diff --git a/metadata/modules/goldbachBidAdapter.json b/metadata/modules/goldbachBidAdapter.json index b9bf12de31a..56e056ea6e1 100644 --- a/metadata/modules/goldbachBidAdapter.json +++ b/metadata/modules/goldbachBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gb-next.ch/TcfGoldbachDeviceStorage.json": { - "timestamp": "2026-05-18T20:04:35.530Z", + "timestamp": "2026-05-27T12:18:58.908Z", "disclosures": [ { "identifier": "dakt_2_session_id", @@ -15,59 +15,157 @@ 3, 4, 7, - 8, 9, 10 + ], + "specialPurposes": [ + 1, + 2 ] }, { "identifier": "dakt_2_uuid_ts", "type": "cookie", - "maxAgeSeconds": 94670856, - "cookieRefresh": false, + "maxAgeSeconds": 15552000, + "cookieRefresh": true, "purposes": [ 1, 2, 3, 4, 7, - 8, 9, 10 + ], + "specialPurposes": [ + 1, + 2 ] }, { "identifier": "dakt_2_version", "type": "cookie", - "maxAgeSeconds": 94670856, - "cookieRefresh": false, + "maxAgeSeconds": 15552000, + "cookieRefresh": true, "purposes": [ 1 + ], + "specialPurposes": [ + 1 ] }, { "identifier": "dakt_2_uuid", "type": "cookie", - "maxAgeSeconds": 94670856, - "cookieRefresh": false, + "maxAgeSeconds": 15552000, + "cookieRefresh": true, "purposes": [ 1, 2, 3, 4, 7, - 8, 9, 10 + ], + "specialPurposes": [ + 1, + 2 ] }, { "identifier": "dakt_2_dnt", "type": "cookie", - "maxAgeSeconds": 31556952, + "maxAgeSeconds": 15552000, + "cookieRefresh": false, + "purposes": [], + "specialPurposes": [ + 1 + ], + "optOut": true + }, + { + "identifier": "DqSync", + "type": "cookie", + "maxAgeSeconds": 1800, "cookieRefresh": false, "purposes": [ 1 + ], + "specialPurposes": [ + 2 + ] + }, + { + "identifier": "dqTag:1pId", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2 + ] + }, + { + "identifier": "dqTag:3pId", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2 + ] + }, + { + "identifier": "dqTag:dqId", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2 + ] + }, + { + "identifier": "goldbach_uid", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2 ] } ] diff --git a/metadata/modules/gridBidAdapter.json b/metadata/modules/gridBidAdapter.json index 9cb0d2a521e..bc09accd001 100644 --- a/metadata/modules/gridBidAdapter.json +++ b/metadata/modules/gridBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.themediagrid.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:36.059Z", + "timestamp": "2026-05-27T12:18:59.055Z", "disclosures": [] } }, diff --git a/metadata/modules/gumgumBidAdapter.json b/metadata/modules/gumgumBidAdapter.json index 3ccd10cc84e..d540b6b8a84 100644 --- a/metadata/modules/gumgumBidAdapter.json +++ b/metadata/modules/gumgumBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://marketing.gumgum.com/devicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:04:36.214Z", + "timestamp": "2026-05-27T12:18:59.240Z", "disclosures": [] } }, diff --git a/metadata/modules/hadronIdSystem.json b/metadata/modules/hadronIdSystem.json index b488f0bac8d..bb728b90fef 100644 --- a/metadata/modules/hadronIdSystem.json +++ b/metadata/modules/hadronIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://p.ad.gt/static/iab_tcf.json": { - "timestamp": "2026-05-18T20:04:36.343Z", + "timestamp": "2026-05-27T12:18:59.408Z", "disclosures": [ { "identifier": "au/sid", diff --git a/metadata/modules/hadronRtdProvider.json b/metadata/modules/hadronRtdProvider.json index 7e393823d70..bb6919e6642 100644 --- a/metadata/modules/hadronRtdProvider.json +++ b/metadata/modules/hadronRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://p.ad.gt/static/iab_tcf.json": { - "timestamp": "2026-05-18T20:04:36.468Z", + "timestamp": "2026-05-27T12:18:59.573Z", "disclosures": [ { "identifier": "au/sid", diff --git a/metadata/modules/harionBidAdapter.json b/metadata/modules/harionBidAdapter.json index d3a028259c0..d740806f7b7 100644 --- a/metadata/modules/harionBidAdapter.json +++ b/metadata/modules/harionBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://markappmedia.site/vendor.json": { - "timestamp": "2026-05-18T20:04:36.468Z", + "timestamp": "2026-05-27T12:18:59.574Z", "disclosures": [] } }, diff --git a/metadata/modules/holidBidAdapter.json b/metadata/modules/holidBidAdapter.json index 9740e754cc5..931908a0ef6 100644 --- a/metadata/modules/holidBidAdapter.json +++ b/metadata/modules/holidBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ads.holid.io/devicestorage.json": { - "timestamp": "2026-05-18T20:04:36.931Z", + "timestamp": "2026-05-27T12:18:59.978Z", "disclosures": [ { "identifier": "uids", diff --git a/metadata/modules/hubvisorBidAdapter.json b/metadata/modules/hubvisorBidAdapter.json new file mode 100644 index 00000000000..51e92fda7fc --- /dev/null +++ b/metadata/modules/hubvisorBidAdapter.json @@ -0,0 +1,64 @@ +{ + "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", + "disclosures": { + "https://cdn.hubvisor.io/assets/deviceStorage.json": { + "timestamp": "2026-05-27T12:19:00.225Z", + "disclosures": [ + { + "identifier": "hbv:turbo-cmp", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, + { + "identifier": "hbv:remote-configuration", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, + { + "identifier": "hbv:dynamic-timeout", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, + { + "identifier": "hbv:ttdid", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, + { + "identifier": "hbv:client-context", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + } + ] + } + }, + "components": [ + { + "componentType": "bidder", + "componentName": "hubvisor", + "aliasOf": null, + "gvlid": 1112, + "disclosureURL": "https://cdn.hubvisor.io/assets/deviceStorage.json" + } + ] +} \ No newline at end of file diff --git a/metadata/modules/hybridBidAdapter.json b/metadata/modules/hybridBidAdapter.json index a4baa4aabf5..69408c404dc 100644 --- a/metadata/modules/hybridBidAdapter.json +++ b/metadata/modules/hybridBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://st.hybrid.ai/policy/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:37.218Z", + "timestamp": "2026-05-27T12:19:00.481Z", "disclosures": [] } }, diff --git a/metadata/modules/id5IdSystem.json b/metadata/modules/id5IdSystem.json index 5ee3f6220a1..4340cad79d4 100644 --- a/metadata/modules/id5IdSystem.json +++ b/metadata/modules/id5IdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://id5-sync.com/tcf/disclosures.json": { - "timestamp": "2026-05-18T20:04:37.407Z", + "timestamp": "2026-05-27T12:19:00.650Z", "disclosures": [ { "identifier": "id5id", diff --git a/metadata/modules/identityLinkIdSystem.json b/metadata/modules/identityLinkIdSystem.json index 5ea4e071abf..8f7d38701cb 100644 --- a/metadata/modules/identityLinkIdSystem.json +++ b/metadata/modules/identityLinkIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.ats.rlcdn.com/device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:04:37.744Z", + "timestamp": "2026-05-27T12:19:00.938Z", "disclosures": [ { "identifier": "_lr_retry_request", diff --git a/metadata/modules/illuminBidAdapter.json b/metadata/modules/illuminBidAdapter.json index da0e50311e4..02015477e10 100644 --- a/metadata/modules/illuminBidAdapter.json +++ b/metadata/modules/illuminBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admanmedia.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:37.822Z", + "timestamp": "2026-05-27T12:19:01.103Z", "disclosures": [] } }, diff --git a/metadata/modules/impactifyBidAdapter.json b/metadata/modules/impactifyBidAdapter.json index bc6a46abe19..d93fb161a72 100644 --- a/metadata/modules/impactifyBidAdapter.json +++ b/metadata/modules/impactifyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.impactify.io/tcfvendors.json": { - "timestamp": "2026-05-18T20:04:38.287Z", + "timestamp": "2026-05-27T12:19:01.386Z", "disclosures": [ { "identifier": "_im*", diff --git a/metadata/modules/improvedigitalBidAdapter.json b/metadata/modules/improvedigitalBidAdapter.json index bad837b0964..ea561a2a7e1 100644 --- a/metadata/modules/improvedigitalBidAdapter.json +++ b/metadata/modules/improvedigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sellers.improvedigital.com/tcf-cookies.json": { - "timestamp": "2026-05-18T20:04:38.613Z", + "timestamp": "2026-05-27T12:19:01.750Z", "disclosures": [ { "identifier": "tuuid", diff --git a/metadata/modules/inmobiBidAdapter.json b/metadata/modules/inmobiBidAdapter.json index 54b44739a3e..aa174888fbb 100644 --- a/metadata/modules/inmobiBidAdapter.json +++ b/metadata/modules/inmobiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://publisher.inmobi.com/public/disclosure.json": { - "timestamp": "2026-05-18T20:04:38.613Z", + "timestamp": "2026-05-27T12:19:01.751Z", "disclosures": [ { "identifier": "iDSP_Cookie", diff --git a/metadata/modules/insticatorBidAdapter.json b/metadata/modules/insticatorBidAdapter.json index 0c1af21681a..122957d7c48 100644 --- a/metadata/modules/insticatorBidAdapter.json +++ b/metadata/modules/insticatorBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.insticator.com/iab/device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:04:38.735Z", + "timestamp": "2026-05-27T12:19:01.829Z", "disclosures": [ { "identifier": "visitorGeo", diff --git a/metadata/modules/insuradsBidAdapter.json b/metadata/modules/insuradsBidAdapter.json index 597fa99b02a..2c3d6494fbf 100644 --- a/metadata/modules/insuradsBidAdapter.json +++ b/metadata/modules/insuradsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.insurads.com/tcf-vdsod.json": { - "timestamp": "2026-05-18T20:04:39.072Z", + "timestamp": "2026-05-27T12:19:02.177Z", "disclosures": [ { "identifier": "___iat_ses", diff --git a/metadata/modules/insuradsRtdProvider.json b/metadata/modules/insuradsRtdProvider.json index 45689e16f30..6e068abc8b8 100644 --- a/metadata/modules/insuradsRtdProvider.json +++ b/metadata/modules/insuradsRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.insurads.com/tcf-vdsod.json": { - "timestamp": "2026-05-18T20:04:39.546Z", + "timestamp": "2026-05-27T12:19:02.544Z", "disclosures": [ { "identifier": "___iat_ses", diff --git a/metadata/modules/intentIqIdSystem.json b/metadata/modules/intentIqIdSystem.json index 9b9a1b9f0c5..70146b9e020 100644 --- a/metadata/modules/intentIqIdSystem.json +++ b/metadata/modules/intentIqIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://agent.intentiq.com/GDPR/gdpr.json": { - "timestamp": "2026-05-18T20:04:39.547Z", + "timestamp": "2026-05-27T12:19:02.545Z", "disclosures": [] } }, diff --git a/metadata/modules/invibesBidAdapter.json b/metadata/modules/invibesBidAdapter.json index 0f26dd63c52..fa86eaef642 100644 --- a/metadata/modules/invibesBidAdapter.json +++ b/metadata/modules/invibesBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.invibes.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:39.747Z", + "timestamp": "2026-05-27T12:19:02.759Z", "disclosures": [ { "identifier": "ivvcap", diff --git a/metadata/modules/ipromBidAdapter.json b/metadata/modules/ipromBidAdapter.json index cabb5cc61e5..48393aed581 100644 --- a/metadata/modules/ipromBidAdapter.json +++ b/metadata/modules/ipromBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://core.iprom.net/info/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:40.233Z", + "timestamp": "2026-05-27T12:19:03.140Z", "disclosures": [] } }, diff --git a/metadata/modules/ixBidAdapter.json b/metadata/modules/ixBidAdapter.json index 10795079248..d79d46ae676 100644 --- a/metadata/modules/ixBidAdapter.json +++ b/metadata/modules/ixBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.indexexchange.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:40.791Z", + "timestamp": "2026-05-27T12:19:03.577Z", "disclosures": [ { "identifier": "ix_features", diff --git a/metadata/modules/jixieBidAdapter.json b/metadata/modules/jixieBidAdapter.json index a9aa5292e0f..3febcd85122 100644 --- a/metadata/modules/jixieBidAdapter.json +++ b/metadata/modules/jixieBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/jixieBidAdapterDisclosure.json": { - "timestamp": "2026-05-18T20:04:41.188Z", + "timestamp": "2026-05-27T12:19:03.884Z", "disclosures": [ { "identifier": "_jxx", diff --git a/metadata/modules/jixieIdSystem.json b/metadata/modules/jixieIdSystem.json index 048063ca475..6cba32ef9ac 100644 --- a/metadata/modules/jixieIdSystem.json +++ b/metadata/modules/jixieIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/jixieIdSystemDisclosure.json": { - "timestamp": "2026-05-18T20:04:41.188Z", + "timestamp": "2026-05-27T12:19:03.884Z", "disclosures": [ { "identifier": "_jxx", diff --git a/metadata/modules/justIdSystem.json b/metadata/modules/justIdSystem.json index 29e9ff13dad..9776b93a1de 100644 --- a/metadata/modules/justIdSystem.json +++ b/metadata/modules/justIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audience-solutions.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:41.189Z", + "timestamp": "2026-05-27T12:19:03.885Z", "disclosures": [ { "identifier": "__jtuid", diff --git a/metadata/modules/justpremiumBidAdapter.json b/metadata/modules/justpremiumBidAdapter.json index 6e673c6c5e2..c2a9ba0703f 100644 --- a/metadata/modules/justpremiumBidAdapter.json +++ b/metadata/modules/justpremiumBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.justpremium.com/devicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:04:41.869Z", + "timestamp": "2026-05-27T12:19:04.352Z", "disclosures": [] } }, diff --git a/metadata/modules/jwplayerBidAdapter.json b/metadata/modules/jwplayerBidAdapter.json index d97d4b1c1d5..2b04e286e7b 100644 --- a/metadata/modules/jwplayerBidAdapter.json +++ b/metadata/modules/jwplayerBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.jwplayer.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:42.288Z", + "timestamp": "2026-05-27T12:19:04.688Z", "disclosures": [] } }, diff --git a/metadata/modules/kargoBidAdapter.json b/metadata/modules/kargoBidAdapter.json index f7df17ffa6e..9bb3160b5cf 100644 --- a/metadata/modules/kargoBidAdapter.json +++ b/metadata/modules/kargoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://storage.cloud.kargo.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:42.664Z", + "timestamp": "2026-05-27T12:19:05.075Z", "disclosures": [ { "identifier": "krg_crb", diff --git a/metadata/modules/kueezRtbBidAdapter.json b/metadata/modules/kueezRtbBidAdapter.json index c6d1cbe667a..ccdb590de0a 100644 --- a/metadata/modules/kueezRtbBidAdapter.json +++ b/metadata/modules/kueezRtbBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://en.kueez.com/tcf.json": { - "timestamp": "2026-05-18T20:04:42.860Z", + "timestamp": "2026-05-27T12:19:05.235Z", "disclosures": [ { "identifier": "ck48wz12sqj7", diff --git a/metadata/modules/limelightDigitalBidAdapter.json b/metadata/modules/limelightDigitalBidAdapter.json index 689fe69ba43..4a7913c95eb 100644 --- a/metadata/modules/limelightDigitalBidAdapter.json +++ b/metadata/modules/limelightDigitalBidAdapter.json @@ -2,11 +2,11 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://policy.iion.io/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:42.946Z", + "timestamp": "2026-05-27T12:19:05.281Z", "disclosures": [] }, "https://orangeclickmedia.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:43.167Z", + "timestamp": "2026-05-27T12:19:05.565Z", "disclosures": [] } }, diff --git a/metadata/modules/liveIntentIdSystem.json b/metadata/modules/liveIntentIdSystem.json index 3960d2e5281..c1d99acc62a 100644 --- a/metadata/modules/liveIntentIdSystem.json +++ b/metadata/modules/liveIntentIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://b-code.liadm.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:43.168Z", + "timestamp": "2026-05-27T12:19:05.565Z", "disclosures": [ { "identifier": "_lc2_fpi", diff --git a/metadata/modules/liveIntentRtdProvider.json b/metadata/modules/liveIntentRtdProvider.json index f9590c9a5b1..d7495d7abb1 100644 --- a/metadata/modules/liveIntentRtdProvider.json +++ b/metadata/modules/liveIntentRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://b-code.liadm.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:43.276Z", + "timestamp": "2026-05-27T12:19:05.747Z", "disclosures": [ { "identifier": "_lc2_fpi", diff --git a/metadata/modules/livewrappedBidAdapter.json b/metadata/modules/livewrappedBidAdapter.json index 77bb9ca92f3..91477cb0d8a 100644 --- a/metadata/modules/livewrappedBidAdapter.json +++ b/metadata/modules/livewrappedBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://content.lwadm.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:43.277Z", + "timestamp": "2026-05-27T12:19:05.747Z", "disclosures": [ { "cookieRefresh": false, diff --git a/metadata/modules/loopmeBidAdapter.json b/metadata/modules/loopmeBidAdapter.json index 9a264c291ad..4621bda4e36 100644 --- a/metadata/modules/loopmeBidAdapter.json +++ b/metadata/modules/loopmeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://co.loopme.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:43.475Z", + "timestamp": "2026-05-27T12:19:05.887Z", "disclosures": [] } }, diff --git a/metadata/modules/lotamePanoramaIdSystem.json b/metadata/modules/lotamePanoramaIdSystem.json index 3333a3e728e..98e0bb89031 100644 --- a/metadata/modules/lotamePanoramaIdSystem.json +++ b/metadata/modules/lotamePanoramaIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tags.crwdcntrl.net/privacy/tcf-purposes.json": { - "timestamp": "2026-05-18T20:04:43.661Z", + "timestamp": "2026-05-27T12:19:06.105Z", "disclosures": [ { "identifier": "_cc_id", diff --git a/metadata/modules/luponmediaBidAdapter.json b/metadata/modules/luponmediaBidAdapter.json index e51589d41ec..0bcfe104263 100644 --- a/metadata/modules/luponmediaBidAdapter.json +++ b/metadata/modules/luponmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://luponmedia.com/vendor_device_storage.json": { - "timestamp": "2026-05-18T20:04:43.743Z", + "timestamp": "2026-05-27T12:19:06.262Z", "disclosures": [] } }, diff --git a/metadata/modules/madvertiseBidAdapter.json b/metadata/modules/madvertiseBidAdapter.json index c196931704c..d626c5ffdd3 100644 --- a/metadata/modules/madvertiseBidAdapter.json +++ b/metadata/modules/madvertiseBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserver.bluestack.app/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:44.331Z", + "timestamp": "2026-05-27T12:19:06.693Z", "disclosures": [] } }, diff --git a/metadata/modules/magniteBidAdapter.json b/metadata/modules/magniteBidAdapter.json index 86d006ff117..933df2a08b1 100644 --- a/metadata/modules/magniteBidAdapter.json +++ b/metadata/modules/magniteBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.rubiconproject.com/dvplus/devicestoragedisclosure.json": { - "timestamp": "2026-05-18T20:04:44.847Z", + "timestamp": "2026-05-27T12:19:07.130Z", "disclosures": [] } }, diff --git a/metadata/modules/marsmediaBidAdapter.json b/metadata/modules/marsmediaBidAdapter.json index 0edd353d60d..78dbe5d41dd 100644 --- a/metadata/modules/marsmediaBidAdapter.json +++ b/metadata/modules/marsmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mars.media/apis/tcf-v2.json": { - "timestamp": "2026-05-18T20:04:45.083Z", + "timestamp": "2026-05-27T12:19:07.406Z", "disclosures": [] } }, diff --git a/metadata/modules/matterfullBidAdapter.json b/metadata/modules/matterfullBidAdapter.json new file mode 100644 index 00000000000..9e13d965d97 --- /dev/null +++ b/metadata/modules/matterfullBidAdapter.json @@ -0,0 +1,13 @@ +{ + "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", + "disclosures": {}, + "components": [ + { + "componentType": "bidder", + "componentName": "matterfull", + "aliasOf": null, + "gvlid": null, + "disclosureURL": null + } + ] +} \ No newline at end of file diff --git a/metadata/modules/mediaConsortiumBidAdapter.json b/metadata/modules/mediaConsortiumBidAdapter.json index d2ba34484d1..5e4bdec73c9 100644 --- a/metadata/modules/mediaConsortiumBidAdapter.json +++ b/metadata/modules/mediaConsortiumBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.hubvisor.io/assets/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:45.226Z", + "timestamp": "2026-05-27T12:19:07.601Z", "disclosures": [ { "identifier": "hbv:turbo-cmp", diff --git a/metadata/modules/mediaforceBidAdapter.json b/metadata/modules/mediaforceBidAdapter.json index 28a1d6cedd3..323f54affcd 100644 --- a/metadata/modules/mediaforceBidAdapter.json +++ b/metadata/modules/mediaforceBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://comparisons.org/privacy.json": { - "timestamp": "2026-05-18T20:04:45.677Z", + "timestamp": "2026-05-27T12:19:07.602Z", "disclosures": [] } }, diff --git a/metadata/modules/mediafuseBidAdapter.json b/metadata/modules/mediafuseBidAdapter.json index d44f560b0d8..8493e920091 100644 --- a/metadata/modules/mediafuseBidAdapter.json +++ b/metadata/modules/mediafuseBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:04:45.946Z", + "timestamp": "2026-05-27T12:19:07.864Z", "disclosures": [] } }, diff --git a/metadata/modules/mediagoBidAdapter.json b/metadata/modules/mediagoBidAdapter.json index e2381dbb50b..d7f51e59636 100644 --- a/metadata/modules/mediagoBidAdapter.json +++ b/metadata/modules/mediagoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.mediago.io/js/tcf.json": { - "timestamp": "2026-05-18T20:04:45.946Z", + "timestamp": "2026-05-27T12:19:07.865Z", "disclosures": [] } }, diff --git a/metadata/modules/mediakeysBidAdapter.json b/metadata/modules/mediakeysBidAdapter.json index 687932634ac..7287a4249b7 100644 --- a/metadata/modules/mediakeysBidAdapter.json +++ b/metadata/modules/mediakeysBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s3.eu-west-3.amazonaws.com/adserving.resourcekeys.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:46.082Z", + "timestamp": "2026-05-27T12:19:07.956Z", "disclosures": [] } }, diff --git a/metadata/modules/medianetBidAdapter.json b/metadata/modules/medianetBidAdapter.json index bbe82bcfb10..675cf7a58ed 100644 --- a/metadata/modules/medianetBidAdapter.json +++ b/metadata/modules/medianetBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.media.net/tcfv2/gvl/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:46.455Z", + "timestamp": "2026-05-27T12:19:08.398Z", "disclosures": [ { "identifier": "_mNExInsl", @@ -246,7 +246,7 @@ ] }, "https://trustedstack.com/tcf/gvl/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:46.565Z", + "timestamp": "2026-05-27T12:19:08.534Z", "disclosures": [ { "identifier": "usp_status", diff --git a/metadata/modules/mediasquareBidAdapter.json b/metadata/modules/mediasquareBidAdapter.json index 0d89fa4d263..f5d7b25ff81 100644 --- a/metadata/modules/mediasquareBidAdapter.json +++ b/metadata/modules/mediasquareBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mediasquare.fr/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:46.648Z", + "timestamp": "2026-05-27T12:19:08.777Z", "disclosures": [] } }, diff --git a/metadata/modules/mgidBidAdapter.json b/metadata/modules/mgidBidAdapter.json index d669f0b4de2..c3bfa1b35e4 100644 --- a/metadata/modules/mgidBidAdapter.json +++ b/metadata/modules/mgidBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-18T20:04:47.376Z", + "timestamp": "2026-05-27T12:19:09.069Z", "disclosures": [] } }, diff --git a/metadata/modules/mgidRtdProvider.json b/metadata/modules/mgidRtdProvider.json index 25b048dddc3..fe64f24e2c1 100644 --- a/metadata/modules/mgidRtdProvider.json +++ b/metadata/modules/mgidRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-18T20:04:47.596Z", + "timestamp": "2026-05-27T12:19:09.106Z", "disclosures": [] } }, diff --git a/metadata/modules/mgidXBidAdapter.json b/metadata/modules/mgidXBidAdapter.json index 42f7c5835af..7ea804cd59e 100644 --- a/metadata/modules/mgidXBidAdapter.json +++ b/metadata/modules/mgidXBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-18T20:04:47.596Z", + "timestamp": "2026-05-27T12:19:09.106Z", "disclosures": [] } }, diff --git a/metadata/modules/minutemediaBidAdapter.json b/metadata/modules/minutemediaBidAdapter.json index 3238b564e92..65fa27d6b93 100644 --- a/metadata/modules/minutemediaBidAdapter.json +++ b/metadata/modules/minutemediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://disclosures.mmctsvc.com/device-storage.json": { - "timestamp": "2026-05-18T20:04:47.597Z", + "timestamp": "2026-05-27T12:19:09.107Z", "disclosures": [] } }, diff --git a/metadata/modules/missenaBidAdapter.json b/metadata/modules/missenaBidAdapter.json index eb2dfa05443..c2b83b1d83c 100644 --- a/metadata/modules/missenaBidAdapter.json +++ b/metadata/modules/missenaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.missena.io/iab.json": { - "timestamp": "2026-05-18T20:04:47.729Z", + "timestamp": "2026-05-27T12:19:09.224Z", "disclosures": [] } }, diff --git a/metadata/modules/mobianRtdProvider.json b/metadata/modules/mobianRtdProvider.json index 8a81da9d6f9..77cb287c355 100644 --- a/metadata/modules/mobianRtdProvider.json +++ b/metadata/modules/mobianRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://js.outcomes.net/tcf.json": { - "timestamp": "2026-05-18T20:04:48.017Z", + "timestamp": "2026-05-27T12:19:09.507Z", "disclosures": [] } }, diff --git a/metadata/modules/mobkoiBidAdapter.json b/metadata/modules/mobkoiBidAdapter.json index b6179ab8583..4ffeca08c95 100644 --- a/metadata/modules/mobkoiBidAdapter.json +++ b/metadata/modules/mobkoiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.maximus.mobkoi.com/tcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:48.329Z", + "timestamp": "2026-05-27T12:19:09.662Z", "disclosures": [] } }, diff --git a/metadata/modules/mobkoiIdSystem.json b/metadata/modules/mobkoiIdSystem.json index a3f33404559..7a9ce3163de 100644 --- a/metadata/modules/mobkoiIdSystem.json +++ b/metadata/modules/mobkoiIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.maximus.mobkoi.com/tcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:48.701Z", + "timestamp": "2026-05-27T12:19:09.801Z", "disclosures": [] } }, diff --git a/metadata/modules/msftBidAdapter.json b/metadata/modules/msftBidAdapter.json index 291e42349af..365132aaafd 100644 --- a/metadata/modules/msftBidAdapter.json +++ b/metadata/modules/msftBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-18T20:04:48.701Z", + "timestamp": "2026-05-27T12:19:09.801Z", "disclosures": [] } }, diff --git a/metadata/modules/nativeryBidAdapter.json b/metadata/modules/nativeryBidAdapter.json index ab5294f8636..0ef07c347c4 100644 --- a/metadata/modules/nativeryBidAdapter.json +++ b/metadata/modules/nativeryBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdnimg.nativery.com/widget/js/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:48.702Z", + "timestamp": "2026-05-27T12:19:09.802Z", "disclosures": [] } }, diff --git a/metadata/modules/nativoBidAdapter.json b/metadata/modules/nativoBidAdapter.json index df30f220781..ddc69cf2d50 100644 --- a/metadata/modules/nativoBidAdapter.json +++ b/metadata/modules/nativoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab.nativo.com/tcf-disclosures.json": { - "timestamp": "2026-05-18T20:04:49.201Z", + "timestamp": "2026-05-27T12:19:10.190Z", "disclosures": [] } }, diff --git a/metadata/modules/newspassidBidAdapter.json b/metadata/modules/newspassidBidAdapter.json index 46fac8088dd..8b2c5ed5e9b 100644 --- a/metadata/modules/newspassidBidAdapter.json +++ b/metadata/modules/newspassidBidAdapter.json @@ -1,8 +1,8 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { - "https://www.aditude.com/storageaccess.json": { - "timestamp": "2026-05-18T20:04:49.386Z", + "https://cdn-prod.aditude.com/storageaccess.json": { + "timestamp": "2026-05-27T12:19:10.247Z", "disclosures": [] } }, @@ -12,7 +12,7 @@ "componentName": "newspassid", "aliasOf": null, "gvlid": 1317, - "disclosureURL": "https://www.aditude.com/storageaccess.json" + "disclosureURL": "https://cdn-prod.aditude.com/storageaccess.json" } ] } \ No newline at end of file diff --git a/metadata/modules/nextMillenniumBidAdapter.json b/metadata/modules/nextMillenniumBidAdapter.json index 0c63ac6b502..bbe2f6a0221 100644 --- a/metadata/modules/nextMillenniumBidAdapter.json +++ b/metadata/modules/nextMillenniumBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://nextmillennium.io/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:49.387Z", + "timestamp": "2026-05-27T12:19:10.247Z", "disclosures": [] } }, diff --git a/metadata/modules/nextrollBidAdapter.json b/metadata/modules/nextrollBidAdapter.json index e0679fc63a4..fb0b48c9ebf 100644 --- a/metadata/modules/nextrollBidAdapter.json +++ b/metadata/modules/nextrollBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.adroll.com/shares/device_storage.json": { - "timestamp": "2026-05-18T20:04:49.670Z", + "timestamp": "2026-05-27T12:19:10.297Z", "disclosures": [ { "identifier": "__adroll_fpc", diff --git a/metadata/modules/nexx360BidAdapter.json b/metadata/modules/nexx360BidAdapter.json index f34dd5e0e4b..c40297df520 100644 --- a/metadata/modules/nexx360BidAdapter.json +++ b/metadata/modules/nexx360BidAdapter.json @@ -2,19 +2,19 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://fast.nexx360.io/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:52.030Z", + "timestamp": "2026-05-27T12:19:12.289Z", "disclosures": [] }, "https://static.first-id.fr/tcf/cookie.json": { - "timestamp": "2026-05-18T20:04:50.117Z", + "timestamp": "2026-05-27T12:19:10.635Z", "disclosures": [] }, "https://i.plug.it/banners/js/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:50.670Z", + "timestamp": "2026-05-27T12:19:11.177Z", "disclosures": [] }, "https://player.glomex.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:51.376Z", + "timestamp": "2026-05-27T12:19:11.864Z", "disclosures": [ { "identifier": "glomexUser", @@ -32,6 +32,15 @@ 10 ] }, + { + "identifier": "turboPlayerProfile", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1 + ] + }, { "identifier": "ET_EventCollector_SessionInstallationId", "type": "web", @@ -46,7 +55,7 @@ ] }, "https://gdpr.pubx.ai/devicestoragedisclosure.json": { - "timestamp": "2026-05-18T20:04:51.376Z", + "timestamp": "2026-05-27T12:19:11.864Z", "disclosures": [ { "identifier": "pubx:defaults", @@ -60,9 +69,52 @@ } ] }, - "https://yieldbird.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:51.556Z", - "disclosures": [] + "https://yieldbird.com/device-storage-disclosure.json": { + "timestamp": "2026-05-27T12:19:11.906Z", + "disclosures": [ + { + "identifier": "pm_utm_*", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1, + 7, + 9, + 10 + ], + "specialPurposes": [], + "description": "First-party web storage used by Yieldbird PrebidManager to persist UTM campaign parameters for operational analytics, advertising performance measurement, audience statistics and service improvement." + }, + { + "identifier": "yb_ab_test", + "type": "cookie", + "maxAgeSeconds": 604800, + "cookieRefresh": false, + "purposes": [ + 1, + 7, + 9, + 10 + ], + "specialPurposes": [], + "description": "Cookie used by Yieldbird QW wrapper to assign and persist A/B test participation for advertising performance measurement, audience statistics and service improvement." + }, + { + "identifier": "yb_ab_test", + "type": "web", + "maxAgeSeconds": null, + "cookieRefresh": false, + "purposes": [ + 1, + 7, + 9, + 10 + ], + "specialPurposes": [], + "description": "Session storage used by Yieldbird QW wrapper to assign and persist A/B test participation for advertising performance measurement, audience statistics and service improvement." + } + ] } }, "components": [ @@ -176,7 +228,7 @@ "componentName": "ybidder", "aliasOf": "nexx360", "gvlid": 1253, - "disclosureURL": "https://yieldbird.com/devicestorage.json" + "disclosureURL": "https://yieldbird.com/device-storage-disclosure.json" }, { "componentType": "bidder", diff --git a/metadata/modules/nobidBidAdapter.json b/metadata/modules/nobidBidAdapter.json index 5c859e4933b..31c8ca804c4 100644 --- a/metadata/modules/nobidBidAdapter.json +++ b/metadata/modules/nobidBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://public.servenobid.com/gdpr_tcf/vendor_device_storage_operational_disclosures.json": { - "timestamp": "2026-05-18T20:04:52.031Z", + "timestamp": "2026-05-27T12:19:12.290Z", "disclosures": [] } }, diff --git a/metadata/modules/nodalsAiRtdProvider.json b/metadata/modules/nodalsAiRtdProvider.json index c81c6776035..5ccb789150a 100644 --- a/metadata/modules/nodalsAiRtdProvider.json +++ b/metadata/modules/nodalsAiRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.nodals.ai/vendor.json": { - "timestamp": "2026-05-18T20:04:52.089Z", + "timestamp": "2026-05-27T12:19:12.379Z", "disclosures": [ { "identifier": "localStorage", diff --git a/metadata/modules/novatiqIdSystem.json b/metadata/modules/novatiqIdSystem.json index 7f8750bda69..3503a377a43 100644 --- a/metadata/modules/novatiqIdSystem.json +++ b/metadata/modules/novatiqIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://novatiq.com/privacy/iab/novatiq.json": { - "timestamp": "2026-05-18T20:04:52.595Z", + "timestamp": "2026-05-27T12:19:12.614Z", "disclosures": [ { "identifier": "novatiq", diff --git a/metadata/modules/oguryBidAdapter.json b/metadata/modules/oguryBidAdapter.json index 1034032f066..fab898b5f9f 100644 --- a/metadata/modules/oguryBidAdapter.json +++ b/metadata/modules/oguryBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.ogury.co/disclosure.json": { - "timestamp": "2026-05-18T20:04:53.133Z", + "timestamp": "2026-05-27T12:19:12.963Z", "disclosures": [] } }, diff --git a/metadata/modules/omnidexBidAdapter.json b/metadata/modules/omnidexBidAdapter.json index f2730838e2a..06874b573c4 100644 --- a/metadata/modules/omnidexBidAdapter.json +++ b/metadata/modules/omnidexBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.omni-dex.io/devicestorage.json": { - "timestamp": "2026-05-18T20:04:53.335Z", + "timestamp": "2026-05-27T12:19:13.102Z", "disclosures": [ { "identifier": "ck48wz12sqj7", diff --git a/metadata/modules/omsBidAdapter.json b/metadata/modules/omsBidAdapter.json index a712234d07f..84b153fbcc9 100644 --- a/metadata/modules/omsBidAdapter.json +++ b/metadata/modules/omsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.marphezis.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-18T20:04:53.407Z", + "timestamp": "2026-05-27T12:19:13.168Z", "disclosures": [] } }, diff --git a/metadata/modules/onetagBidAdapter.json b/metadata/modules/onetagBidAdapter.json index a5f868f9de2..119ca338c97 100644 --- a/metadata/modules/onetagBidAdapter.json +++ b/metadata/modules/onetagBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://onetag-cdn.com/privacy/tcf_storage.json": { - "timestamp": "2026-05-18T20:04:53.407Z", + "timestamp": "2026-05-27T12:19:13.168Z", "disclosures": [ { "identifier": "onetag_sid", diff --git a/metadata/modules/openwebBidAdapter.json b/metadata/modules/openwebBidAdapter.json index 781adfee6e7..c963896148b 100644 --- a/metadata/modules/openwebBidAdapter.json +++ b/metadata/modules/openwebBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://spotim-prd-static-assets.s3.amazonaws.com/iab/device-storage.json": { - "timestamp": "2026-05-18T20:04:53.833Z", + "timestamp": "2026-05-27T12:19:13.508Z", "disclosures": [] } }, diff --git a/metadata/modules/openxBidAdapter.json b/metadata/modules/openxBidAdapter.json index 47337691f99..1a51c3cec01 100644 --- a/metadata/modules/openxBidAdapter.json +++ b/metadata/modules/openxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.openx.com/device-storage.json": { - "timestamp": "2026-05-18T20:04:53.960Z", + "timestamp": "2026-05-27T12:19:13.641Z", "disclosures": [] } }, diff --git a/metadata/modules/operaadsBidAdapter.json b/metadata/modules/operaadsBidAdapter.json index 3e317979b7f..05b7cc6d854 100644 --- a/metadata/modules/operaadsBidAdapter.json +++ b/metadata/modules/operaadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://res.adx.opera.com/dsd.json": { - "timestamp": "2026-05-18T20:04:54.100Z", + "timestamp": "2026-05-27T12:19:13.704Z", "disclosures": [] } }, diff --git a/metadata/modules/optidigitalBidAdapter.json b/metadata/modules/optidigitalBidAdapter.json index c715c02f3ac..8623c711c5a 100644 --- a/metadata/modules/optidigitalBidAdapter.json +++ b/metadata/modules/optidigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://scripts.opti-digital.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:54.239Z", + "timestamp": "2026-05-27T12:19:13.770Z", "disclosures": [] } }, diff --git a/metadata/modules/optoutBidAdapter.json b/metadata/modules/optoutBidAdapter.json index e038888f368..ac420f36e78 100644 --- a/metadata/modules/optoutBidAdapter.json +++ b/metadata/modules/optoutBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserving.optoutadvertising.com/dsd": { - "timestamp": "2026-05-18T20:04:54.364Z", + "timestamp": "2026-05-27T12:19:13.809Z", "disclosures": [] } }, diff --git a/metadata/modules/orbidderBidAdapter.json b/metadata/modules/orbidderBidAdapter.json index ed951db46f2..f79f17ef56e 100644 --- a/metadata/modules/orbidderBidAdapter.json +++ b/metadata/modules/orbidderBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://orbidder.otto.de/disclosure/dsd.json": { - "timestamp": "2026-05-18T20:04:54.800Z", + "timestamp": "2026-05-27T12:19:14.155Z", "disclosures": [] } }, diff --git a/metadata/modules/outbrainBidAdapter.json b/metadata/modules/outbrainBidAdapter.json index bbc298c701b..ac3d83cf583 100644 --- a/metadata/modules/outbrainBidAdapter.json +++ b/metadata/modules/outbrainBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.outbrain.com/privacy/wp-json/privacy/v2/devicestorage.json": { - "timestamp": "2026-05-18T20:04:55.185Z", + "timestamp": "2026-05-27T12:19:14.611Z", "disclosures": [ { "identifier": "dicbo_id", diff --git a/metadata/modules/ozoneBidAdapter.json b/metadata/modules/ozoneBidAdapter.json index 1ac102c60e8..1d3f05255c9 100644 --- a/metadata/modules/ozoneBidAdapter.json +++ b/metadata/modules/ozoneBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://prebid.the-ozone-project.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:55.269Z", + "timestamp": "2026-05-27T12:19:14.641Z", "disclosures": [] } }, diff --git a/metadata/modules/pairIdSystem.json b/metadata/modules/pairIdSystem.json index 45c93beaa6c..470d184870d 100644 --- a/metadata/modules/pairIdSystem.json +++ b/metadata/modules/pairIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.gstatic.com/iabtcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:55.497Z", + "timestamp": "2026-05-27T12:19:14.895Z", "disclosures": [ { "identifier": "__gads", diff --git a/metadata/modules/panxoBidAdapter.json b/metadata/modules/panxoBidAdapter.json index ab327d4978e..d2db1fc15e0 100644 --- a/metadata/modules/panxoBidAdapter.json +++ b/metadata/modules/panxoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.panxo.ai/tcf/device-storage.json": { - "timestamp": "2026-05-18T20:04:55.700Z", + "timestamp": "2026-05-27T12:19:14.953Z", "disclosures": [ { "identifier": "panxo_uid", diff --git a/metadata/modules/performaxBidAdapter.json b/metadata/modules/performaxBidAdapter.json index 4a109f5e0ae..b39c0ec573c 100644 --- a/metadata/modules/performaxBidAdapter.json +++ b/metadata/modules/performaxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.performax.cz/device_storage.json": { - "timestamp": "2026-05-18T20:04:55.894Z", + "timestamp": "2026-05-27T12:19:15.128Z", "disclosures": [ { "identifier": "px2uid", diff --git a/metadata/modules/permutiveIdentityManagerIdSystem.json b/metadata/modules/permutiveIdentityManagerIdSystem.json index b0000cbe630..10db8d396f5 100644 --- a/metadata/modules/permutiveIdentityManagerIdSystem.json +++ b/metadata/modules/permutiveIdentityManagerIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.permutive.app/tcf/tcf.json": { - "timestamp": "2026-05-18T20:04:56.471Z", + "timestamp": "2026-05-27T12:19:15.675Z", "disclosures": [ { "identifier": "_pdfps", diff --git a/metadata/modules/permutiveRtdProvider.json b/metadata/modules/permutiveRtdProvider.json index 37586efd5be..2795ac124e0 100644 --- a/metadata/modules/permutiveRtdProvider.json +++ b/metadata/modules/permutiveRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.permutive.app/tcf/tcf.json": { - "timestamp": "2026-05-18T20:04:56.684Z", + "timestamp": "2026-05-27T12:19:15.840Z", "disclosures": [ { "identifier": "_pdfps", diff --git a/metadata/modules/pgamdirectBidAdapter.json b/metadata/modules/pgamdirectBidAdapter.json index f28865ccd57..3f5f695ce6a 100644 --- a/metadata/modules/pgamdirectBidAdapter.json +++ b/metadata/modules/pgamdirectBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.pgammedia.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:56.685Z", + "timestamp": "2026-05-27T12:19:15.840Z", "disclosures": [] } }, diff --git a/metadata/modules/pixfutureBidAdapter.json b/metadata/modules/pixfutureBidAdapter.json index f7600419c14..a9b422a77e8 100644 --- a/metadata/modules/pixfutureBidAdapter.json +++ b/metadata/modules/pixfutureBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.pixfuture.com/vendor-disclosures.json": { - "timestamp": "2026-05-18T20:04:56.799Z", + "timestamp": "2026-05-27T12:19:15.916Z", "disclosures": [] } }, diff --git a/metadata/modules/playdigoBidAdapter.json b/metadata/modules/playdigoBidAdapter.json index cda4b372796..f5beb0c0bfd 100644 --- a/metadata/modules/playdigoBidAdapter.json +++ b/metadata/modules/playdigoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://playdigo.com/file.json": { - "timestamp": "2026-05-18T20:04:56.966Z", + "timestamp": "2026-05-27T12:19:16.019Z", "disclosures": [] } }, diff --git a/metadata/modules/prebid-core.json b/metadata/modules/prebid-core.json index 59af0e979fe..107694e274c 100644 --- a/metadata/modules/prebid-core.json +++ b/metadata/modules/prebid-core.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/probes.json": { - "timestamp": "2026-05-18T20:03:46.492Z", + "timestamp": "2026-05-27T12:17:29.210Z", "disclosures": [ { "identifier": "_rdc*", @@ -23,7 +23,7 @@ ] }, "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/debugging.json": { - "timestamp": "2026-05-18T20:03:46.492Z", + "timestamp": "2026-05-27T12:17:29.210Z", "disclosures": [ { "identifier": "__*_debugging__", diff --git a/metadata/modules/precisoBidAdapter.json b/metadata/modules/precisoBidAdapter.json index a516d7492b8..75c522790eb 100644 --- a/metadata/modules/precisoBidAdapter.json +++ b/metadata/modules/precisoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://preciso.net/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:57.218Z", + "timestamp": "2026-05-27T12:19:16.246Z", "disclosures": [ { "identifier": "XXXXX_viewnew", diff --git a/metadata/modules/prismaBidAdapter.json b/metadata/modules/prismaBidAdapter.json index e109f5071b2..db901ebc8f3 100644 --- a/metadata/modules/prismaBidAdapter.json +++ b/metadata/modules/prismaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://fast.nexx360.io/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:57.570Z", + "timestamp": "2026-05-27T12:19:16.520Z", "disclosures": [] } }, diff --git a/metadata/modules/programmaticXBidAdapter.json b/metadata/modules/programmaticXBidAdapter.json index 262980003fc..3f93072b892 100644 --- a/metadata/modules/programmaticXBidAdapter.json +++ b/metadata/modules/programmaticXBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://progrtb.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-18T20:04:57.570Z", + "timestamp": "2026-05-27T12:19:16.521Z", "disclosures": [] } }, diff --git a/metadata/modules/proxistoreBidAdapter.json b/metadata/modules/proxistoreBidAdapter.json index df90835373e..9a9991e3200 100644 --- a/metadata/modules/proxistoreBidAdapter.json +++ b/metadata/modules/proxistoreBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://abs.proxistore.com/assets/json/proxistore_device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:57.809Z", + "timestamp": "2026-05-27T12:19:16.677Z", "disclosures": [] } }, diff --git a/metadata/modules/publinkIdSystem.json b/metadata/modules/publinkIdSystem.json index 84ec35adad3..7ec5191d077 100644 --- a/metadata/modules/publinkIdSystem.json +++ b/metadata/modules/publinkIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s-usweb.dotomi.com/assets/js/taggy-js/2.18.13/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:04:58.663Z", + "timestamp": "2026-05-27T12:19:17.215Z", "disclosures": [ { "identifier": "dtm_status", diff --git a/metadata/modules/pubmaticBidAdapter.json b/metadata/modules/pubmaticBidAdapter.json index 4ff92ce98b8..cea0023d8d9 100644 --- a/metadata/modules/pubmaticBidAdapter.json +++ b/metadata/modules/pubmaticBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pubmatic.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:58.664Z", + "timestamp": "2026-05-27T12:19:17.216Z", "disclosures": [] } }, diff --git a/metadata/modules/pubmaticIdSystem.json b/metadata/modules/pubmaticIdSystem.json index 07b714f6990..b01a0031110 100644 --- a/metadata/modules/pubmaticIdSystem.json +++ b/metadata/modules/pubmaticIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pubmatic.com/devicestorage.json": { - "timestamp": "2026-05-18T20:04:58.880Z", + "timestamp": "2026-05-27T12:19:17.243Z", "disclosures": [] } }, diff --git a/metadata/modules/pubstackBidAdapter.json b/metadata/modules/pubstackBidAdapter.json index 1ebd7c9fa12..60032712491 100644 --- a/metadata/modules/pubstackBidAdapter.json +++ b/metadata/modules/pubstackBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pbstck.com/privacy_policies/device_storage_disclosures.json": { - "timestamp": "2026-05-18T20:04:58.969Z", + "timestamp": "2026-05-27T12:19:17.364Z", "disclosures": [] } }, diff --git a/metadata/modules/pulsepointBidAdapter.json b/metadata/modules/pulsepointBidAdapter.json index a6279f67d6f..000c1e9df7f 100644 --- a/metadata/modules/pulsepointBidAdapter.json +++ b/metadata/modules/pulsepointBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bh.contextweb.com/tcf/vendorInfo.json": { - "timestamp": "2026-05-18T20:04:58.970Z", + "timestamp": "2026-05-27T12:19:17.365Z", "disclosures": [] } }, diff --git a/metadata/modules/r2b2BidAdapter.json b/metadata/modules/r2b2BidAdapter.json index f98783fd527..e04a28b7055 100644 --- a/metadata/modules/r2b2BidAdapter.json +++ b/metadata/modules/r2b2BidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.r2b2.io/cookie_disclosure": { - "timestamp": "2026-05-18T20:04:59.361Z", + "timestamp": "2026-05-27T12:19:17.616Z", "disclosures": [ { "identifier": "AdTrack-hide-*", diff --git a/metadata/modules/readpeakBidAdapter.json b/metadata/modules/readpeakBidAdapter.json index 7d083b81f34..019b7830656 100644 --- a/metadata/modules/readpeakBidAdapter.json +++ b/metadata/modules/readpeakBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.readpeak.com/tcf/deviceStorage.json": { - "timestamp": "2026-05-18T20:04:59.850Z", + "timestamp": "2026-05-27T12:19:18.087Z", "disclosures": [ { "identifier": "rp_uidfp", diff --git a/metadata/modules/relevantdigitalBidAdapter.json b/metadata/modules/relevantdigitalBidAdapter.json index f33a847e81e..fcf455aacbd 100644 --- a/metadata/modules/relevantdigitalBidAdapter.json +++ b/metadata/modules/relevantdigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.relevant-digital.com/resources/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:00.109Z", + "timestamp": "2026-05-27T12:19:18.420Z", "disclosures": [ { "identifier": "_rlvData", diff --git a/metadata/modules/resetdigitalBidAdapter.json b/metadata/modules/resetdigitalBidAdapter.json index e7d5a2a8c35..4a428cf625a 100644 --- a/metadata/modules/resetdigitalBidAdapter.json +++ b/metadata/modules/resetdigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resetdigital.co/GDPR-TCF.json": { - "timestamp": "2026-05-18T20:05:00.273Z", + "timestamp": "2026-05-27T12:19:18.587Z", "disclosures": [] } }, diff --git a/metadata/modules/responsiveAdsBidAdapter.json b/metadata/modules/responsiveAdsBidAdapter.json index e62f5312c53..1d02742f472 100644 --- a/metadata/modules/responsiveAdsBidAdapter.json +++ b/metadata/modules/responsiveAdsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://publish.responsiveads.com/tcf/tcf-v2.json": { - "timestamp": "2026-05-18T20:05:00.433Z", + "timestamp": "2026-05-27T12:19:18.630Z", "disclosures": [] } }, diff --git a/metadata/modules/revantageBidAdapter.json b/metadata/modules/revantageBidAdapter.json index 90e20a1728f..e66e5f9682f 100644 --- a/metadata/modules/revantageBidAdapter.json +++ b/metadata/modules/revantageBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://revantage.io/.well-known/tcf-device-storage.json": { - "timestamp": "2026-05-18T20:05:00.635Z", + "timestamp": "2026-05-27T12:19:18.710Z", "disclosures": [] } }, diff --git a/metadata/modules/revcontentBidAdapter.json b/metadata/modules/revcontentBidAdapter.json index 9bb7fe57996..07db0fc40f4 100644 --- a/metadata/modules/revcontentBidAdapter.json +++ b/metadata/modules/revcontentBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sothebys.revcontent.com/static/device_storage.json": { - "timestamp": "2026-05-18T20:05:01.079Z", + "timestamp": "2026-05-27T12:19:19.267Z", "disclosures": [ { "identifier": "__ID", diff --git a/metadata/modules/revnewBidAdapter.json b/metadata/modules/revnewBidAdapter.json index 7008c6c4996..9046c85aaa1 100644 --- a/metadata/modules/revnewBidAdapter.json +++ b/metadata/modules/revnewBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mediafuse.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:01.304Z", + "timestamp": "2026-05-27T12:19:22.571Z", "disclosures": [] } }, diff --git a/metadata/modules/rhythmoneBidAdapter.json b/metadata/modules/rhythmoneBidAdapter.json index e532fcc040a..5b4b4928e18 100644 --- a/metadata/modules/rhythmoneBidAdapter.json +++ b/metadata/modules/rhythmoneBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://video.unrulymedia.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:01.509Z", + "timestamp": "2026-05-27T12:19:22.638Z", "disclosures": [] } }, diff --git a/metadata/modules/richaudienceBidAdapter.json b/metadata/modules/richaudienceBidAdapter.json index a7eb6d4c408..c199208ca16 100644 --- a/metadata/modules/richaudienceBidAdapter.json +++ b/metadata/modules/richaudienceBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdnj.richaudience.com/52a26ab9400b2a9f5aabfa20acf3196g.json": { - "timestamp": "2026-05-18T20:05:01.865Z", + "timestamp": "2026-05-27T12:19:22.928Z", "disclosures": [] } }, diff --git a/metadata/modules/riseBidAdapter.json b/metadata/modules/riseBidAdapter.json index 3be52dbca86..1b5f854ad79 100644 --- a/metadata/modules/riseBidAdapter.json +++ b/metadata/modules/riseBidAdapter.json @@ -2,11 +2,11 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d2pm7iglz0b6eq.cloudfront.net/RiseDeviceStorage.json": { - "timestamp": "2026-05-18T20:05:02.031Z", + "timestamp": "2026-05-27T12:19:23.059Z", "disclosures": [] }, "https://spotim-prd-static-assets.s3.amazonaws.com/iab/device-storage.json": { - "timestamp": "2026-05-18T20:05:02.031Z", + "timestamp": "2026-05-27T12:19:23.059Z", "disclosures": [] } }, diff --git a/metadata/modules/rixengineBidAdapter.json b/metadata/modules/rixengineBidAdapter.json index 0c0902b4711..0ee40a30bbb 100644 --- a/metadata/modules/rixengineBidAdapter.json +++ b/metadata/modules/rixengineBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.algorix.co/gdpr-disclosure.json": { - "timestamp": "2026-05-18T20:05:02.032Z", + "timestamp": "2026-05-27T12:19:23.060Z", "disclosures": [] } }, diff --git a/metadata/modules/rtbhouseBidAdapter.json b/metadata/modules/rtbhouseBidAdapter.json index 9db2d1c2511..726a04394cf 100644 --- a/metadata/modules/rtbhouseBidAdapter.json +++ b/metadata/modules/rtbhouseBidAdapter.json @@ -2,11 +2,12 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.rtbhouse.com/DeviceStorage.json": { - "timestamp": "2026-05-18T20:05:02.125Z", + "timestamp": "2026-05-27T12:19:23.150Z", "disclosures": [ { "identifier": "_rtbh.*", "type": "web", + "maxAgeSeconds": null, "purposes": [ 1, 2, @@ -15,6 +16,111 @@ 7, 9, 10 + ], + "specialPurposes": [ + 1, + 2, + 3 + ] + }, + { + "identifier": "__rtbh.lid", + "type": "cookie", + "maxAgeSeconds": 31536000, + "cookieRefresh": true, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2, + 3 + ] + }, + { + "identifier": "__rtbh.uid", + "type": "cookie", + "maxAgeSeconds": 31536000, + "cookieRefresh": true, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2, + 3 + ] + }, + { + "identifier": "__rtbh.aid", + "type": "cookie", + "maxAgeSeconds": 31536000, + "cookieRefresh": true, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2, + 3 + ] + }, + { + "identifier": "__rtbh.sid", + "type": "cookie", + "maxAgeSeconds": 31536000, + "cookieRefresh": true, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2, + 3 + ] + }, + { + "identifier": "__rtbh.eid", + "type": "cookie", + "maxAgeSeconds": 31536000, + "cookieRefresh": true, + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "specialPurposes": [ + 1, + 2, + 3 ] } ] diff --git a/metadata/modules/rubiconBidAdapter.json b/metadata/modules/rubiconBidAdapter.json index 1f2f2a432f1..32911bad017 100644 --- a/metadata/modules/rubiconBidAdapter.json +++ b/metadata/modules/rubiconBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.rubiconproject.com/dvplus/devicestoragedisclosure.json": { - "timestamp": "2026-05-18T20:05:02.416Z", + "timestamp": "2026-05-27T12:19:23.495Z", "disclosures": [] } }, diff --git a/metadata/modules/scaliburBidAdapter.json b/metadata/modules/scaliburBidAdapter.json index 79503e353d3..3d73d8f6b97 100644 --- a/metadata/modules/scaliburBidAdapter.json +++ b/metadata/modules/scaliburBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://legal.overwolf.com/docs/overwolf/website/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:02.417Z", + "timestamp": "2026-05-27T12:19:23.496Z", "disclosures": [ { "identifier": "scluid", diff --git a/metadata/modules/screencoreBidAdapter.json b/metadata/modules/screencoreBidAdapter.json index f03c922076b..21075e60e2f 100644 --- a/metadata/modules/screencoreBidAdapter.json +++ b/metadata/modules/screencoreBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://screencore.io/tcf.json": { - "timestamp": "2026-05-18T20:05:02.553Z", + "timestamp": "2026-05-27T12:19:23.733Z", "disclosures": [] } }, diff --git a/metadata/modules/seedingAllianceBidAdapter.json b/metadata/modules/seedingAllianceBidAdapter.json index bb3ed98fb2b..5e2160c5c21 100644 --- a/metadata/modules/seedingAllianceBidAdapter.json +++ b/metadata/modules/seedingAllianceBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.nativendo.de/cdn/asset/tcf/purpose-specific-storage-and-access-information.json": { - "timestamp": "2026-05-18T20:05:02.694Z", + "timestamp": "2026-05-27T12:19:23.947Z", "disclosures": [] } }, diff --git a/metadata/modules/seedtagBidAdapter.json b/metadata/modules/seedtagBidAdapter.json index e6aeca74a9f..8e1bd7fbde7 100644 --- a/metadata/modules/seedtagBidAdapter.json +++ b/metadata/modules/seedtagBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.seedtag.com/vendor.json": { - "timestamp": "2026-05-18T20:05:02.983Z", + "timestamp": "2026-05-27T12:19:24.414Z", "disclosures": [] } }, diff --git a/metadata/modules/selectmediaBidAdapter.json b/metadata/modules/selectmediaBidAdapter.json index 66493baa533..203c54f6dfc 100644 --- a/metadata/modules/selectmediaBidAdapter.json +++ b/metadata/modules/selectmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.selectmedia.asia/gdpr/devicestorage.json": { - "timestamp": "2026-05-18T20:05:02.983Z", + "timestamp": "2026-05-27T12:19:24.414Z", "disclosures": [ { "identifier": "waterFallCacheAnsKey_*", diff --git a/metadata/modules/semantiqRtdProvider.json b/metadata/modules/semantiqRtdProvider.json index 5b3e16f4a31..ed4a11ef589 100644 --- a/metadata/modules/semantiqRtdProvider.json +++ b/metadata/modules/semantiqRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audienzz.com/device_storage_disclosure_vendor_783.json": { - "timestamp": "2026-05-18T20:05:03.182Z", + "timestamp": "2026-05-27T12:19:25.581Z", "disclosures": [] } }, diff --git a/metadata/modules/setupadBidAdapter.json b/metadata/modules/setupadBidAdapter.json index 274481b7cfc..e3a67220cfa 100644 --- a/metadata/modules/setupadBidAdapter.json +++ b/metadata/modules/setupadBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cookies.stpd.cloud/disclosures.json": { - "timestamp": "2026-05-18T20:05:03.533Z", + "timestamp": "2026-05-27T12:19:25.811Z", "disclosures": null } }, diff --git a/metadata/modules/sevioBidAdapter.json b/metadata/modules/sevioBidAdapter.json index 4e862215c45..7cc82218307 100644 --- a/metadata/modules/sevioBidAdapter.json +++ b/metadata/modules/sevioBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sevio.com/tcf.json": { - "timestamp": "2026-05-18T20:05:03.580Z", + "timestamp": "2026-05-27T12:19:25.885Z", "disclosures": [] } }, diff --git a/metadata/modules/sharedIdSystem.json b/metadata/modules/sharedIdSystem.json index 6d9954b0057..6d935cede5d 100644 --- a/metadata/modules/sharedIdSystem.json +++ b/metadata/modules/sharedIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/sharedId-optout.json": { - "timestamp": "2026-05-18T20:05:03.820Z", + "timestamp": "2026-05-27T12:19:26.042Z", "disclosures": [ { "identifier": "_pubcid_optout", diff --git a/metadata/modules/sharethroughBidAdapter.json b/metadata/modules/sharethroughBidAdapter.json index a9544194bd7..e919c0ab184 100644 --- a/metadata/modules/sharethroughBidAdapter.json +++ b/metadata/modules/sharethroughBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.sharethrough.com/gvl.json": { - "timestamp": "2026-05-18T20:05:03.821Z", + "timestamp": "2026-05-27T12:19:26.043Z", "disclosures": [] } }, diff --git a/metadata/modules/showheroes-bsBidAdapter.json b/metadata/modules/showheroes-bsBidAdapter.json index 02f27cc5fb4..de9e3f33375 100644 --- a/metadata/modules/showheroes-bsBidAdapter.json +++ b/metadata/modules/showheroes-bsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static-origin.showheroes.com/gvl_storage_disclosure.json": { - "timestamp": "2026-05-18T20:05:04.068Z", + "timestamp": "2026-05-27T12:19:26.160Z", "disclosures": [] } }, diff --git a/metadata/modules/showheroesBidAdapter.json b/metadata/modules/showheroesBidAdapter.json index 4d3ae1aa1fa..382c0066e53 100644 --- a/metadata/modules/showheroesBidAdapter.json +++ b/metadata/modules/showheroesBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static-origin.showheroes.com/gvl_storage_disclosure.json": { - "timestamp": "2026-05-18T20:05:04.646Z", + "timestamp": "2026-05-27T12:19:26.670Z", "disclosures": [] } }, diff --git a/metadata/modules/silvermobBidAdapter.json b/metadata/modules/silvermobBidAdapter.json index 02e34cecc12..f3e213cc830 100644 --- a/metadata/modules/silvermobBidAdapter.json +++ b/metadata/modules/silvermobBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://silvermob.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:04.646Z", + "timestamp": "2026-05-27T12:19:26.671Z", "disclosures": [] } }, diff --git a/metadata/modules/sirdataRtdProvider.json b/metadata/modules/sirdataRtdProvider.json index 1ff1e2ad107..936dc312585 100644 --- a/metadata/modules/sirdataRtdProvider.json +++ b/metadata/modules/sirdataRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.sirdata.eu/sirdata_device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:05:04.908Z", + "timestamp": "2026-05-27T12:19:26.715Z", "disclosures": [] } }, diff --git a/metadata/modules/smaatoBidAdapter.json b/metadata/modules/smaatoBidAdapter.json index 211deb903c5..24699c6995e 100644 --- a/metadata/modules/smaatoBidAdapter.json +++ b/metadata/modules/smaatoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resources.smaato.com/hubfs/Smaato/IAB/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:05.346Z", + "timestamp": "2026-05-27T12:19:27.362Z", "disclosures": [] } }, diff --git a/metadata/modules/smartadserverBidAdapter.json b/metadata/modules/smartadserverBidAdapter.json index 548ea873327..39b53daec84 100644 --- a/metadata/modules/smartadserverBidAdapter.json +++ b/metadata/modules/smartadserverBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apps.smartadserver.com/device-storage-disclosures/equativDeviceStorageDisclosures.json": { - "timestamp": "2026-05-18T20:05:05.571Z", + "timestamp": "2026-05-27T12:19:27.589Z", "disclosures": [] } }, diff --git a/metadata/modules/smartxBidAdapter.json b/metadata/modules/smartxBidAdapter.json index f2434f3b9a9..7d5b15813a6 100644 --- a/metadata/modules/smartxBidAdapter.json +++ b/metadata/modules/smartxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.smartclip.net/iab/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:05.572Z", + "timestamp": "2026-05-27T12:19:27.590Z", "disclosures": [] } }, diff --git a/metadata/modules/smartyadsBidAdapter.json b/metadata/modules/smartyadsBidAdapter.json index 377112b163c..13021760e73 100644 --- a/metadata/modules/smartyadsBidAdapter.json +++ b/metadata/modules/smartyadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://smartyads.com/tcf.json": { - "timestamp": "2026-05-18T20:05:05.782Z", + "timestamp": "2026-05-27T12:19:27.756Z", "disclosures": [] } }, diff --git a/metadata/modules/smilewantedBidAdapter.json b/metadata/modules/smilewantedBidAdapter.json index f1120c7293d..579f4e540d7 100644 --- a/metadata/modules/smilewantedBidAdapter.json +++ b/metadata/modules/smilewantedBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://smilewanted.com/vendor-device-storage-disclosures.json": { - "timestamp": "2026-05-18T20:05:06.006Z", + "timestamp": "2026-05-27T12:19:27.877Z", "disclosures": [] } }, diff --git a/metadata/modules/snigelBidAdapter.json b/metadata/modules/snigelBidAdapter.json index 4a024cf4ef3..958e955da2e 100644 --- a/metadata/modules/snigelBidAdapter.json +++ b/metadata/modules/snigelBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.snigelweb.com/gvl/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:06.521Z", + "timestamp": "2026-05-27T12:19:28.327Z", "disclosures": [] } }, diff --git a/metadata/modules/sonaradsBidAdapter.json b/metadata/modules/sonaradsBidAdapter.json index 0f7918c64ff..2c71818e416 100644 --- a/metadata/modules/sonaradsBidAdapter.json +++ b/metadata/modules/sonaradsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bridgeupp.com/device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:05:06.559Z", + "timestamp": "2026-05-27T12:19:28.433Z", "disclosures": [] } }, diff --git a/metadata/modules/sonobiBidAdapter.json b/metadata/modules/sonobiBidAdapter.json index af7c3d9a30d..82dea214130 100644 --- a/metadata/modules/sonobiBidAdapter.json +++ b/metadata/modules/sonobiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sonobi.com/tcf2-device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:05:06.981Z", + "timestamp": "2026-05-27T12:19:28.726Z", "disclosures": [] } }, diff --git a/metadata/modules/sovrnBidAdapter.json b/metadata/modules/sovrnBidAdapter.json index 7243c860556..c82ab825dd9 100644 --- a/metadata/modules/sovrnBidAdapter.json +++ b/metadata/modules/sovrnBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.sovrn.com/tcf-cookie-disclosure/disclosure.json": { - "timestamp": "2026-05-18T20:05:07.248Z", + "timestamp": "2026-05-27T12:19:28.960Z", "disclosures": [] } }, diff --git a/metadata/modules/sparteoBidAdapter.json b/metadata/modules/sparteoBidAdapter.json index d84337629d4..fe4d04e2d12 100644 --- a/metadata/modules/sparteoBidAdapter.json +++ b/metadata/modules/sparteoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.bricks-co.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:07.418Z", + "timestamp": "2026-05-27T12:19:29.146Z", "disclosures": [ { "identifier": "fastCMP-addtlConsent", diff --git a/metadata/modules/ssmasBidAdapter.json b/metadata/modules/ssmasBidAdapter.json index 40fa2de9948..1882cdbae2a 100644 --- a/metadata/modules/ssmasBidAdapter.json +++ b/metadata/modules/ssmasBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://semseoymas.com/iab.json": { - "timestamp": "2026-05-18T20:05:07.777Z", + "timestamp": "2026-05-27T12:19:29.553Z", "disclosures": null } }, diff --git a/metadata/modules/sspBCBidAdapter.json b/metadata/modules/sspBCBidAdapter.json index 6464eeceda6..69d42236ad2 100644 --- a/metadata/modules/sspBCBidAdapter.json +++ b/metadata/modules/sspBCBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.wp.pl/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:08.552Z", + "timestamp": "2026-05-27T12:19:30.298Z", "disclosures": [] } }, diff --git a/metadata/modules/stackadaptBidAdapter.json b/metadata/modules/stackadaptBidAdapter.json index 21d87dc19f0..566fe3760ff 100644 --- a/metadata/modules/stackadaptBidAdapter.json +++ b/metadata/modules/stackadaptBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s3.amazonaws.com/stackadapt_public/disclosures.json": { - "timestamp": "2026-05-18T20:05:08.552Z", + "timestamp": "2026-05-27T12:19:30.298Z", "disclosures": [ { "identifier": "sa-camp-*", diff --git a/metadata/modules/startioBidAdapter.json b/metadata/modules/startioBidAdapter.json index a50e07b4eeb..ac3c6b3d5c3 100644 --- a/metadata/modules/startioBidAdapter.json +++ b/metadata/modules/startioBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://info.startappservice.com/tcf/start.io_domains.json": { - "timestamp": "2026-05-18T20:05:08.670Z", + "timestamp": "2026-05-27T12:19:30.369Z", "disclosures": [] } }, diff --git a/metadata/modules/startioIdSystem.json b/metadata/modules/startioIdSystem.json index a6a30c69810..6390d0b25fb 100644 --- a/metadata/modules/startioIdSystem.json +++ b/metadata/modules/startioIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://info.startappservice.com/tcf/start.io_domains.json": { - "timestamp": "2026-05-18T20:05:08.846Z", + "timestamp": "2026-05-27T12:19:30.467Z", "disclosures": [] } }, diff --git a/metadata/modules/stroeerCoreBidAdapter.json b/metadata/modules/stroeerCoreBidAdapter.json index ee6f4865d86..f3daa62d508 100644 --- a/metadata/modules/stroeerCoreBidAdapter.json +++ b/metadata/modules/stroeerCoreBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.stroeer.de/StroeerSSP_deviceStorage.json": { - "timestamp": "2026-05-18T20:05:08.846Z", + "timestamp": "2026-05-27T12:19:30.467Z", "disclosures": [] } }, diff --git a/metadata/modules/stvBidAdapter.json b/metadata/modules/stvBidAdapter.json index c2dad679ced..877c2f3fc2a 100644 --- a/metadata/modules/stvBidAdapter.json +++ b/metadata/modules/stvBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.adtech.app/gen/deviceStorageDisclosure/stv.json": { - "timestamp": "2026-05-18T20:05:09.401Z", + "timestamp": "2026-05-27T12:19:30.888Z", "disclosures": [] } }, diff --git a/metadata/modules/sublimeBidAdapter.json b/metadata/modules/sublimeBidAdapter.json index 4870309daf4..51cd4ff1c65 100644 --- a/metadata/modules/sublimeBidAdapter.json +++ b/metadata/modules/sublimeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.ayads.co/cookiepolicy.json": { - "timestamp": "2026-05-18T20:05:10.213Z", + "timestamp": "2026-05-27T12:19:31.560Z", "disclosures": [ { "identifier": "dnt", diff --git a/metadata/modules/taboolaBidAdapter.json b/metadata/modules/taboolaBidAdapter.json index b44ae0f73ca..1476578b19f 100644 --- a/metadata/modules/taboolaBidAdapter.json +++ b/metadata/modules/taboolaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://accessrequest.taboola.com/iab-tcf-v2-disclosure.json": { - "timestamp": "2026-05-18T20:05:10.609Z", + "timestamp": "2026-05-27T12:19:31.728Z", "disclosures": [ { "identifier": "trc_cookie_storage", diff --git a/metadata/modules/taboolaIdSystem.json b/metadata/modules/taboolaIdSystem.json index e451682e7f4..1f2b2d511a1 100644 --- a/metadata/modules/taboolaIdSystem.json +++ b/metadata/modules/taboolaIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://accessrequest.taboola.com/iab-tcf-v2-disclosure.json": { - "timestamp": "2026-05-18T20:05:11.414Z", + "timestamp": "2026-05-27T12:19:32.420Z", "disclosures": [ { "identifier": "trc_cookie_storage", diff --git a/metadata/modules/tadvertisingBidAdapter.json b/metadata/modules/tadvertisingBidAdapter.json index d9c4197b3df..908deb1ec67 100644 --- a/metadata/modules/tadvertisingBidAdapter.json +++ b/metadata/modules/tadvertisingBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.emetriq.de/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:11.415Z", + "timestamp": "2026-05-27T12:19:32.421Z", "disclosures": [] } }, diff --git a/metadata/modules/tappxBidAdapter.json b/metadata/modules/tappxBidAdapter.json index ef45418b7d2..725e73a5a08 100644 --- a/metadata/modules/tappxBidAdapter.json +++ b/metadata/modules/tappxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tappx.com/devicestorage.json": { - "timestamp": "2026-05-18T20:05:11.853Z", + "timestamp": "2026-05-27T12:19:32.571Z", "disclosures": [] } }, diff --git a/metadata/modules/targetVideoBidAdapter.json b/metadata/modules/targetVideoBidAdapter.json index b45d2531a90..9258a4c2702 100644 --- a/metadata/modules/targetVideoBidAdapter.json +++ b/metadata/modules/targetVideoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://target-video.com/vendors-device-storage-and-operational-disclosures.json": { - "timestamp": "2026-05-18T20:05:12.093Z", + "timestamp": "2026-05-27T12:19:32.611Z", "disclosures": [ { "identifier": "brid_location", diff --git a/metadata/modules/teadsBidAdapter.json b/metadata/modules/teadsBidAdapter.json index 2b9b81d1a24..2b1fa85c782 100644 --- a/metadata/modules/teadsBidAdapter.json +++ b/metadata/modules/teadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab-cookie-disclosure.teads.tv/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:12.093Z", + "timestamp": "2026-05-27T12:19:32.612Z", "disclosures": [] } }, diff --git a/metadata/modules/teadsIdSystem.json b/metadata/modules/teadsIdSystem.json index 93b7a68ec97..a661a0efff8 100644 --- a/metadata/modules/teadsIdSystem.json +++ b/metadata/modules/teadsIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab-cookie-disclosure.teads.tv/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:12.129Z", + "timestamp": "2026-05-27T12:19:32.645Z", "disclosures": [] } }, diff --git a/metadata/modules/tealBidAdapter.json b/metadata/modules/tealBidAdapter.json index ecbf29fedbe..78e4e8e6eb6 100644 --- a/metadata/modules/tealBidAdapter.json +++ b/metadata/modules/tealBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://c.bids.ws/iab/disclosures.json": { - "timestamp": "2026-05-18T20:05:12.129Z", + "timestamp": "2026-05-27T12:19:32.645Z", "disclosures": [] } }, diff --git a/metadata/modules/tncIdSystem.json b/metadata/modules/tncIdSystem.json index 67fca247da8..3437050ef69 100644 --- a/metadata/modules/tncIdSystem.json +++ b/metadata/modules/tncIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://js.tncid.app/iab-tcf-device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:05:12.165Z", + "timestamp": "2026-05-27T12:19:32.679Z", "disclosures": [] } }, diff --git a/metadata/modules/tne_catalystBidAdapter.json b/metadata/modules/tne_catalystBidAdapter.json index 11e716a37f7..15de06c4a66 100644 --- a/metadata/modules/tne_catalystBidAdapter.json +++ b/metadata/modules/tne_catalystBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ads.thenexusengine.com/tcf-disclosure.json": { - "timestamp": "2026-05-18T20:05:12.289Z", + "timestamp": "2026-05-27T12:19:32.856Z", "disclosures": [] } }, diff --git a/metadata/modules/topicsFpdModule.json b/metadata/modules/topicsFpdModule.json index 5c4dc63c5d8..01fa7e16765 100644 --- a/metadata/modules/topicsFpdModule.json +++ b/metadata/modules/topicsFpdModule.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/topicsFpdModule.json": { - "timestamp": "2026-05-18T20:03:46.494Z", + "timestamp": "2026-05-27T12:17:29.211Z", "disclosures": [ { "identifier": "prebid:topics", diff --git a/metadata/modules/toponBidAdapter.json b/metadata/modules/toponBidAdapter.json index da8354313c5..7fefb5a76dc 100644 --- a/metadata/modules/toponBidAdapter.json +++ b/metadata/modules/toponBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mores.toponad.net/tcf/toponads_tcf_disclosure.json": { - "timestamp": "2026-05-18T20:05:12.392Z", + "timestamp": "2026-05-27T12:19:32.953Z", "disclosures": [] } }, diff --git a/metadata/modules/tripleliftBidAdapter.json b/metadata/modules/tripleliftBidAdapter.json index ce6e76c44f6..9c459d0bc5d 100644 --- a/metadata/modules/tripleliftBidAdapter.json +++ b/metadata/modules/tripleliftBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://triplelift.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:12.677Z", + "timestamp": "2026-05-27T12:19:33.151Z", "disclosures": [] } }, diff --git a/metadata/modules/ttdBidAdapter.json b/metadata/modules/ttdBidAdapter.json index 9984dbe196d..8e96a6abed5 100644 --- a/metadata/modules/ttdBidAdapter.json +++ b/metadata/modules/ttdBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-18T20:05:12.925Z", + "timestamp": "2026-05-27T12:19:33.328Z", "disclosures": [] } }, diff --git a/metadata/modules/twistDigitalBidAdapter.json b/metadata/modules/twistDigitalBidAdapter.json index 577737a60e7..51701d1d073 100644 --- a/metadata/modules/twistDigitalBidAdapter.json +++ b/metadata/modules/twistDigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://twistdigital.net/iab.json": { - "timestamp": "2026-05-18T20:05:12.925Z", + "timestamp": "2026-05-27T12:19:33.328Z", "disclosures": [ { "identifier": "vdzj1_{id}", diff --git a/metadata/modules/underdogmediaBidAdapter.json b/metadata/modules/underdogmediaBidAdapter.json index 4dd2f1f4bc6..ed15fc865b5 100644 --- a/metadata/modules/underdogmediaBidAdapter.json +++ b/metadata/modules/underdogmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.underdog.media/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:13.055Z", + "timestamp": "2026-05-27T12:19:33.447Z", "disclosures": [ { "identifier": "udm_edge_floater_fcap", diff --git a/metadata/modules/undertoneBidAdapter.json b/metadata/modules/undertoneBidAdapter.json index d504c1b29c5..100fec75ded 100644 --- a/metadata/modules/undertoneBidAdapter.json +++ b/metadata/modules/undertoneBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.undertone.com/js/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:13.182Z", + "timestamp": "2026-05-27T12:19:33.526Z", "disclosures": [] } }, diff --git a/metadata/modules/unifiedIdSystem.json b/metadata/modules/unifiedIdSystem.json index 7f60d1d7bc4..4d75d606770 100644 --- a/metadata/modules/unifiedIdSystem.json +++ b/metadata/modules/unifiedIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-18T20:05:13.377Z", + "timestamp": "2026-05-27T12:19:33.710Z", "disclosures": [] } }, diff --git a/metadata/modules/unrulyBidAdapter.json b/metadata/modules/unrulyBidAdapter.json index 6cb9c3dc244..6424edd1a10 100644 --- a/metadata/modules/unrulyBidAdapter.json +++ b/metadata/modules/unrulyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://video.unrulymedia.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:13.377Z", + "timestamp": "2026-05-27T12:19:33.711Z", "disclosures": [] } }, diff --git a/metadata/modules/userId.json b/metadata/modules/userId.json index e3c61b494e3..03eba774c59 100644 --- a/metadata/modules/userId.json +++ b/metadata/modules/userId.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/userId-optout.json": { - "timestamp": "2026-05-18T20:03:46.496Z", + "timestamp": "2026-05-27T12:17:29.212Z", "disclosures": [ { "identifier": "_pbjs_id_optout", diff --git a/metadata/modules/utiqIdSystem.json b/metadata/modules/utiqIdSystem.json index 30ee56a92bf..6b7f5f55747 100644 --- a/metadata/modules/utiqIdSystem.json +++ b/metadata/modules/utiqIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/utiqDeviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:13.377Z", + "timestamp": "2026-05-27T12:19:33.711Z", "disclosures": [ { "identifier": "utiqPass", diff --git a/metadata/modules/utiqMtpIdSystem.json b/metadata/modules/utiqMtpIdSystem.json index cf0f62097f5..5fd83f3b3eb 100644 --- a/metadata/modules/utiqMtpIdSystem.json +++ b/metadata/modules/utiqMtpIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/utiqDeviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:13.379Z", + "timestamp": "2026-05-27T12:19:33.712Z", "disclosures": [ { "identifier": "utiqPass", diff --git a/metadata/modules/validationFpdModule.json b/metadata/modules/validationFpdModule.json index aae9cb79190..572de202651 100644 --- a/metadata/modules/validationFpdModule.json +++ b/metadata/modules/validationFpdModule.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/sharedId-optout.json": { - "timestamp": "2026-05-18T20:03:46.495Z", + "timestamp": "2026-05-27T12:17:29.212Z", "disclosures": [ { "identifier": "_pubcid_optout", diff --git a/metadata/modules/valuadBidAdapter.json b/metadata/modules/valuadBidAdapter.json index 77c0033cbe2..16577199043 100644 --- a/metadata/modules/valuadBidAdapter.json +++ b/metadata/modules/valuadBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.valuad.cloud/tcfdevice.json": { - "timestamp": "2026-05-18T20:05:13.379Z", + "timestamp": "2026-05-27T12:19:33.712Z", "disclosures": [] } }, diff --git a/metadata/modules/vidazooBidAdapter.json b/metadata/modules/vidazooBidAdapter.json index 56815c4f7f8..17217d4820a 100644 --- a/metadata/modules/vidazooBidAdapter.json +++ b/metadata/modules/vidazooBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vidazoo.com/gdpr-tcf/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:13.675Z", + "timestamp": "2026-05-27T12:19:33.984Z", "disclosures": [ { "identifier": "ck48wz12sqj7", diff --git a/metadata/modules/vidoomyBidAdapter.json b/metadata/modules/vidoomyBidAdapter.json index 9e7d3190e9b..733b15c5f1a 100644 --- a/metadata/modules/vidoomyBidAdapter.json +++ b/metadata/modules/vidoomyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vidoomy.com/storageurl/devicestoragediscurl.json": { - "timestamp": "2026-05-18T20:05:13.820Z", + "timestamp": "2026-05-27T12:19:34.095Z", "disclosures": [] } }, diff --git a/metadata/modules/viouslyBidAdapter.json b/metadata/modules/viouslyBidAdapter.json index 2833320e2ac..ebda39a1e53 100644 --- a/metadata/modules/viouslyBidAdapter.json +++ b/metadata/modules/viouslyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.bricks-co.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:14.434Z", + "timestamp": "2026-05-27T12:19:34.576Z", "disclosures": [ { "identifier": "fastCMP-addtlConsent", diff --git a/metadata/modules/visxBidAdapter.json b/metadata/modules/visxBidAdapter.json index 156de38b9b6..81629003db9 100644 --- a/metadata/modules/visxBidAdapter.json +++ b/metadata/modules/visxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.yoc.com/visx/sellers/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:14.435Z", + "timestamp": "2026-05-27T12:19:34.577Z", "disclosures": [ { "identifier": "__vads", diff --git a/metadata/modules/vlybyBidAdapter.json b/metadata/modules/vlybyBidAdapter.json index 21bcad04419..59270ebfd82 100644 --- a/metadata/modules/vlybyBidAdapter.json +++ b/metadata/modules/vlybyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.vlyby.com/conf/iab/gvl.json": { - "timestamp": "2026-05-18T20:05:14.663Z", + "timestamp": "2026-05-27T12:19:34.794Z", "disclosures": [] } }, diff --git a/metadata/modules/voxBidAdapter.json b/metadata/modules/voxBidAdapter.json index 9985c2099d8..d78305696c6 100644 --- a/metadata/modules/voxBidAdapter.json +++ b/metadata/modules/voxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://st.hybrid.ai/policy/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:15.084Z", + "timestamp": "2026-05-27T12:19:35.222Z", "disclosures": [] } }, diff --git a/metadata/modules/vrtcalBidAdapter.json b/metadata/modules/vrtcalBidAdapter.json index e3f1933e383..c7940b0f81f 100644 --- a/metadata/modules/vrtcalBidAdapter.json +++ b/metadata/modules/vrtcalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vrtcal.com/docs/gdpr-tcf-disclosures.json": { - "timestamp": "2026-05-18T20:05:15.084Z", + "timestamp": "2026-05-27T12:19:35.222Z", "disclosures": [] } }, diff --git a/metadata/modules/vuukleBidAdapter.json b/metadata/modules/vuukleBidAdapter.json index 866e8b4acba..ac44c2e379d 100644 --- a/metadata/modules/vuukleBidAdapter.json +++ b/metadata/modules/vuukleBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.vuukle.com/data-privacy/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:15.197Z", + "timestamp": "2026-05-27T12:19:35.269Z", "disclosures": [ { "identifier": "vuukle_token", diff --git a/metadata/modules/weboramaRtdProvider.json b/metadata/modules/weboramaRtdProvider.json index cb4b2bc7927..4f3de9ad17e 100644 --- a/metadata/modules/weboramaRtdProvider.json +++ b/metadata/modules/weboramaRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cstatic.weborama.fr/tcf/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:15.464Z", + "timestamp": "2026-05-27T12:19:35.561Z", "disclosures": [] } }, diff --git a/metadata/modules/welectBidAdapter.json b/metadata/modules/welectBidAdapter.json index 397b43fa89e..4d250b7280b 100644 --- a/metadata/modules/welectBidAdapter.json +++ b/metadata/modules/welectBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.welect.de/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:15.652Z", + "timestamp": "2026-05-27T12:19:36.049Z", "disclosures": [] } }, diff --git a/metadata/modules/wurflRtdProvider.json b/metadata/modules/wurflRtdProvider.json index f05d9834fbd..6bc8cc0bfab 100644 --- a/metadata/modules/wurflRtdProvider.json +++ b/metadata/modules/wurflRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/wurflRtdProvider.json": { - "timestamp": "2026-05-18T20:05:16.239Z", + "timestamp": "2026-05-27T12:19:36.517Z", "disclosures": [ { "identifier": "wurflrtd", diff --git a/metadata/modules/yahooAdsBidAdapter.json b/metadata/modules/yahooAdsBidAdapter.json index 560b83e2557..87c29234312 100644 --- a/metadata/modules/yahooAdsBidAdapter.json +++ b/metadata/modules/yahooAdsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://meta.legal.yahoo.com/iab-tcf/v2/device-storage-disclosure.json": { - "timestamp": "2026-05-18T20:05:16.239Z", + "timestamp": "2026-05-27T12:19:36.518Z", "disclosures": [ { "identifier": "vmcid", diff --git a/metadata/modules/yaleoBidAdapter.json b/metadata/modules/yaleoBidAdapter.json index 845154df991..0c17f04d691 100644 --- a/metadata/modules/yaleoBidAdapter.json +++ b/metadata/modules/yaleoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audienzz.com/device_storage_disclosure_vendor_783.json": { - "timestamp": "2026-05-18T20:05:16.240Z", + "timestamp": "2026-05-27T12:19:36.518Z", "disclosures": [] } }, diff --git a/metadata/modules/yieldlabBidAdapter.json b/metadata/modules/yieldlabBidAdapter.json index 36421bc9452..1bb78349ef1 100644 --- a/metadata/modules/yieldlabBidAdapter.json +++ b/metadata/modules/yieldlabBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.yieldlab.net/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:16.240Z", + "timestamp": "2026-05-27T12:19:36.519Z", "disclosures": [] } }, diff --git a/metadata/modules/yieldloveBidAdapter.json b/metadata/modules/yieldloveBidAdapter.json index 0f7fcbf4466..68b6265be4e 100644 --- a/metadata/modules/yieldloveBidAdapter.json +++ b/metadata/modules/yieldloveBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn-a.yieldlove.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:16.618Z", + "timestamp": "2026-05-27T12:19:36.642Z", "disclosures": [ { "identifier": "session_id", diff --git a/metadata/modules/yieldmoBidAdapter.json b/metadata/modules/yieldmoBidAdapter.json index bb81b045ad2..3a56012f282 100644 --- a/metadata/modules/yieldmoBidAdapter.json +++ b/metadata/modules/yieldmoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://devicestoragedisclosureurl.yieldmo.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:05:17.040Z", + "timestamp": "2026-05-27T12:19:36.952Z", "disclosures": [] } }, diff --git a/metadata/modules/zeotapIdPlusIdSystem.json b/metadata/modules/zeotapIdPlusIdSystem.json index 38dcc4beaf2..22aba93cf38 100644 --- a/metadata/modules/zeotapIdPlusIdSystem.json +++ b/metadata/modules/zeotapIdPlusIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zd.rqtrk.eu/assets/iab-disclosure.json": { - "timestamp": "2026-05-18T20:05:17.223Z", + "timestamp": "2026-05-27T12:19:37.212Z", "disclosures": [] } }, diff --git a/metadata/modules/zeta_globalBidAdapter.json b/metadata/modules/zeta_globalBidAdapter.json index 0eb8b88a594..4a8b2734d29 100644 --- a/metadata/modules/zeta_globalBidAdapter.json +++ b/metadata/modules/zeta_globalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zetaglobal.com/ZetaDeviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:17.606Z", + "timestamp": "2026-05-27T12:19:37.529Z", "disclosures": [] } }, diff --git a/metadata/modules/zeta_global_sspBidAdapter.json b/metadata/modules/zeta_global_sspBidAdapter.json index 44588a0c55a..9c178d89835 100644 --- a/metadata/modules/zeta_global_sspBidAdapter.json +++ b/metadata/modules/zeta_global_sspBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zetaglobal.com/ZetaDeviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:05:17.695Z", + "timestamp": "2026-05-27T12:19:37.667Z", "disclosures": [] } }, diff --git a/package-lock.json b/package-lock.json index 720a1484391..cdabd26b84f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prebid.js", - "version": "11.14.0-pre", + "version": "11.14.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prebid.js", - "version": "11.14.0-pre", + "version": "11.14.0", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.28.4", diff --git a/package.json b/package.json index f29ef16b45e..b8ad63a696a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "11.14.0-pre", + "version": "11.14.0", "description": "Header Bidding Management Library", "main": "dist/src/prebid.public.ts", "exports": { From c234cffd62644584787c891f0aea42063ca6ae06 Mon Sep 17 00:00:00 2001 From: "Prebid.js automated release" Date: Wed, 27 May 2026 12:20:53 +0000 Subject: [PATCH 006/124] Increment version to 11.15.0-pre --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index cdabd26b84f..9c88bb9abb7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "prebid.js", - "version": "11.14.0", + "version": "11.15.0-pre", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "prebid.js", - "version": "11.14.0", + "version": "11.15.0-pre", "license": "Apache-2.0", "dependencies": { "@babel/core": "^7.28.4", diff --git a/package.json b/package.json index b8ad63a696a..57a30f5d0ae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "prebid.js", - "version": "11.14.0", + "version": "11.15.0-pre", "description": "Header Bidding Management Library", "main": "dist/src/prebid.public.ts", "exports": { From 5f034c160749277e42e6f4fe82d8c88d57a151ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 27 May 2026 09:22:55 -0400 Subject: [PATCH 007/124] Bump tmp from 0.2.4 to 0.2.6 (#14953) Bumps [tmp](https://github.com/raszi/node-tmp) from 0.2.4 to 0.2.6. - [Changelog](https://github.com/raszi/node-tmp/blob/master/CHANGELOG.md) - [Commits](https://github.com/raszi/node-tmp/compare/v0.2.4...v0.2.6) --- updated-dependencies: - dependency-name: tmp dependency-version: 0.2.6 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9c88bb9abb7..5abe85300f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20821,11 +20821,10 @@ } }, "node_modules/tmp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", - "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-5sJPdPjfI5Kx+qbrDesxkglRBxW//g7hCsqspEjwkewGvBMGIKMOTKzLt1hFVJzyadba3lDUN20O9qhvbQUSTA==", "dev": true, - "license": "MIT", "engines": { "node": ">=14.14" } @@ -36416,9 +36415,9 @@ "dev": true }, "tmp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", - "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.6.tgz", + "integrity": "sha512-5sJPdPjfI5Kx+qbrDesxkglRBxW//g7hCsqspEjwkewGvBMGIKMOTKzLt1hFVJzyadba3lDUN20O9qhvbQUSTA==", "dev": true }, "to-absolute-glob": { From 24d3a090d271e402201985b10dbceb4fcd84106a Mon Sep 17 00:00:00 2001 From: Nick Llerandi Date: Wed, 27 May 2026 10:11:20 -0400 Subject: [PATCH 008/124] SSPF-3301: Kargo Adapter: use gppString for GPP consent (fix Prebid API) (#65) (#14954) * Kargo Adapter: use gppString for GPP consent (fix Prebid API) * remove comment Co-authored-by: Julian Gan --- modules/kargoBidAdapter.js | 6 +++--- test/spec/modules/kargoBidAdapter_spec.js | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/kargoBidAdapter.js b/modules/kargoBidAdapter.js index 33355868d19..2242c084939 100644 --- a/modules/kargoBidAdapter.js +++ b/modules/kargoBidAdapter.js @@ -253,7 +253,7 @@ function getUserSyncs(syncOptions, _, gdprConsent, usPrivacy, gppConsent) { var gdpr = (gdprConsent && gdprConsent.gdprApplies) ? 1 : 0; var gdprConsentString = (gdprConsent && gdprConsent.consentString) ? gdprConsent.consentString : ''; - var gppString = (gppConsent && gppConsent.consentString) ? gppConsent.consentString : ''; + var gppString = (gppConsent && gppConsent.gppString) ? gppConsent.gppString : ''; var gppApplicableSections = (gppConsent && gppConsent.applicableSections && Array.isArray(gppConsent.applicableSections)) ? gppConsent.applicableSections.join(',') : ''; // don't sync if opted out via usPrivacy @@ -398,8 +398,8 @@ function getUserIds(tdidAdapter, usp, gdpr, eids, gpp) { // GPP if (gpp) { const parsedGPP = {}; - if (gpp.consentString) { - parsedGPP.gppString = gpp.consentString; + if (gpp.gppString) { + parsedGPP.gppString = gpp.gppString; } if (gpp.applicableSections) { parsedGPP.applicableSections = gpp.applicableSections; diff --git a/test/spec/modules/kargoBidAdapter_spec.js b/test/spec/modules/kargoBidAdapter_spec.js index 4de51a7b860..ebe0f5a7512 100644 --- a/test/spec/modules/kargoBidAdapter_spec.js +++ b/test/spec/modules/kargoBidAdapter_spec.js @@ -1253,7 +1253,7 @@ describe('kargo adapter tests', function() { it('fetches gpp from the bidder request if present', function() { bidderRequest.gppConsent = { - consentString: 'gppString', + gppString: 'gppString', applicableSections: [-1] }; const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); @@ -1266,7 +1266,7 @@ describe('kargo adapter tests', function() { it('does not send empty gpp values', function() { bidderRequest.gppConsent = { - consentString: '', + gppString: '', applicableSections: '' }; const payload = getPayloadFromTestBids([{ ...minimumBidParams }]); @@ -2028,13 +2028,13 @@ describe('kargo adapter tests', function() { it('includes gpp information if provided', function() { [ - { applicableSections: [-1], consentString: 'test-consent-string', as: '-1', cs: 'test-consent-string' }, - { applicableSections: [1, 2, 3], consentString: 'test-consent-string', as: '1,2,3', cs: 'test-consent-string' }, + { applicableSections: [-1], gppString: 'test-consent-string', as: '-1', cs: 'test-consent-string' }, + { applicableSections: [1, 2, 3], gppString: 'test-consent-string', as: '1,2,3', cs: 'test-consent-string' }, { applicableSections: [-1], as: '-1', cs: '' }, - { applicableSections: false, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, - { applicableSections: null, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, - { applicableSections: {}, consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, - { applicableSections: [], consentString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: false, gppString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: null, gppString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: {}, gppString: 'test-consent-string', as: '', cs: 'test-consent-string' }, + { applicableSections: [], gppString: 'test-consent-string', as: '', cs: 'test-consent-string' }, { as: '', cs: '' }, ].forEach(value => expect(getUserSyncs(undefined, undefined, value), `Value - ${value}`) .to.deep.equal(buildSyncUrls(baseUrl @@ -2060,7 +2060,7 @@ describe('kargo adapter tests', function() { expect(getUserSyncs( { gdprApplies: true, consentString: 'test-gdpr-consent' }, '1---', - { applicableSections: [1, 2, 3], consentString: 'test-gpp-consent' } + { applicableSections: [1, 2, 3], gppString: 'test-gpp-consent' } )).to.deep.equal(buildSyncUrls(baseUrl .replace(/gdpr=\d/, 'gdpr=1') .replace(/gdpr_consent=/, 'gdpr_consent=test-gdpr-consent') From f0bd17432ed3b24a6ebaeb23ff5d5ef32a70879d Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 27 May 2026 18:03:41 -0700 Subject: [PATCH 009/124] Core: complete enforcement of accessRequestCredentials (#14935) * Core: fix bug with accessRequestCredentials not controlling access to request credentials * keep shallow copying in abtshieldIdSystem * remove unused function * lint * Fix firefox losing keepalive flag * Use module name in bidder's ajax * add withCallers plumbing * Build-time determination of moduleType/moduleName * fix undetermined callers * fix undetermined callers * fix multi-gvlid that are not asking for credentials * fix adapterManager tests * fix adelerate tests * fix asterio tests * chunk 3 test fixes * chunk 4 test fixes * chunk 4 test fixes * Chunk 5 test fixes * chunk 6 fixes * chunk 7 test fixes * chunk 8 test fixes * remove redundant hasDeviceAccess check * lint * Potential fix for pull request finding 'Semicolon insertion' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Potential fix for pull request finding 'Semicolon insertion' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Potential fix for pull request finding 'Semicolon insertion' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * Improve comments --------- Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Patrick McCann --- babelConfig.js | 1 + .../analyticsAdapter/AnalyticsAdapter.ts | 2 +- .../analyticsAdapter/examples/example2.js | 2 +- libraries/liveIntentId/idSystem.js | 4 +- libraries/mediaImpactUtils/index.js | 2 +- libraries/medianetUtils/logger.js | 2 +- libraries/precisoUtils/bidUtils.js | 2 +- .../uid2IdSystemShared/uid2IdSystem_shared.js | 2 +- modules/adelerateBidAdapter.ts | 10 +- modules/adlooxAdServerVideo.js | 5 +- modules/adtelligentIdSystem.js | 5 +- modules/asterioBidAdapter.ts | 6 +- modules/colombiaBidAdapter.js | 8 +- modules/connatixBidAdapter.js | 6 +- modules/contxtfulBidAdapter.js | 6 +- modules/criteoBidAdapter.js | 6 +- modules/currency.ts | 2 +- modules/datamageRtdProvider.js | 6 +- modules/gamAdServerVideo.js | 2 +- modules/goldbachBidAdapter.js | 5 +- modules/gridBidAdapter.js | 2 +- modules/growthCodeRtdProvider.js | 4 +- modules/idImportLibrary.js | 7 +- modules/impactifyBidAdapter.js | 2 +- modules/insuradsRtdProvider.ts | 6 +- modules/kinessoIdSystem.js | 6 +- modules/limelightDigitalBidAdapter.js | 2 +- modules/locIdSystem.js | 8 +- modules/luceadBidAdapter.js | 6 +- modules/merkleIdSystem.js | 4 +- modules/mileBidAdapter.ts | 11 +- modules/mobianRtdProvider.js | 5 +- modules/nativeryBidAdapter.js | 5 +- modules/naveggIdSystem.js | 5 +- modules/operaadsIdSystem.js | 5 +- modules/performaxBidAdapter.js | 5 +- modules/pgamdirectAnalyticsAdapter.ts | 8 +- modules/priceFloors.ts | 5 +- modules/r2b2AnalyticsAdapter.js | 8 +- modules/rules/index.ts | 2 +- modules/tadvertisingBidAdapter.js | 9 +- modules/tapadIdSystem.js | 8 +- modules/timeoutRtdProvider.js | 5 +- modules/wurflRtdProvider.js | 8 +- modules/yandexBidAdapter.js | 6 +- plugins/callerContext.js | 89 ++ plugins/eslint/resolver.js | 12 +- plugins/eslint/validateImports.js | 4 +- plugins/pbjsGlobals.js | 31 +- plugins/utils.js | 53 ++ src/adapterManager.ts | 10 +- src/ajax.ts | 98 +- src/videoCache.ts | 5 +- test/spec/auctionmanager_spec.js | 8 +- test/spec/modules/adelerateBidAdapter_spec.js | 8 +- test/spec/modules/asterioBidAdapter_spec.js | 5 +- test/spec/modules/colombiaBidAdapter_spec.js | 7 +- test/spec/modules/connatixBidAdapter_spec.js | 5 +- test/spec/modules/contxtfulBidAdapter_spec.js | 16 +- test/spec/modules/criteoBidAdapter_spec.js | 5 +- test/spec/modules/datamageRtdProvider_spec.js | 5 +- test/spec/modules/goldbachBidAdapter_spec.js | 7 +- test/spec/modules/insuradsRtdProvider_spec.js | 5 +- test/spec/modules/kinessoIdSystem_spec.js | 5 +- test/spec/modules/locIdSystem_spec.js | 7 +- test/spec/modules/luceadBidAdapter_spec.js | 7 +- test/spec/modules/merkleIdSystem_spec.js | 4 +- test/spec/modules/mileBidAdapter_spec.js | 8 +- test/spec/modules/mobianRtdProvider_spec.js | 18 +- test/spec/modules/nativeryBidAdapter_spec.js | 19 +- test/spec/modules/naveggIdSystem_spec.js | 5 +- test/spec/modules/performaxBidAdapter_spec.js | 5 +- .../pgamdirectAnalyticsAdapter_spec.js | 5 +- .../spec/modules/r2b2AnalytiscAdapter_spec.js | 9 +- .../modules/tadvertisingBidAdapter_spec.js | 12 +- test/spec/modules/timeoutRtdProvider_spec.js | 6 +- test/spec/modules/wurflRtdProvider_spec.js | 40 +- test/spec/modules/yandexBidAdapter_spec.js | 11 +- test/spec/unit/core/ajax_spec.js | 863 ++++++++++-------- test/spec/unit/pbjs_api_spec.js | 4 +- 80 files changed, 988 insertions(+), 639 deletions(-) create mode 100644 plugins/callerContext.js create mode 100644 plugins/utils.js diff --git a/babelConfig.js b/babelConfig.js index 5d944b12fa0..f813c3f664e 100644 --- a/babelConfig.js +++ b/babelConfig.js @@ -33,6 +33,7 @@ module.exports = function (options = {}) { 'plugins': (() => { const plugins = [ [path.resolve(__dirname, './plugins/pbjsGlobals.js'), options], + [path.resolve(__dirname, './plugins/callerContext.js'), options], [useLocal('@babel/plugin-transform-runtime')], ]; return plugins; diff --git a/libraries/analyticsAdapter/AnalyticsAdapter.ts b/libraries/analyticsAdapter/AnalyticsAdapter.ts index 0cf77d6ed5c..ac60f081fc6 100644 --- a/libraries/analyticsAdapter/AnalyticsAdapter.ts +++ b/libraries/analyticsAdapter/AnalyticsAdapter.ts @@ -1,5 +1,5 @@ import { EVENTS } from '../../src/constants.js'; -import { ajax } from '../../src/ajax.js'; +import { noCredsAjax as ajax } from '../../src/ajax.js'; import { logError, logMessage } from '../../src/utils.js'; import * as events from '../../src/events.js'; import { config } from '../../src/config.js'; diff --git a/libraries/analyticsAdapter/examples/example2.js b/libraries/analyticsAdapter/examples/example2.js index d95a3f54283..2836699b872 100644 --- a/libraries/analyticsAdapter/examples/example2.js +++ b/libraries/analyticsAdapter/examples/example2.js @@ -1,5 +1,5 @@ /* eslint-disable no-console */ -import { ajax } from '../../../src/ajax.js'; +import { noCredsAjax as ajax } from '../../../src/ajax.js'; /** * example2.js - analytics adapter for Example2 Analytics Endpoint example diff --git a/libraries/liveIntentId/idSystem.js b/libraries/liveIntentId/idSystem.js index 9c2cf65f4e8..cf1c12fd263 100644 --- a/libraries/liveIntentId/idSystem.js +++ b/libraries/liveIntentId/idSystem.js @@ -5,7 +5,7 @@ * @requires module:modules/userId */ import { triggerPixel, logError } from '../../src/utils.js'; -import { ajaxBuilder } from '../../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../../src/ajax.js'; import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../../src/adapterManager.js'; import { submodule } from '../../src/hook.js'; import { LiveConnect } from 'live-connect-js'; // eslint-disable-line prebid/validate-imports @@ -26,7 +26,7 @@ const EVENTS_TOPIC = 'pre_lips'; export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); const calls = { ajaxGet: (url, onSuccess, onError, timeout, headers) => { - ajaxBuilder(timeout)( + qualifiedAjaxBuilder(MODULE_TYPE_UID, MODULE_NAME, timeout)( url, { success: onSuccess, diff --git a/libraries/mediaImpactUtils/index.js b/libraries/mediaImpactUtils/index.js index c089e696030..b5bb140ef0a 100644 --- a/libraries/mediaImpactUtils/index.js +++ b/libraries/mediaImpactUtils/index.js @@ -1,5 +1,5 @@ import { buildUrl } from '../../src/utils.js'; -import { ajax } from '../../src/ajax.js'; +import { noCredsAjax as ajax } from '../../src/ajax.js'; /** * Builds the bid requests and beacon parameters. diff --git a/libraries/medianetUtils/logger.js b/libraries/medianetUtils/logger.js index d3dc46419f4..10df86ec5d8 100644 --- a/libraries/medianetUtils/logger.js +++ b/libraries/medianetUtils/logger.js @@ -7,7 +7,7 @@ import { mnetGlobals, POST_ENDPOINT, PREBID_VERSION } from './constants.js'; -import { ajax, sendBeacon } from '../../src/ajax.js'; +import { noCredsAjax as ajax, sendBeacon } from '../../src/ajax.js'; import { getRefererInfo } from '../../src/refererDetection.js'; import { getGlobal } from '../../src/prebidGlobal.js'; diff --git a/libraries/precisoUtils/bidUtils.js b/libraries/precisoUtils/bidUtils.js index 050f758601c..d7959fc7c7c 100644 --- a/libraries/precisoUtils/bidUtils.js +++ b/libraries/precisoUtils/bidUtils.js @@ -1,6 +1,6 @@ import { convertOrtbRequestToProprietaryNative } from '../../src/native.js'; import { replaceAuctionPrice, deepAccess, logInfo } from '../../src/utils.js'; -import { ajax } from '../../src/ajax.js'; +import { noCredsAjax as ajax } from '../../src/ajax.js'; // import { NATIVE } from '../../src/mediaTypes.js'; import { consentCheck, getBidFloor } from './bidUtilsCommon.js'; import { interpretNativeBid } from './bidNativeUtils.js'; diff --git a/libraries/uid2IdSystemShared/uid2IdSystem_shared.js b/libraries/uid2IdSystemShared/uid2IdSystem_shared.js index aa9af0844d7..01801299e1e 100644 --- a/libraries/uid2IdSystemShared/uid2IdSystem_shared.js +++ b/libraries/uid2IdSystemShared/uid2IdSystem_shared.js @@ -1,4 +1,4 @@ -import { ajax } from '../../src/ajax.js' +import { noCredsAjax as ajax } from '../../src/ajax.js' import { cyrb53Hash, logError } from '../../src/utils.js'; export const Uid2CodeVersion = '1.1'; diff --git a/modules/adelerateBidAdapter.ts b/modules/adelerateBidAdapter.ts index 62ea8270104..f381c7ffdf3 100644 --- a/modules/adelerateBidAdapter.ts +++ b/modules/adelerateBidAdapter.ts @@ -5,6 +5,10 @@ import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; +export const dep = { + ajax +}; + type AdelerateBidParams = { placementId: string; publisherId: string; @@ -189,7 +193,7 @@ function onTimeout(data) { if (!data || !data.length) { return; } - ajax(`${EVENTS_ENDPOINT}/timeout`, undefined, JSON.stringify(data), { + dep.ajax(`${EVENTS_ENDPOINT}/timeout`, undefined, JSON.stringify(data), { method: 'POST', keepalive: true, withCredentials: true, @@ -200,7 +204,7 @@ function onBidWon(bid) { if (!bid) { return; } - ajax(`${EVENTS_ENDPOINT}/win`, undefined, JSON.stringify({ + dep.ajax(`${EVENTS_ENDPOINT}/win`, undefined, JSON.stringify({ requestId: bid.requestId, adId: bid.adId, cpm: bid.cpm, @@ -215,7 +219,7 @@ function onBidWon(bid) { function onBidderError(args) { const { error, bidderRequest } = args || {}; - ajax(`${EVENTS_ENDPOINT}/error`, undefined, JSON.stringify({ + dep.ajax(`${EVENTS_ENDPOINT}/error`, undefined, JSON.stringify({ error: error?.status, bidderCode: BIDDER_CODE, auctionId: bidderRequest?.auctionId, diff --git a/modules/adlooxAdServerVideo.js b/modules/adlooxAdServerVideo.js index b7874b10997..6faaf97e525 100644 --- a/modules/adlooxAdServerVideo.js +++ b/modules/adlooxAdServerVideo.js @@ -8,10 +8,13 @@ import { registerVideoSupport } from '../src/adServerManager.js'; import { command as analyticsCommand, COMMAND } from './adlooxAnalyticsAdapter.js'; -import { ajax } from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { EVENTS } from '../src/constants.js'; import { targeting } from '../src/targeting.js'; import { logInfo, isFn, logError, isPlainObject, isStr, isBoolean, deepSetValue, deepClone, timestamp, logWarn } from '../src/utils.js'; +import { MODULE_TYPE_ANALYTICS } from '../src/activities/modules.js'; + +const ajax = qualifiedAjaxBuilder(MODULE_TYPE_ANALYTICS, 'adloox'); const MODULE = 'adlooxAdserverVideo'; diff --git a/modules/adtelligentIdSystem.js b/modules/adtelligentIdSystem.js index 428633a6e4c..4edfc6861a2 100644 --- a/modules/adtelligentIdSystem.js +++ b/modules/adtelligentIdSystem.js @@ -5,8 +5,9 @@ * @requires module:modules/userId */ -import * as ajax from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; /** * @typedef {import('../modules/userId/index.js').Submodule} Submodule @@ -28,7 +29,7 @@ function buildUrl(opts) { } function requestRemoteIdAsync(url, cb) { - ajax.ajaxBuilder()( + qualifiedAjaxBuilder(MODULE_TYPE_UID, moduleName)( url, { success: response => { diff --git a/modules/asterioBidAdapter.ts b/modules/asterioBidAdapter.ts index 313eb4420b5..4c6441367d6 100644 --- a/modules/asterioBidAdapter.ts +++ b/modules/asterioBidAdapter.ts @@ -8,6 +8,10 @@ import type { Size } from '../src/types/common.d.ts'; const BIDDER_CODE = 'asterio'; export const ENDPOINT = 'https://bid.asterio.ai/prebid/bid'; +export const dep = { + ajax +} + export type AsterioBidParams = { adUnitToken: string; pos?: number; @@ -127,7 +131,7 @@ export const spec: BidderSpec = { onBidWon: function (bid: { winUrl?: string; cpm: number }) { if (bid.winUrl) { const winUrl = bid.winUrl.replace(/\$\{AUCTION_PRICE}/, String(bid.cpm)); - ajax(winUrl, null, undefined, { keepalive: true }); + dep.ajax(winUrl, null, undefined, { keepalive: true }); return true; } return false; diff --git a/modules/colombiaBidAdapter.js b/modules/colombiaBidAdapter.js index e791c19fb9b..b7f77b83a43 100644 --- a/modules/colombiaBidAdapter.js +++ b/modules/colombiaBidAdapter.js @@ -8,6 +8,10 @@ const ENDPOINT_URL = 'https://ade.clmbtech.com/cde/prebid.htm'; const ENDPOINT_TIMEOUT = "https://ade.clmbtech.com/cde/bidNotify.htm"; const HOST_NAME = document.location.protocol + '//' + window.location.host; +export const dep = { + ajax +} + export const spec = { code: BIDDER_CODE, aliases: ['clmb'], @@ -124,7 +128,7 @@ export const spec = { payload.bidNotifyType = 1; payload.evt = bid.ext && bid.ext.evtData; - ajax(ENDPOINT_BIDWON, null, JSON.stringify(payload), { + dep.ajax(ENDPOINT_BIDWON, null, JSON.stringify(payload), { method: 'POST', withCredentials: false }); @@ -145,7 +149,7 @@ export const spec = { payload.bidNotifyType = 2; payload.pubAdCodeNames = pubAdCodesString; - ajax(ENDPOINT_TIMEOUT, null, JSON.stringify(payload), { + dep.ajax(ENDPOINT_TIMEOUT, null, JSON.stringify(payload), { method: 'POST', withCredentials: false }); diff --git a/modules/connatixBidAdapter.js b/modules/connatixBidAdapter.js index 1b6c11a385c..67c17059799 100644 --- a/modules/connatixBidAdapter.js +++ b/modules/connatixBidAdapter.js @@ -40,6 +40,10 @@ let cnxIdsValues; const EVENTS_URL = 'https://capi.connatix.com/tr/am'; +export const dep = { + ajax +}; + let context = {}; /* @@ -437,7 +441,7 @@ export const spec = { }, triggerEvent(data) { - ajax(EVENTS_URL, null, JSON.stringify(data), { + dep.ajax(EVENTS_URL, null, JSON.stringify(data), { method: 'POST', withCredentials: false }); diff --git a/modules/contxtfulBidAdapter.js b/modules/contxtfulBidAdapter.js index c057bd78c05..5261363f393 100644 --- a/modules/contxtfulBidAdapter.js +++ b/modules/contxtfulBidAdapter.js @@ -19,6 +19,10 @@ const DEFAULT_TTL = 300; const DEFAULT_SAMPLING_RATE = 1.0; const PREBID_VERSION = '$prebid.version$'; +export const dep = { + ajax +}; + // ORTB conversion const converter = ortbConverter({ context: { @@ -239,7 +243,7 @@ const logEvent = (eventType, data) => { logInfo(BIDDER_CODE, `[${eventType}] Logging data sent using Beacon and payload: ${stringifiedPayload}`); } else { // Fallback to using ajax - ajax(eventUrl, null, stringifiedPayload, { + dep.ajax(eventUrl, null, stringifiedPayload, { method: 'POST', contentType: 'application/json', withCredentials: true, diff --git a/modules/criteoBidAdapter.js b/modules/criteoBidAdapter.js index 1b06d8fe51f..25baadb4677 100644 --- a/modules/criteoBidAdapter.js +++ b/modules/criteoBidAdapter.js @@ -35,6 +35,10 @@ const GUID_RETENTION_TIME_HOUR = 24 * 30 * 13; // 13 months const OPTOUT_RETENTION_TIME_HOUR = 5 * 12 * 30 * 24; // 5 years const DEFAULT_GZIP_ENABLED = true; +export const dep = { + ajax +}; + /** * Defines the generic oRTB converter and all customization functions. */ @@ -404,7 +408,7 @@ export const spec = { const id = readFromAllStorages(BUNDLE_COOKIE_NAME); if (id) { deleteFromAllStorages(BUNDLE_COOKIE_NAME); - ajax('https://privacy.criteo.com/api/privacy/datadeletionrequest', + dep.ajax('https://privacy.criteo.com/api/privacy/datadeletionrequest', null, JSON.stringify({ publisherUserId: id }), { diff --git a/modules/currency.ts b/modules/currency.ts index 5517916a6b7..b66c2100351 100644 --- a/modules/currency.ts +++ b/modules/currency.ts @@ -1,7 +1,7 @@ import { deepSetValue, logError, logInfo, logMessage, logWarn } from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { EVENTS, REJECTION_REASON } from '../src/constants.js'; -import { ajax } from '../src/ajax.js'; +import { noCredsAjax as ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; import { getHook } from '../src/hook.js'; import { defer } from '../src/utils/promise.js'; diff --git a/modules/datamageRtdProvider.js b/modules/datamageRtdProvider.js index 178eb35a47f..f0befbf0401 100644 --- a/modules/datamageRtdProvider.js +++ b/modules/datamageRtdProvider.js @@ -4,6 +4,10 @@ import { ajaxBuilder } from '../src/ajax.js'; const MODULE_NAME = 'datamage'; +export const dep = { + ajaxBuilder +}; + let fetchPromise = null; let lastTargeting = null; @@ -107,7 +111,7 @@ function buildApiUrl(params) { function fetchContextData(apiUrl, fetchTimeoutMs) { if (fetchPromise) return fetchPromise; - const ajax = ajaxBuilder(fetchTimeoutMs); + const ajax = dep.ajaxBuilder(fetchTimeoutMs); fetchPromise = new Promise((resolve, reject) => { ajax(apiUrl, { success: (responseText) => { diff --git a/modules/gamAdServerVideo.js b/modules/gamAdServerVideo.js index 3fc5dddd678..cfef90df3ac 100644 --- a/modules/gamAdServerVideo.js +++ b/modules/gamAdServerVideo.js @@ -23,7 +23,7 @@ import { } from '../src/utils.js'; import { DEFAULT_GAM_PARAMS, GAM_ENDPOINT, gdprParams } from '../libraries/gamUtils/gamUtils.js'; import { vastLocalCache } from '../src/videoCache.js'; -import { fetch } from '../src/ajax.js'; +import { noCredsFetch as fetch } from '../src/ajax.js'; import XMLUtil from '../libraries/xmlUtils/xmlUtils.js'; import { getGlobalVarName } from '../src/buildOptions.js'; diff --git a/modules/goldbachBidAdapter.js b/modules/goldbachBidAdapter.js index 84cca2ebbb3..c5da61dae90 100644 --- a/modules/goldbachBidAdapter.js +++ b/modules/goldbachBidAdapter.js @@ -40,6 +40,9 @@ const EVENTS = { /* Goldbach storage */ export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); +export const dep = { + ajax +}; const setUid = (uid) => { if (storage.localStorageIsEnabled()) { @@ -185,7 +188,7 @@ const converter = ortbConverter({ const sendLog = (data, percentage = 0.0001) => { if (Math.random() > percentage) return; const encodedData = `data=${window.btoa(JSON.stringify({ ...data, source: 'goldbach_pbjs', projectedAmount: (1 / percentage) }))}`; - ajax(URL_LOGGING, null, encodedData, { + dep.ajax(URL_LOGGING, null, encodedData, { withCredentials: false, method: METHOD, crossOrigin: true, diff --git a/modules/gridBidAdapter.js b/modules/gridBidAdapter.js index 31a592cf6b6..372933842f2 100644 --- a/modules/gridBidAdapter.js +++ b/modules/gridBidAdapter.js @@ -10,7 +10,7 @@ import { isStr, isPlainObject } from '../src/utils.js'; -import { ajax } from '../src/ajax.js'; +import { noCredsAjax as ajax } from '../src/ajax.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { Renderer } from '../src/Renderer.js'; import { VIDEO, BANNER } from '../src/mediaTypes.js'; diff --git a/modules/growthCodeRtdProvider.js b/modules/growthCodeRtdProvider.js index 3e5a5b9119e..06dc72e5f9a 100644 --- a/modules/growthCodeRtdProvider.js +++ b/modules/growthCodeRtdProvider.js @@ -7,7 +7,7 @@ import { getStorageManager } from '../src/storageManager.js'; import { logMessage, logError, mergeDeep } from '../src/utils.js'; -import * as ajax from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; import { tryAppendQueryString } from '../libraries/urlUtils/urlUtils.js'; @@ -85,7 +85,7 @@ function callServer(configParams, items, expiresAt, userConsent) { url = tryAppendQueryString(url, 'tcf', userConsent.gdpr.consentString) } - ajax.ajaxBuilder()(url, { + qualifiedAjaxBuilder(MODULE_TYPE_RTD, MODULE_NAME)(url, { success: response => { const respJson = tryParse(response); // If response is a valid json and should save is true diff --git a/modules/idImportLibrary.js b/modules/idImportLibrary.js index 248f999f5bd..4028523f7cc 100644 --- a/modules/idImportLibrary.js +++ b/modules/idImportLibrary.js @@ -3,11 +3,12 @@ import { ACTIVITY_ENRICH_UFPD } from '../src/activities/activities.js'; import { activityParams } from '../src/activities/activityParams.js'; import { MODULE_TYPE_PREBID } from '../src/activities/modules.js'; import { isActivityAllowed } from '../src/activities/rules.js'; -import { ajax } from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { config } from '../src/config.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { logError, logInfo } from '../src/utils.js'; +const moduleName = 'idImportLibrary'; let email; let conf; const LOG_PRE_FIX = 'ID-Library: '; @@ -235,7 +236,7 @@ function postData() { syncPayload.uids = userIds; const payloadString = JSON.stringify(syncPayload); _logInfo(payloadString); - ajax(conf.url, syncCallback(), payloadString, { method: 'POST', withCredentials: true }); + qualifiedAjaxBuilder(MODULE_TYPE_PREBID, moduleName)(conf.url, syncCallback(), payloadString, { method: 'POST', withCredentials: true }); } function associateIds() { @@ -261,7 +262,7 @@ export function setConfig(config) { _logError('The required url is not configured'); return; } - if (!isActivityAllowed(ACTIVITY_ENRICH_UFPD, activityParams(MODULE_TYPE_PREBID, 'idImportLibrary'))) { + if (!isActivityAllowed(ACTIVITY_ENRICH_UFPD, activityParams(MODULE_TYPE_PREBID, moduleName))) { _logError('Permission for id import was denied by CMP'); return; } diff --git a/modules/impactifyBidAdapter.js b/modules/impactifyBidAdapter.js index 0307e26ac7e..5230401f28f 100644 --- a/modules/impactifyBidAdapter.js +++ b/modules/impactifyBidAdapter.js @@ -2,7 +2,7 @@ import { deepAccess, deepSetValue, getWinDimensions, isPlainObject, getWindowTop } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { config } from '../src/config.js'; -import { ajax } from '../src/ajax.js'; +import { noCredsAjax as ajax } from '../src/ajax.js'; import { getStorageManager } from '../src/storageManager.js'; import { isViewabilityMeasurable, getViewability } from '../libraries/percentInView/percentInView.js'; diff --git a/modules/insuradsRtdProvider.ts b/modules/insuradsRtdProvider.ts index 1ec232326fe..c957469835e 100644 --- a/modules/insuradsRtdProvider.ts +++ b/modules/insuradsRtdProvider.ts @@ -17,6 +17,10 @@ const GVLID = 596; let keyValues = {}; let apiCallPromise = Promise.resolve(); +export const dep = { + fetch +}; + declare module './rtdModule/spec.ts' { interface ProviderConfig { insuradsRtd: { @@ -87,7 +91,7 @@ async function makeApiCall(publicId: string) { const currentUrl = encodeURIComponent(location.href); try { - const response = await fetch(`${ENDPOINT}/${publicId}?url=${currentUrl}`, { + const response = await dep.fetch(`${ENDPOINT}/${publicId}?url=${currentUrl}`, { method: 'GET', headers: { 'Content-Type': 'application/json' diff --git a/modules/kinessoIdSystem.js b/modules/kinessoIdSystem.js index 8653a7a6737..5a3572b58a5 100644 --- a/modules/kinessoIdSystem.js +++ b/modules/kinessoIdSystem.js @@ -26,6 +26,10 @@ const TIME_LEN = 10; const RANDOM_LEN = 16; const id = factory(); +export const dep = { + ajax +}; + /** * the factory to generate unique identifier based on time and current pseudorandom number * @param {string} currPrng the current pseudorandom number generator @@ -235,7 +239,7 @@ export const kinessoIdSubmodule = { const kinessoIdPayload = {}; kinessoIdPayload.id = knnsoId; const payloadString = JSON.stringify(kinessoIdPayload); - ajax(kinessoSyncUrl(accountId, consentData), syncId(knnsoId), payloadString, { method: 'POST', withCredentials: true }); + dep.ajax(kinessoSyncUrl(accountId, consentData), syncId(knnsoId), payloadString, { method: 'POST', withCredentials: true }); return { 'id': knnsoId }; }, eids: { diff --git a/modules/limelightDigitalBidAdapter.js b/modules/limelightDigitalBidAdapter.js index 5656b34e18a..58f3ac7cfef 100644 --- a/modules/limelightDigitalBidAdapter.js +++ b/modules/limelightDigitalBidAdapter.js @@ -1,7 +1,7 @@ import { uniques, flatten, deepSetValue } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; -import { ajax } from '../src/ajax.js'; +import { noCredsAjax as ajax } from '../src/ajax.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; /** diff --git a/modules/locIdSystem.js b/modules/locIdSystem.js index 5e06e29b302..ec923c84cff 100644 --- a/modules/locIdSystem.js +++ b/modules/locIdSystem.js @@ -30,7 +30,9 @@ const DEFAULT_IP_CACHE_TTL_MS = 4 * 60 * 60 * 1000; // 4 hours const IP_CACHE_SUFFIX = '_ip'; export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); - +export const dep = { + ajaxBuilder +}; /** * Normalizes privacy mode config to a boolean flag. * Supports both requirePrivacySignals (boolean) and privacyMode (string enum). @@ -448,7 +450,7 @@ function fetchLocIdFromEndpoint(config, callback) { }; try { - const ajax = ajaxBuilder(timeoutMs); + const ajax = dep.ajaxBuilder(timeoutMs); ajax(requestUrl, { success: onSuccess, error: onError }, null, requestOptions); } catch (e) { logError(LOG_PREFIX, 'Error initiating request:', e.message); @@ -489,7 +491,7 @@ function fetchIpFromEndpoint(config, callback) { }; try { - const ajax = ajaxBuilder(timeoutMs); + const ajax = dep.ajaxBuilder(timeoutMs); const requestOptions = { method: 'GET', withCredentials: params.withCredentials === true diff --git a/modules/luceadBidAdapter.js b/modules/luceadBidAdapter.js index 52f7718a7ab..1ce7a928194 100755 --- a/modules/luceadBidAdapter.js +++ b/modules/luceadBidAdapter.js @@ -7,6 +7,10 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; import { getUniqueIdentifierStr, deepSetValue, logInfo } from '../src/utils.js'; import { fetch } from '../src/ajax.js'; +export const dep = { + fetch +}; + const bidderCode = 'lucead'; const defaultCurrency = 'EUR'; const defaultTtl = 500; @@ -111,7 +115,7 @@ function interpretResponse(serverResponse, bidRequest) { function report(type, data) { // noinspection JSCheckFunctionSignatures - return fetch(`${endpointUrl}/go/report/${type}`, { + return dep.fetch(`${endpointUrl}/go/report/${type}`, { body: JSON.stringify({ ...data, domain: location.hostname, diff --git a/modules/merkleIdSystem.js b/modules/merkleIdSystem.js index 166bb84b7e1..76f2cab2cdf 100644 --- a/modules/merkleIdSystem.js +++ b/modules/merkleIdSystem.js @@ -6,7 +6,7 @@ */ import { logInfo, logError, logWarn } from '../src/utils.js'; -import * as ajaxLib from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { submodule } from '../src/hook.js' import { getStorageManager } from '../src/storageManager.js'; import { MODULE_TYPE_UID } from '../src/activities/modules.js'; @@ -62,7 +62,7 @@ function generateId(configParams, configStorage) { const url = constructUrl(configParams); const resp = function (callback) { - ajaxLib.ajaxBuilder()( + qualifiedAjaxBuilder(MODULE_TYPE_UID, MODULE_NAME)( url, response => { let responseObj; diff --git a/modules/mileBidAdapter.ts b/modules/mileBidAdapter.ts index a26617279b9..bc78d0ee961 100644 --- a/modules/mileBidAdapter.ts +++ b/modules/mileBidAdapter.ts @@ -31,7 +31,9 @@ declare module '../src/adUnits' { [BIDDER_CODE]: MileBidParams; } } - +export const dep = { + ajax +}; export let siteIdTracker : string | undefined; export let publisherIdTracker : string | undefined; @@ -396,10 +398,9 @@ export const spec: BidderSpec = { site: deepAccess(bid, 'meta.domain') || '', } - ajax(MILE_ANALYTICS_ENDPOINT, null, JSON.stringify([winNotificationData]), { method: 'POST' }); + dep.ajax(MILE_ANALYTICS_ENDPOINT, null, JSON.stringify([winNotificationData]), { method: 'POST' }); - // @ts-expect-error - bid.nurl is not defined - if (bid.nurl) ajax(bid.nurl, null, null, { method: 'GET' }); + if ((bid as any).nurl) dep.ajax((bid as any).nurl, null, null, { method: 'GET' }); }, /** @@ -430,7 +431,7 @@ export const spec: BidderSpec = { timedOutBids.push(timeoutNotificationData); }); - ajax(MILE_ANALYTICS_ENDPOINT, null, JSON.stringify(timedOutBids), { method: 'POST' }); + dep.ajax(MILE_ANALYTICS_ENDPOINT, null, JSON.stringify(timedOutBids), { method: 'POST' }); }, }; diff --git a/modules/mobianRtdProvider.js b/modules/mobianRtdProvider.js index 1e1bd46741e..af5b852f286 100644 --- a/modules/mobianRtdProvider.js +++ b/modules/mobianRtdProvider.js @@ -47,6 +47,9 @@ export const TQ = 'tq'; export const TG = 'tg'; export const THEMES = 'themes'; export const TONES = 'tones'; +export const dep = { + ajaxBuilder +}; export const CONTEXT_KEYS = [ AP_VALUES, @@ -132,7 +135,7 @@ export function makeContextDataToKeyValuesReducer(config) { export async function fetchContextData() { const pageUrl = encodeURIComponent(window.location.href); const requestUrl = `${MOBIAN_URL}?url=${pageUrl}`; - const request = ajaxBuilder(); + const request = dep.ajaxBuilder(); return new Promise((resolve, reject) => { request(requestUrl, { success: resolve, error: reject }); diff --git a/modules/nativeryBidAdapter.js b/modules/nativeryBidAdapter.js index 3b3dadd1d10..fcf6e081beb 100644 --- a/modules/nativeryBidAdapter.js +++ b/modules/nativeryBidAdapter.js @@ -28,6 +28,9 @@ const DEFAULT_CURRENCY = 'EUR'; const TTL = 30; const MAX_IMPS_PER_REQUEST = 10; const GVLID = 1133; +export const dep = { + ajax +}; export const converter = ortbConverter({ context: { @@ -182,7 +185,7 @@ function reportEvent(event, data, sampling = null) { event, data, }; - ajax(EVENT_TRACKER_URL, undefined, safeJSONEncode(payload), { method: 'POST', withCredentials: true, keepalive: true }); + dep.ajax(EVENT_TRACKER_URL, undefined, safeJSONEncode(payload), { method: 'POST', withCredentials: true, keepalive: true }); } } diff --git a/modules/naveggIdSystem.js b/modules/naveggIdSystem.js index feb853cbabf..54dc6297ca8 100644 --- a/modules/naveggIdSystem.js +++ b/modules/naveggIdSystem.js @@ -21,10 +21,13 @@ const NAVEGG_ID = 'nvggid'; const BASE_URL = 'https://id.navegg.com/uid/'; export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); +export const dep = { + ajaxBuilder +}; function getIdFromAPI() { const resp = function (callback) { - ajaxBuilder()( + dep.ajaxBuilder()( BASE_URL, response => { if (response) { diff --git a/modules/operaadsIdSystem.js b/modules/operaadsIdSystem.js index 36c9f9a72d7..c9bfcf87e4a 100644 --- a/modules/operaadsIdSystem.js +++ b/modules/operaadsIdSystem.js @@ -4,9 +4,10 @@ * @module modules/operaadsIdSystem * @requires module:modules/userId */ -import * as ajax from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { submodule } from '../src/hook.js'; import { logMessage, logError } from '../src/utils.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; /** * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig @@ -29,7 +30,7 @@ function constructUrl(pairs) { } function asyncRequest(url, cb) { - ajax.ajaxBuilder(AJAX_TIMEOUT)( + qualifiedAjaxBuilder(MODULE_TYPE_UID, MODULE_NAME, AJAX_TIMEOUT)( url, { success: response => { diff --git a/modules/performaxBidAdapter.js b/modules/performaxBidAdapter.js index 04208811f1b..73ace4f2bc0 100644 --- a/modules/performaxBidAdapter.js +++ b/modules/performaxBidAdapter.js @@ -21,6 +21,9 @@ const LOG_EVENT_TYPE_TIMEOUT = 'timeout'; let isUserSyncsInit = false; export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); +export const dep = { + ajax +}; /** * Sends diagnostic events. @@ -37,7 +40,7 @@ function logEvent(type, payload, sampleRate = LOG_EVENT_SAMPLE_RATE) { const data = { type, payload }; const options = { method: 'POST', withCredentials: true, contentType: 'application/json' }; - ajax(LOG_EVENT_URL, undefined, safeJSONEncode(data), options); + dep.ajax(LOG_EVENT_URL, undefined, safeJSONEncode(data), options); } /** diff --git a/modules/pgamdirectAnalyticsAdapter.ts b/modules/pgamdirectAnalyticsAdapter.ts index 6336dc4eb9e..d7fa3a59ea4 100644 --- a/modules/pgamdirectAnalyticsAdapter.ts +++ b/modules/pgamdirectAnalyticsAdapter.ts @@ -68,6 +68,10 @@ interface PgamAnalyticsOptions { let orgId: string | null = null; let endpoint = DEFAULT_ENDPOINT; +export const dep = { + ajax +}; + const pgamdirectAnalytics = Object.assign( adapter({ url: DEFAULT_ENDPOINT, analyticsType: 'endpoint' }), { @@ -96,7 +100,7 @@ const pgamdirectAnalytics = Object.assign( // navigation / unload get dropped before the XHR lands. The // most valuable events (BID_WON, AD_RENDER_*) fire exactly // in the unload window, so this directly improves delivery. - ajax(endpoint, undefined, body, { + dep.ajax(endpoint, undefined, body, { method: 'POST', withCredentials: false, contentType: 'text/plain', @@ -171,7 +175,7 @@ export function maybePostAuctionContext(args: unknown): void { competitor_high_cpm_usd: competitorHigh, }); // text/plain keeps the POST CORS-simple. - ajax(AUCTION_CONTEXT_ENDPOINT, undefined, body, { + dep.ajax(AUCTION_CONTEXT_ENDPOINT, undefined, body, { method: 'POST', withCredentials: false, contentType: 'text/plain', diff --git a/modules/priceFloors.ts b/modules/priceFloors.ts index 2eacebdd575..e479df45f91 100644 --- a/modules/priceFloors.ts +++ b/modules/priceFloors.ts @@ -17,7 +17,7 @@ import { } from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { config } from '../src/config.js'; -import { ajaxBuilder } from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import * as events from '../src/events.js'; import { EVENTS, REJECTION_REASON } from '../src/constants.js'; import { getHook } from '../src/hook.js'; @@ -34,6 +34,7 @@ import { ALL_MEDIATYPES, BANNER, type MediaType } from '../src/mediaTypes.js'; import type { Currency, Size, BidderCode } from "../src/types/common.d.ts"; import type { BidRequest } from '../src/adapterManager.ts'; import type { Bid } from "../src/bidfactory.ts"; +import { MODULE_TYPE_PREBID } from "../src/activities/modules.ts"; export const FLOOR_SKIPPED_REASON = { NOT_FOUND: 'not_found', @@ -48,7 +49,7 @@ const MODULE_NAME = 'Price Floors'; /** * @summary Instantiate Ajax so we control the timeout */ -const ajax = ajaxBuilder(10000); +const ajax = qualifiedAjaxBuilder(MODULE_TYPE_PREBID, 'priceFloors', 10000); // eslint-disable-next-line symbol-description const SYN_FIELD = Symbol(); diff --git a/modules/r2b2AnalyticsAdapter.js b/modules/r2b2AnalyticsAdapter.js index f452e97e094..8a7f0d41ae1 100644 --- a/modules/r2b2AnalyticsAdapter.js +++ b/modules/r2b2AnalyticsAdapter.js @@ -7,6 +7,10 @@ import { isNumber, isPlainObject, isStr, logError, logWarn } from '../src/utils. import { getRefererInfo } from '../src/refererDetection.js'; import { config } from '../src/config.js'; +export const dep = { + ajax +}; + const ADAPTER_VERSION = '1.1.0'; const ADAPTER_CODE = 'r2b2'; const MODULE_NAME = 'R2B2 Analytics' @@ -155,7 +159,7 @@ function reportError (message, params) { (CONFIG_ID ? `&conf=${encodeURIComponent(CONFIG_ID)}` : '') + (CONFIG_VERSION ? `&conf_ver=${encodeURIComponent(CONFIG_VERSION)}` : '') + `&u=${encodeURIComponent(REPORTED_URL)}`; - ajax(url, null, null, {}); + dep.ajax(url, null, null, {}); } function reportEvents (events) { try { @@ -170,7 +174,7 @@ function reportEvents (events) { contentType: 'application/x-www-form-urlencoded' } data = data.replace(/&/g, '%26'); - ajax(url, null, data, headers); + dep.ajax(url, null, data, headers); } catch (e) { const msg = `Error sending events - ${e.message}`; logError(`${MODULE_NAME}: ${msg}`); diff --git a/modules/rules/index.ts b/modules/rules/index.ts index d9dccd6a86b..144c1d5b62c 100644 --- a/modules/rules/index.ts +++ b/modules/rules/index.ts @@ -4,7 +4,7 @@ import { ACTIVITY_ADD_BID_RESPONSE, ACTIVITY_FETCH_BIDS } from "../../src/activi import { MODULE_TYPE_BIDDER } from "../../src/activities/modules.ts"; import { ACTIVITY_PARAM_COMPONENT_NAME, ACTIVITY_PARAM_COMPONENT_TYPE } from "../../src/activities/params.js"; import { registerActivityControl } from "../../src/activities/rules.js"; -import { ajax } from "../../src/ajax.ts"; +import { noCredsAjax as ajax } from "../../src/ajax.ts"; import { AuctionIndex } from "../../src/auctionIndex.js"; import { auctionManager } from "../../src/auctionManager.js"; import { config } from "../../src/config.ts"; diff --git a/modules/tadvertisingBidAdapter.js b/modules/tadvertisingBidAdapter.js index f2bc9af4fe5..52c2e36091c 100644 --- a/modules/tadvertisingBidAdapter.js +++ b/modules/tadvertisingBidAdapter.js @@ -16,6 +16,11 @@ import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { hasPurpose1Consent } from '../src/utils/gdpr.js'; import { ajax, sendBeacon } from "../src/ajax.js"; +export const dep = { + ajax, + sendBeacon +}; + const BIDDER_CODE = 'tadvertising'; const GVL_ID = 213; const ENDPOINT_URL = 'https://prebid.tads.xplosion.de/bid'; @@ -121,9 +126,9 @@ export const sendNotification = (notifyUrl, eventType, data) => { const notificationUrl = `${notifyUrl}/${eventType}`; const payload = JSON.stringify(data) - if (!sendBeacon(notificationUrl, payload)) { + if (!dep.sendBeacon(notificationUrl, payload)) { // Fallback to using AJAX if Beacon API is not supported - ajax(notificationUrl, null, payload, { + dep.ajax(notificationUrl, null, payload, { method: 'POST', contentType: 'text/plain', keepalive: true, diff --git a/modules/tapadIdSystem.js b/modules/tapadIdSystem.js index 34b83485842..ab580923d90 100644 --- a/modules/tapadIdSystem.js +++ b/modules/tapadIdSystem.js @@ -1,11 +1,13 @@ import { logMessage } from '../src/utils.js'; import { submodule } from '../src/hook.js'; -import * as ajax from '../src/ajax.js' +import { qualifiedAjaxBuilder } from '../src/ajax.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; export const graphUrl = 'https://rtga.tapad.com/v1/graph'; +const MODULE_NAME = 'tapadId'; export const tapadIdSubmodule = { - name: 'tapadId', + name: MODULE_NAME, /** * decode the stored id value for passing to bid requests * @function @@ -34,7 +36,7 @@ export const tapadIdSubmodule = { return { callback: (complete) => { - ajax.ajaxBuilder(10000)( + qualifiedAjaxBuilder(MODULE_TYPE_UID, MODULE_NAME, 10000)( `${graphUrl}?company_id=${configParams.companyId}&tapad_id_type=TAPAD_ID`, { success: (response) => { diff --git a/modules/timeoutRtdProvider.js b/modules/timeoutRtdProvider.js index 72ed6b7b9f8..f820a1b22c5 100644 --- a/modules/timeoutRtdProvider.js +++ b/modules/timeoutRtdProvider.js @@ -1,8 +1,9 @@ import { submodule } from '../src/hook.js'; -import * as ajax from '../src/ajax.js'; +import { qualifiedAjaxBuilder } from '../src/ajax.js'; import { logInfo, deepAccess, logError } from '../src/utils.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { bidderTimeoutFunctions } from '../libraries/bidderTimeoutUtils/bidderTimeoutUtils.js'; +import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -27,7 +28,7 @@ function getBidRequestData(reqBidsConfigObj, callback, config, userConsent) { const timeoutUrl = deepAccess(config, 'params.endpoint.url'); if (timeoutUrl) { logInfo('Timeout url', timeoutUrl); - ajax.ajaxBuilder()(timeoutUrl, { + qualifiedAjaxBuilder(MODULE_TYPE_RTD, SUBMODULE_NAME)(timeoutUrl, { success: function(response) { try { const rules = JSON.parse(response); diff --git a/modules/wurflRtdProvider.js b/modules/wurflRtdProvider.js index 0d024138324..7cf10f73488 100644 --- a/modules/wurflRtdProvider.js +++ b/modules/wurflRtdProvider.js @@ -11,6 +11,10 @@ import { getStorageManager } from '../src/storageManager.js'; import { getGlobal } from '../src/prebidGlobal.js'; import { getHighEntropySUA, getLowEntropySUA } from '../src/fpd/sua.js'; +export const dep = { + fetch, sendBeacon +}; + // Constants const REAL_TIME_MODULE = 'realTimeData'; const MODULE_NAME = 'wurfl'; @@ -1413,13 +1417,13 @@ function onAuctionEndEvent(auctionDetails, config, userConsent) { // Both sendBeacon and fetch send as text/plain to avoid CORS preflight requests. // Server must parse body as JSON regardless of Content-Type header. - const sentBeacon = sendBeacon(url.toString(), payload); + const sentBeacon = dep.sendBeacon(url.toString(), payload); if (sentBeacon) { WurflDebugger.setBeaconPayload(payloadData); return; } - fetch(url.toString(), { + dep.fetch(url.toString(), { method: 'POST', body: payload, mode: 'no-cors', diff --git a/modules/yandexBidAdapter.js b/modules/yandexBidAdapter.js index 20bed71bf26..7761c7425cb 100644 --- a/modules/yandexBidAdapter.js +++ b/modules/yandexBidAdapter.js @@ -9,6 +9,10 @@ import { config as pbjsConfig } from '../src/config.js'; import { isWebdriverEnabled } from '../libraries/webdriver/webdriver.js'; import { getAdUnitElement } from '../src/utils/adUnits.js'; +export const dep = { + ajax +}; + /** * @typedef {import('../src/adapters/bidderFactory.js').Bid} Bid * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest @@ -633,7 +637,7 @@ function eventLog(name, resp) { const domain = getBidderDomain(); - ajax(`https://${domain}${EVENT_TRACKER_URL}`, undefined, JSON.stringify(data), { method: 'POST', withCredentials: true }); + dep.ajax(`https://${domain}${EVENT_TRACKER_URL}`, undefined, JSON.stringify(data), { method: 'POST', withCredentials: true }); } } diff --git a/plugins/callerContext.js b/plugins/callerContext.js new file mode 100644 index 00000000000..73dc5a99358 --- /dev/null +++ b/plugins/callerContext.js @@ -0,0 +1,89 @@ +const {relPath, isInDirectory, TEST_DIR, getFreeName, getModuleName, PREBID_ROOT } = require('./utils.js'); +const t = require('@babel/core').types; +const fs = require('fs'); +const osPath = require('path'); + +const NAMES = { + 'src/ajax.js': { + names: ['ajax', 'ajaxBuilder', 'fetch', 'fetcherFactory'], + message: 'Request credentials may be unexpectedly denied. Consider using one of the "qualified" or "noCreds" variants of ajax / fetch instead.' + } +} + +const getCallers = (() => { + const cache = {}; + return function (filename, message) { + if (!cache.hasOwnProperty(filename)) { + const moduleName = getModuleName(osPath.resolve(PREBID_ROOT, filename)); + const metadataFile = osPath.resolve(__dirname, `../metadata/modules/${moduleName}.json`); + if (moduleName != null && fs.existsSync(metadataFile)) { + const metadata = JSON.parse(fs.readFileSync(metadataFile).toString()); + const callers = metadata.components.reduce((summary, {gvlid, componentName, componentType}) => { + summary.gvlids.add(gvlid) + summary.callers.push([componentType, componentName]) + return summary; + }, {gvlids: new Set(), callers: []}); + if (!callers.callers.length) { + throw new Error(`Unexpected empty component list from metadata file ${metadataFile}`); + } + if (callers.gvlids.size > 1) { + console.warn(`WARNING: more than one GVL ID is associated with '${filename}'. ${message}`) + } + cache[filename] = callers.callers; + } else { + console.warn(`WARNING: cannot determine moduleType/moduleName to associate with '${filename}'. If this is a new adapter it may need metadata to be updated. ${message}`) + cache[filename] = null; + } + } + return cache[filename]; + } +})(); + +module.exports = function (api, options) { + return { + visitor: { + ImportDeclaration(path, state) { + /** + * This replaces imports like: + * + * import {ajax} from 'src/ajax.js'; + * + * With: + * + * import {ajax as __ajax0} from 'src/ajax.js'; + * const ajax = __ajax0.withCallers([['bidder', 'example']]); + * + * Using the importer's filename and the 'metadata' folder to decide the argument passed to `withCallers`. + */ + + if (isInDirectory(state.filename, TEST_DIR)) return; + const relFilename = osPath.relative(PREBID_ROOT, state.filename); + if (path.node.source?.value?.endsWith('.ts')) { + throw new Error('callerContext must run after pbjsGlobals'); + } + if (path.node.source?.value) { + Object.entries(NAMES).forEach(([file, {names, message}]) => { + if (path.node.source.value === relPath(state.filename, file)) { + path.node.specifiers.forEach((specifier) => { + if (t.isImportNamespaceSpecifier(specifier)) { + console.warn(`WARNING: File '${relFilename}' imports * from '${file}. ${message}`) + return; + } + if (t.isImportSpecifier(specifier) && names.includes(specifier.imported.name)) { + const callers = getCallers(relFilename, message); + if (callers != null) { + const repl = getFreeName(path, `__${specifier.imported.name}`); + const node = api.parse(`const ${specifier.local.name} = ${repl}.withCallers(${JSON.stringify(callers)})`).program.body[0]; + path.insertAfter(node); + specifier.local.name = repl; + } + } + }) + } + }) + } + } + } + }; +}; + diff --git a/plugins/eslint/resolver.js b/plugins/eslint/resolver.js index f623ba877c3..81580c25623 100644 --- a/plugins/eslint/resolver.js +++ b/plugins/eslint/resolver.js @@ -1,20 +1,12 @@ const path = require('path'); const resolveFrom = require('resolve-from'); const fs = require('fs'); - -const TEST_DIR = path.resolve(__dirname, '../../test'); -const ROOT_DIR = path.resolve(__dirname, '../..'); +const {isInDirectory, TEST_DIR, PREBID_ROOT} = require('../utils.js'); const CODE_EXT = ['.ts', '.js', '.mjs'] -function isInDirectory(filename, dir) { - const rel = path.relative(dir, filename); - return rel && !rel.startsWith('..') && !path.isAbsolute(rel); -} - module.exports = { interfaceVersion: 2, - isInDirectory, CODE_EXT, resolve(source, file) { const {name, dir, ext} = path.parse(source); @@ -25,7 +17,7 @@ module.exports = { const candidates = fileNames.map(fn => [fileDir, fn]); if (isTest && !source.startsWith('.')) { // tests can do import like 'src/auction.js' - candidates.push(...fileNames.map(fn => [ROOT_DIR, `./${fn}`])) + candidates.push(...fileNames.map(fn => [PREBID_ROOT, `./${fn}`])) } const matching = Object.keys( candidates.reduce((matches, [from, path]) => { diff --git a/plugins/eslint/validateImports.js b/plugins/eslint/validateImports.js index 2fe3f444419..e2e3d82f0fd 100644 --- a/plugins/eslint/validateImports.js +++ b/plugins/eslint/validateImports.js @@ -1,7 +1,9 @@ const path = require('path'); const _ = require('lodash'); -const { CODE_EXT, isInDirectory } = require('./resolver.js'); +const { CODE_EXT } = require('./resolver.js'); +const { isInDirectory } = require('../utils.js'); + const MODULES_PATH = path.resolve(__dirname, '../../modules'); const CREATIVE_PATH = path.resolve(__dirname, '../../creative'); diff --git a/plugins/pbjsGlobals.js b/plugins/pbjsGlobals.js index 2986f578c25..7f4c87d4b1f 100644 --- a/plugins/pbjsGlobals.js +++ b/plugins/pbjsGlobals.js @@ -3,6 +3,7 @@ let prebid = require('../package.json'); const path = require('path'); const {buildOptions} = require('./buildOptions.js'); const FEATURES_GLOBAL = 'FEATURES'; +const {getModuleName, relPath, getFreeName} = require('./utils.js'); module.exports = function(api, options) { const {features, distUrlBase, skipCalls} = buildOptions(options); @@ -20,30 +21,6 @@ module.exports = function(api, options) { '$$REPO_AND_VERSION$$' ]; - const PREBID_ROOT = path.resolve(__dirname, '..'); - // on Windows, require paths are not filesystem paths - const SEP_PAT = new RegExp(path.sep.replace(/\\/g, '\\\\'), 'g') - - function relPath(from, toRelToProjectRoot) { - return path.relative(path.dirname(from), path.join(PREBID_ROOT, toRelToProjectRoot)).replace(SEP_PAT, '/'); - } - - function getModuleName(filename) { - const modPath = path.parse(path.relative(PREBID_ROOT, filename)); - if (!['.ts', '.js'].includes(modPath.ext.toLowerCase())) { - return null; - } - if (modPath.dir === 'modules') { - // modules/moduleName.js -> moduleName - return modPath.name; - } - if (modPath.name.toLowerCase() === 'index' && path.dirname(modPath.dir) === 'modules') { - // modules/moduleName/index.js -> moduleName - return path.basename(modPath.dir); - } - return null; - } - function translateToJs(path, state) { if (path.node.source?.value?.endsWith('.ts')) { path.node.source.value = path.node.source.value.replace(/\.ts$/, '.js'); @@ -62,11 +39,7 @@ module.exports = function(api, options) { const modName = getModuleName(state.filename); if (modName != null) { // append "registration" of module file to getGlobal().installedModules - let i = 0; - let registerName; - do { - registerName = `__r${i++}` - } while (path.scope.hasBinding(registerName)) + const registerName = getFreeName(path, '__r'); path.node.body.unshift(...api.parse(`import {registerModule as ${registerName}} from '${relPath(state.filename, 'src/prebidGlobal.js')}';`, {filename: state.filename}).program.body); path.node.body.push(...api.parse(`${registerName}('${modName}');`, {filename: state.filename}).program.body); } diff --git a/plugins/utils.js b/plugins/utils.js new file mode 100644 index 00000000000..7f8a9644679 --- /dev/null +++ b/plugins/utils.js @@ -0,0 +1,53 @@ +const path = require('path'); +const PREBID_ROOT = path.resolve(__dirname, '..'); +const TEST_DIR = path.resolve(__dirname, '../test'); + +function getModuleName(filename) { + const modPath = path.parse(path.relative(PREBID_ROOT, filename)); + if (!['.ts', '.js'].includes(modPath.ext.toLowerCase())) { + return null; + } + if (modPath.dir === 'modules') { + // modules/moduleName.js -> moduleName + return modPath.name; + } + if (modPath.name.toLowerCase() === 'index' && path.dirname(modPath.dir) === 'modules') { + // modules/moduleName/index.js -> moduleName + return path.basename(modPath.dir); + } + return null; +} + +// on Windows, require paths are not filesystem paths +const SEP_PAT = new RegExp(path.sep.replace(/\\/g, '\\\\'), 'g') + +function relPath(from, toRelToProjectRoot) { + let result = path.relative(path.dirname(from), path.join(PREBID_ROOT, toRelToProjectRoot)).replace(SEP_PAT, '/'); + if (!result.startsWith('.')) { + result = `./${result}` + } + return result; +} + +function isInDirectory(filename, dir) { + const rel = path.relative(dir, filename); + return rel && !rel.startsWith('..') && !path.isAbsolute(rel); +} + +function getFreeName(path, prefix = '__var') { + let i = 0; + let name; + do { + name = `${prefix}${i++}`; + } while (path.scope.hasBinding(name)); + return name; +} + +module.exports = { + PREBID_ROOT, + TEST_DIR, + getModuleName, + relPath, + isInDirectory, + getFreeName +}; diff --git a/src/adapterManager.ts b/src/adapterManager.ts index c2b301b6d07..22dc157a733 100644 --- a/src/adapterManager.ts +++ b/src/adapterManager.ts @@ -24,7 +24,7 @@ import { } from './utils.js'; import { decorateAdUnitsWithNativeParams, nativeAdapters } from './native.js'; import { newBidder } from './adapters/bidderFactory.js'; -import { ajaxBuilder } from './ajax.js'; +import { qualifiedAjaxBuilder } from './ajax.js'; import { config, RANDOM } from './config.js'; import { hook } from './hook.js'; import { @@ -742,10 +742,10 @@ const adapterManager = { _s2sConfigs.forEach((s2sConfig) => { if (s2sConfig && uniqueServerBidRequests[counter] && getS2SBidderSet(s2sConfig).has(uniqueServerBidRequests[counter].bidderCode)) { // s2s should get the same client side timeout as other client side requests. - const s2sAjax = ajaxBuilder(requestBidsTimeout, requestCallbacks ? { + const s2sAjax = qualifiedAjaxBuilder(MODULE_TYPE_PREBID, PBS_ADAPTER_NAME, requestBidsTimeout, requestCallbacks ? { request: requestCallbacks.request.bind(null, 's2s'), done: requestCallbacks.done - } : undefined, MODULE_TYPE_PREBID, PBS_ADAPTER_NAME); + } : undefined); const adaptersServerSide = s2sConfig.bidders; const s2sAdapter = _bidderRegistry[s2sConfig.adapter]; const uniquePbsTid = uniqueServerBidRequests[counter].uniquePbsTid; @@ -799,10 +799,10 @@ const adapterManager = { logMessage(`CALLING BIDDER`); events.emit(EVENTS.BID_REQUESTED, bidderRequest); }); - const ajax = ajaxBuilder(requestBidsTimeout, requestCallbacks ? { + const ajax = qualifiedAjaxBuilder(MODULE_TYPE_BIDDER, bidderRequest.bidderCode, requestBidsTimeout, requestCallbacks ? { request: requestCallbacks.request.bind(null, bidderRequest.bidderCode), done: requestCallbacks.done - } : undefined, MODULE_TYPE_BIDDER, bidderRequest.bidderCode); + } : undefined); const adapterDone = doneCb.bind(bidderRequest); try { config.runWithBidder( diff --git a/src/ajax.ts b/src/ajax.ts index 12fbb6f9bea..91c3f92a0cf 100644 --- a/src/ajax.ts +++ b/src/ajax.ts @@ -2,7 +2,8 @@ import { ACTIVITY_ACCESS_REQUEST_CREDENTIALS } from './activities/activities.js' import { activityParams } from './activities/activityParams.js'; import { isActivityAllowed } from './activities/rules.js'; import { config } from './config.js'; -import { buildUrl, hasDeviceAccess, logError, parseUrl } from './utils.js'; +import { buildUrl, logError, parseUrl } from './utils.js'; +import type { ModuleType } from "./activities/modules.ts"; export const dep = { fetch: window.fetch.bind(window), @@ -99,14 +100,52 @@ export function toFetchRequest(url, data, options: AjaxOptions = {}) { return dep.makeRequest(url, rqOpts); } +function callerContext(callers = []) { + const stack = [callers]; + return { + attach(fn, callers) { + return function (...args) { + stack.push(callers); + try { + return fn(...args); + } finally { + stack.pop(); + } + } + }, + getCallers() { + return stack[stack.length - 1]; + } + } +} + +function fixedCallerContext(moduleType, moduleName) { + return { + attach: (fn) => fn, + getCallers: () => [[moduleType, moduleName]] + } +} + /** * Return a version of `fetch` that automatically cancels requests after `timeout` milliseconds. * * If provided, `request` and `done` should be functions accepting a single argument. * `request` is invoked at the beginning of each request, and `done` at the end; both are passed its origin. - * */ export function fetcherFactory(timeout = 3000, { request, done }: any = {}, moduleType?: string, moduleName?: string): typeof window['fetch'] { + return fetcherFactoryImpl(callerContext(), timeout, { request, done }, moduleType, moduleName); +} +(fetcherFactory as any).withCallers = (callers) => { + // this is not intended to be used directly; see plugins/callerContext.js + return (...args) => { + return fetcherFactoryImpl(callerContext(callers), ...args); + } +} + +function fetcherFactoryImpl(context, timeout = 3000, { request, done }: any = {}, moduleType?: string, moduleName?: string): typeof window.fetch { + if (moduleName && moduleType) { + context = fixedCallerContext(moduleType, moduleName); + } let fetcher = (resource, options) => { let to; if (timeout != null && options?.signal == null && !config.getConfig('disableAjaxTimeout')) { @@ -117,9 +156,8 @@ export function fetcherFactory(timeout = 3000, { request, done }: any = {}, modu if ( request.credentials === 'include' && ( - !hasDeviceAccess() || ( - moduleType && moduleName && !isActivityAllowed(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, activityParams(moduleType, moduleName)) - ) + context.getCallers().length === 0 || + context.getCallers().some(([moduleType, moduleName]) => !isActivityAllowed(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, activityParams(moduleType, moduleName))) ) ) { request = dep.makeRequest(request, { @@ -141,6 +179,7 @@ export function fetcherFactory(timeout = 3000, { request, done }: any = {}, modu return req; })(fetcher); } + (fetcher as any).withCallers = (callers) => context.attach(fetcher, callers); return fetcher; } @@ -209,10 +248,22 @@ export type AjaxErrorCallback = (statusText: string, xhr: XHR) => void; export type AjaxCallback = AjaxSuccessCallback | { success?: AjaxErrorCallback; error?: AjaxSuccessCallback }; export function ajaxBuilder(timeout = 3000, { request, done } = {} as any, moduleType?: string, moduleName?: string) { - const fetcher = fetcherFactory(timeout, { request, done }, moduleType, moduleName); - return function (url: string, callback?: AjaxCallback, data?: unknown, options: AjaxOptions = {}) { + return ajaxBuilderImpl(callerContext(), timeout, { request, done }, moduleType, moduleName); +} +(ajaxBuilder as any).withCallers = (callers) => { + // this is not intended to be used directly; see plugins/callerContext.js + return (...args) => { + return ajaxBuilderImpl(callerContext(callers), ...args); + } +} + +function ajaxBuilderImpl(context, timeout = 3000, { request, done } = {} as any, moduleType?: string, moduleName?: string) { + const fetcher = fetcherFactoryImpl(context, timeout, { request, done }, moduleType, moduleName); + function ajax(url: string, callback?: AjaxCallback, data?: unknown, options: AjaxOptions = {}) { attachCallbacks(fetcher(toFetchRequest(url, data, options)), callback); - }; + } + (ajax as any).withCallers = (callers) => context.attach(ajax, callers); + return ajax; } /** @@ -229,7 +280,38 @@ export function sendBeacon(url, data) { return window.navigator.sendBeacon(url, data); } +function requireNames(fn: T) { + return function (moduleType: ModuleType, moduleName: string, timeout?: number, requestCallbacks?): ReturnType { + if (!moduleType || !moduleName) { + throw new Error('moduleType and moduleName are required'); + } + return (fn as any)(timeout, requestCallbacks, moduleType, moduleName); + }; +} + +/** + * A version of ajaxBuilder that requires an explicit moduleType and moduleName. + */ +export const qualifiedAjaxBuilder = requireNames(ajaxBuilder); +/** + * A version of fetcherFactory that requires an explicit moduleType and moduleName. + */ +export const qualifiedFetcherFactory = requireNames(fetcherFactory); + export const ajax = ajaxBuilder(); export const fetch = fetcherFactory(); +// the difference between 'noCredsAjax'/'noCredsFetch' and 'ajax'/'fetch' is that the latter two (together with +// ajaxBuilder and fetcherFactory) are automatically decorated with moduleType/moduleName at build time - +// see plugins/callerContext.js + +/** + * A version of `ajax` that will never include request credentials (withCredentials = false). + */ +export const noCredsAjax = ajax; +/** + * A version of `fetch` that will never include request credentials (credentials = 'same-origin'). + */ +export const noCredsFetch = fetch; + export type Ajax = typeof ajax; diff --git a/src/videoCache.ts b/src/videoCache.ts index 248ad600f01..9442d89975e 100644 --- a/src/videoCache.ts +++ b/src/videoCache.ts @@ -9,7 +9,7 @@ * This trickery helps integrate with ad servers, which set character limits on request params. */ -import { ajaxBuilder } from './ajax.js'; +import { qualifiedAjaxBuilder } from './ajax.js'; import { config } from './config.js'; import { auctionManager } from './auctionManager.js'; import { generateUUID, logError, logWarn } from './utils.js'; @@ -17,6 +17,7 @@ import { addBidToAuction } from './auction.js'; import { hook } from './hook.js'; import { OUTSTREAM } from './video.js'; import type { AudioBidResponse, VideoBid, VideoBidResponse } from "./bidfactory.ts"; +import { MODULE_TYPE_PREBID } from "./activities/modules.ts"; /** * Might be useful to be configurable in the future @@ -226,7 +227,7 @@ function shimStorageCallback(done: VideoCacheStoreCallback) { * @param getAjax * the data has been stored in the cache. */ -export function store(bids: VideoBid[], done?: VideoCacheStoreCallback, getAjax = ajaxBuilder) { +export function store(bids: VideoBid[], done?: VideoCacheStoreCallback, getAjax = (timeout) => qualifiedAjaxBuilder(MODULE_TYPE_PREBID, 'cache', timeout)) { const requestData = { puts: bids.map(bid => toStorageRequest(bid)) }; diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index baa94b44b02..fd11f0e166b 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -1083,7 +1083,7 @@ describe('auctionmanager.js', function () { describe('when auction timeout is 3000', function () { beforeEach(function () { - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockAjaxBuilder); adUnits = [{ mediaTypes: { banner: { @@ -1655,7 +1655,7 @@ describe('auctionmanager.js', function () { ]; const makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); makeRequestsStub.returns(bidRequests); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockAjaxBuilder); createAuctionStub = sinon.stub(auctionModule, 'newAuction'); createAuctionStub.returns(auction); indexAuctions = [auction]; @@ -1817,7 +1817,7 @@ describe('auctionmanager.js', function () { const makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); makeRequestsStub.returns(bidRequests); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockAjaxBuilder); spec = mockBidder(BIDDER_CODE, bids); spec1 = mockBidder(BIDDER_CODE1, bids1); @@ -1857,7 +1857,7 @@ describe('auctionmanager.js', function () { beforeEach(function () { makeRequestsStub = sinon.stub(adapterManager, 'makeBidRequests'); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockAjaxBuilder); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockAjaxBuilder); const adUnits = [{ code: ADUNIT_CODE, diff --git a/test/spec/modules/adelerateBidAdapter_spec.js b/test/spec/modules/adelerateBidAdapter_spec.js index a439ede88a1..1c5b0084735 100644 --- a/test/spec/modules/adelerateBidAdapter_spec.js +++ b/test/spec/modules/adelerateBidAdapter_spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import { spec } from 'modules/adelerateBidAdapter.js'; +import { dep, spec } from 'modules/adelerateBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; import { deepClone } from 'src/utils.js'; @@ -769,7 +769,7 @@ describe('AdelerateBidAdapter', function () { let ajaxStub; beforeEach(function () { - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { @@ -799,7 +799,7 @@ describe('AdelerateBidAdapter', function () { let ajaxStub; beforeEach(function () { - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { @@ -833,7 +833,7 @@ describe('AdelerateBidAdapter', function () { let ajaxStub; beforeEach(function () { - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { diff --git a/test/spec/modules/asterioBidAdapter_spec.js b/test/spec/modules/asterioBidAdapter_spec.js index c45ef42dd5b..6df402b31d6 100644 --- a/test/spec/modules/asterioBidAdapter_spec.js +++ b/test/spec/modules/asterioBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import * as ajaxModule from 'src/ajax.js'; -import { ENDPOINT, spec } from 'modules/asterioBidAdapter.js'; +import { dep, ENDPOINT, spec } from 'modules/asterioBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; const REQUEST = { @@ -230,7 +229,7 @@ describe('asterioBidAdapter', function () { let ajaxStub; beforeEach(function () { - ajaxStub = sinon.stub(ajaxModule, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { diff --git a/test/spec/modules/colombiaBidAdapter_spec.js b/test/spec/modules/colombiaBidAdapter_spec.js index ce6d8a7e6b0..9da750d9256 100644 --- a/test/spec/modules/colombiaBidAdapter_spec.js +++ b/test/spec/modules/colombiaBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; -import { spec } from 'modules/colombiaBidAdapter'; +import { dep, spec } from 'modules/colombiaBidAdapter'; import { newBidder } from 'src/adapters/bidderFactory'; -import * as ajaxLib from 'src/ajax.js'; const HOST_NAME = document.location.protocol + '//' + window.location.host; const ENDPOINT = 'https://ade.clmbtech.com/cde/prebid.htm'; @@ -155,7 +154,7 @@ describe('colombiaBidAdapter', function () { describe('onBidWon', function () { let ajaxStub; beforeEach(() => { - ajaxStub = sinon.stub(ajaxLib, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(() => { @@ -198,7 +197,7 @@ describe('colombiaBidAdapter', function () { let ajaxStub; beforeEach(function () { - ajaxStub = sinon.stub(ajaxLib, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { diff --git a/test/spec/modules/connatixBidAdapter_spec.js b/test/spec/modules/connatixBidAdapter_spec.js index 8f1ab52b9b1..69d88a95cc4 100644 --- a/test/spec/modules/connatixBidAdapter_spec.js +++ b/test/spec/modules/connatixBidAdapter_spec.js @@ -10,11 +10,10 @@ import { readFromLocalStorage as connatixReadFromLocalStorage, saveInLocalStorage as connatixSaveInLocalStorage, spec, - storage + storage, dep } from '../../../modules/connatixBidAdapter.js'; import adapterManager from '../../../src/adapterManager.js'; import * as utils from '../../../src/utils.js'; -import * as ajax from '../../../src/ajax.js'; import { BANNER, VIDEO } from '../../../src/mediaTypes.js'; import * as winDimensions from '../../../src/utils/winDimensions.js'; import * as adUnits from 'src/utils/adUnits'; @@ -420,7 +419,7 @@ describe('connatixBidAdapter', function () { let ajaxStub; beforeEach(() => { - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(() => { diff --git a/test/spec/modules/contxtfulBidAdapter_spec.js b/test/spec/modules/contxtfulBidAdapter_spec.js index 8217a9f2eeb..f15f42cf243 100644 --- a/test/spec/modules/contxtfulBidAdapter_spec.js +++ b/test/spec/modules/contxtfulBidAdapter_spec.js @@ -1,4 +1,4 @@ -import { spec, safeStringify } from 'modules/contxtfulBidAdapter.js'; +import { spec, safeStringify, dep } from 'modules/contxtfulBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { config } from 'src/config.js'; import * as ajax from 'src/ajax.js'; @@ -914,7 +914,7 @@ describe('contxtful bid adapter', function () { }); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(true); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); expect(spec.onTimeout({ 'customData': 'customvalue' })).to.not.throw; expect(beaconStub.called).to.be.true; expect(ajaxStub.called).to.be.false; @@ -925,7 +925,7 @@ describe('contxtful bid adapter', function () { contxtful: { customer: CUSTOMER, version: VERSION }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); expect(spec.onTimeout({ 'customData': 'customvalue' })).to.not.throw; expect(beaconStub.called).to.be.true; @@ -940,7 +940,7 @@ describe('contxtful bid adapter', function () { contxtful: { customer: CUSTOMER, version: VERSION }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); spec.onBidderError({ 'customData': 'customvalue' }); expect(ajaxStub.calledOnce).to.be.true; @@ -954,7 +954,7 @@ describe('contxtful bid adapter', function () { contxtful: { customer: CUSTOMER, version: VERSION }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); spec.onBidWon({ 'customData': 'customvalue' }); expect(ajaxStub.calledOnce).to.be.true; @@ -966,7 +966,7 @@ describe('contxtful bid adapter', function () { contxtful: { customer: CUSTOMER, version: VERSION }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); const payload = { adata: "hello" @@ -983,7 +983,7 @@ describe('contxtful bid adapter', function () { config.setConfig({ contxtful: { customer: CUSTOMER, version: VERSION, sampling: { onBidBillable: 1.0 } }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); spec.onBidBillable({ 'customData': 'customvalue' }); expect(ajaxStub.calledOnce).to.be.true; @@ -996,7 +996,7 @@ describe('contxtful bid adapter', function () { config.setConfig({ contxtful: { customer: CUSTOMER, version: VERSION, sampling: { onAdRenderSucceeded: 1.0 } }, }); - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); const beaconStub = sandbox.stub(ajax, 'sendBeacon').returns(false); spec.onAdRenderSucceeded({ 'customData': 'customvalue' }); expect(ajaxStub.calledOnce).to.be.true; diff --git a/test/spec/modules/criteoBidAdapter_spec.js b/test/spec/modules/criteoBidAdapter_spec.js index e5deed2db84..61b5e0cbaf2 100644 --- a/test/spec/modules/criteoBidAdapter_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1,8 +1,7 @@ import { expect } from 'chai'; -import { spec, storage } from 'modules/criteoBidAdapter.js'; +import { dep, spec, storage } from 'modules/criteoBidAdapter.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 { addFPDToBidderRequest } from '../../helpers/fpd.js'; @@ -27,7 +26,7 @@ describe('The Criteo bidding adapter', function () { localStorage.removeItem('criteo_fast_bid'); sandbox = sinon.createSandbox(); logWarnStub = sandbox.stub(utils, 'logWarn'); - ajaxStub = sandbox.stub(ajax, 'ajax'); + ajaxStub = sandbox.stub(dep, 'ajax'); }); afterEach(function () { diff --git a/test/spec/modules/datamageRtdProvider_spec.js b/test/spec/modules/datamageRtdProvider_spec.js index fddb448b978..e52611c92bc 100644 --- a/test/spec/modules/datamageRtdProvider_spec.js +++ b/test/spec/modules/datamageRtdProvider_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { datamageRtdSubmodule } from 'modules/datamageRtdProvider.js'; -import * as ajaxUtils from 'src/ajax.js'; +import { datamageRtdSubmodule, dep } from 'modules/datamageRtdProvider.js'; import * as utils from 'src/utils.js'; describe('datamageRtdSubmodule (DataMage RTD Provider)', function () { @@ -64,7 +63,7 @@ describe('datamageRtdSubmodule (DataMage RTD Provider)', function () { }; // Stub Prebid's internal ajaxBuilder - ajaxBuilderStub = sandbox.stub(ajaxUtils, 'ajaxBuilder'); + ajaxBuilderStub = sandbox.stub(dep, 'ajaxBuilder'); // Keep tests deterministic + allow port-strip assertion btoaStub = sandbox.stub(window, 'btoa').callsFake((s) => `b64(${s})`); diff --git a/test/spec/modules/goldbachBidAdapter_spec.js b/test/spec/modules/goldbachBidAdapter_spec.js index caf0efec2ec..041fb643aff 100644 --- a/test/spec/modules/goldbachBidAdapter_spec.js +++ b/test/spec/modules/goldbachBidAdapter_spec.js @@ -1,12 +1,11 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { spec, storage } from 'modules/goldbachBidAdapter.js'; +import { dep, spec, storage } from 'modules/goldbachBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { deepClone } from 'src/utils.js'; -import { BANNER, VIDEO, NATIVE } from 'src/mediaTypes.js'; +import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; import { OUTSTREAM } from 'src/video.js'; import { addFPDToBidderRequest } from '../../helpers/fpd.js'; -import * as ajaxLib from 'src/ajax.js'; const BIDDER_NAME = 'goldbach' const ENDPOINT = 'https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction'; @@ -276,7 +275,7 @@ describe('GoldbachBidAdapter', function () { beforeEach(() => { sandbox = sinon.createSandbox(); - ajaxStub = sandbox.stub(ajaxLib, 'ajax'); + ajaxStub = sandbox.stub(dep, 'ajax'); sandbox.stub(Math, 'random').returns(0); }); diff --git a/test/spec/modules/insuradsRtdProvider_spec.js b/test/spec/modules/insuradsRtdProvider_spec.js index 92a0d68c52b..deba4377314 100644 --- a/test/spec/modules/insuradsRtdProvider_spec.js +++ b/test/spec/modules/insuradsRtdProvider_spec.js @@ -1,5 +1,4 @@ -import { insuradsRtdProvider } from 'modules/insuradsRtdProvider.js'; -import * as ajax from 'src/ajax.js'; +import { dep, insuradsRtdProvider } from 'modules/insuradsRtdProvider.js'; import { config } from 'src/config.js'; const sampleConfig = { @@ -21,7 +20,7 @@ describe('insuradsRtdProvider', function () { beforeEach(function () { config.resetConfig(); - fetchStub = sinon.stub(ajax, 'fetch'); + fetchStub = sinon.stub(dep, 'fetch'); }); afterEach(function () { diff --git a/test/spec/modules/kinessoIdSystem_spec.js b/test/spec/modules/kinessoIdSystem_spec.js index fab5ec781a6..c2dac3e85de 100644 --- a/test/spec/modules/kinessoIdSystem_spec.js +++ b/test/spec/modules/kinessoIdSystem_spec.js @@ -1,9 +1,8 @@ import sinon from 'sinon'; import { attachIdSystem } from '../../../modules/userId/index.js'; -import { kinessoIdSubmodule } from '../../../modules/kinessoIdSystem.js'; +import { dep, kinessoIdSubmodule } from '../../../modules/kinessoIdSystem.js'; import { createEidsArray } from '../../../modules/userId/eids.js'; import * as utils from '../../../src/utils.js'; -import * as ajaxLib from '../../../src/ajax.js'; import { expect } from 'chai/index.mjs'; describe('kinesso ID', () => { @@ -64,7 +63,7 @@ describe('kinesso ID', () => { sandbox = sinon.createSandbox(); sandbox.stub(utils, 'logError'); sandbox.stub(utils, 'logInfo'); - ajaxStub = sandbox.stub(ajaxLib, 'ajax'); + ajaxStub = sandbox.stub(dep, 'ajax'); }); afterEach(() => { diff --git a/test/spec/modules/locIdSystem_spec.js b/test/spec/modules/locIdSystem_spec.js index 1b2fc02ddc8..dbdf5a41cd3 100644 --- a/test/spec/modules/locIdSystem_spec.js +++ b/test/spec/modules/locIdSystem_spec.js @@ -3,12 +3,11 @@ * http://www.apache.org/licenses/LICENSE-2.0 */ -import { locIdSubmodule, storage } from 'modules/locIdSystem.js'; +import { dep, locIdSubmodule, storage } from 'modules/locIdSystem.js'; import { createEidsArray } from 'modules/userId/eids.js'; import { attachIdSystem } from 'modules/userId/index.js'; -import * as ajax from 'src/ajax.js'; import { VENDORLESS_GVLID } from 'src/consentHandler.js'; -import { uspDataHandler, gppDataHandler } from 'src/adapterManager.js'; +import { gppDataHandler, uspDataHandler } from 'src/adapterManager.js'; import { expect } from 'chai/index.mjs'; import sinon from 'sinon'; @@ -28,7 +27,7 @@ describe('LocID System', () => { sandbox.stub(storage, 'getDataFromLocalStorage').returns(null); sandbox.stub(storage, 'setDataInLocalStorage'); ajaxStub = sandbox.stub(); - ajaxBuilderStub = sandbox.stub(ajax, 'ajaxBuilder').returns(ajaxStub); + ajaxBuilderStub = sandbox.stub(dep, 'ajaxBuilder').returns(ajaxStub); }); afterEach(() => { diff --git a/test/spec/modules/luceadBidAdapter_spec.js b/test/spec/modules/luceadBidAdapter_spec.js index 71087fbdcb3..f92698b6565 100755 --- a/test/spec/modules/luceadBidAdapter_spec.js +++ b/test/spec/modules/luceadBidAdapter_spec.js @@ -1,8 +1,7 @@ import { expect } from 'chai'; -import { spec } from 'modules/luceadBidAdapter.js'; +import { dep, spec } from 'modules/luceadBidAdapter.js'; import sinon from 'sinon'; import { newBidder } from 'src/adapters/bidderFactory.js'; -import * as ajax from 'src/ajax.js'; describe('Lucead Adapter', () => { describe('inherited functions', function () { @@ -48,11 +47,11 @@ describe('Lucead Adapter', () => { }); it('should trigger impression pixel', function () { - sandbox.spy(ajax, 'fetch'); + sandbox.spy(dep, 'fetch'); for (const bid of bids) { spec.onBidWon(bid); - expect(ajax?.fetch?.args[0][0]).to.match(/report\/impression$/); + expect(dep?.fetch?.args[0][0]).to.match(/report\/impression$/); } }); diff --git a/test/spec/modules/merkleIdSystem_spec.js b/test/spec/modules/merkleIdSystem_spec.js index cf307b76117..a78733b17f9 100644 --- a/test/spec/modules/merkleIdSystem_spec.js +++ b/test/spec/modules/merkleIdSystem_spec.js @@ -86,7 +86,7 @@ describe('Merkle System', function () { sinon.stub(utils, 'logWarn'); sinon.stub(utils, 'logError'); callbackSpy.resetHistory(); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockResponse(JSON.stringify(MOCK_RESPONSE))); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockResponse(JSON.stringify(MOCK_RESPONSE))); }); afterEach(function () { @@ -176,7 +176,7 @@ describe('Merkle System', function () { sinon.stub(utils, 'logWarn'); sinon.stub(utils, 'logError'); callbackSpy.resetHistory(); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(mockResponse(JSON.stringify(MOCK_RESPONSE))); + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(mockResponse(JSON.stringify(MOCK_RESPONSE))); }); afterEach(function () { diff --git a/test/spec/modules/mileBidAdapter_spec.js b/test/spec/modules/mileBidAdapter_spec.js index cac8ea41a10..70c562c92b1 100644 --- a/test/spec/modules/mileBidAdapter_spec.js +++ b/test/spec/modules/mileBidAdapter_spec.js @@ -1,8 +1,6 @@ import { expect } from 'chai'; -import { spec, siteIdTracker, publisherIdTracker } from 'modules/mileBidAdapter.js'; +import { dep, spec } from 'modules/mileBidAdapter.js'; import { BANNER } from 'src/mediaTypes.js'; -import * as ajax from 'src/ajax.js'; -import * as utils from 'src/utils.js'; describe('mileBidAdapter', function () { describe('isBidRequestValid', function () { @@ -567,7 +565,7 @@ describe('mileBidAdapter', function () { } }; - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { @@ -646,7 +644,7 @@ describe('mileBidAdapter', function () { } ]; - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(function () { diff --git a/test/spec/modules/mobianRtdProvider_spec.js b/test/spec/modules/mobianRtdProvider_spec.js index 72b61192835..f34c3b6eb94 100644 --- a/test/spec/modules/mobianRtdProvider_spec.js +++ b/test/spec/modules/mobianRtdProvider_spec.js @@ -22,7 +22,7 @@ import { makeMemoizedFetch, makeContextDataToKeyValuesReducer, makeDataFromResponse, - setTargeting, + setTargeting, dep, } from 'modules/mobianRtdProvider.js'; describe('Mobian RTD Submodule', function () { @@ -102,7 +102,7 @@ describe('Mobian RTD Submodule', function () { describe('fetchContextData', function () { it('should return fetched context data', async function () { - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function(url, callbacks) { callbacks.success(mockResponse); }); @@ -120,7 +120,7 @@ describe('Mobian RTD Submodule', function () { describe('getContextData', function () { it('should return formatted context data', async function () { - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function(url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function(url, callbacks) { callbacks.success(mockResponse); }); @@ -320,7 +320,7 @@ describe('Mobian RTD Submodule', function () { it('should evict the oldest entry when cache exceeds maxSize', async function () { const maxSize = 2; let fetchCount = 0; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; callbacks.success(mockResponse); }); @@ -357,7 +357,7 @@ describe('Mobian RTD Submodule', function () { it('should fall back to MAX_CACHE_SIZE when given an invalid maxSize', async function () { let fetchCount = 0; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; callbacks.success(mockResponse); }); @@ -394,7 +394,7 @@ describe('Mobian RTD Submodule', function () { it('should floor fractional maxSize to an integer', async function () { let fetchCount = 0; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; callbacks.success(mockResponse); }); @@ -420,7 +420,7 @@ describe('Mobian RTD Submodule', function () { it('should share a single in-flight request for concurrent calls to the same URL', async function () { let fetchCount = 0; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; setTimeout(() => callbacks.success(mockResponse), 10); }); @@ -440,7 +440,7 @@ describe('Mobian RTD Submodule', function () { it('should delete failed cache entries so subsequent calls refetch after an error', async function () { let fetchCount = 0; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; callbacks.error(new Error('network error')); }); @@ -460,7 +460,7 @@ describe('Mobian RTD Submodule', function () { let fetchCount = 0; let shouldError = true; - ajaxStub = sinon.stub(ajax, 'ajaxBuilder').returns(function (url, callbacks) { + ajaxStub = sinon.stub(dep, 'ajaxBuilder').returns(function (url, callbacks) { fetchCount++; if (shouldError) { setTimeout(() => callbacks.error(new Error('server error')), 10); diff --git a/test/spec/modules/nativeryBidAdapter_spec.js b/test/spec/modules/nativeryBidAdapter_spec.js index 3aa4b90cba2..5b1eb846b82 100644 --- a/test/spec/modules/nativeryBidAdapter_spec.js +++ b/test/spec/modules/nativeryBidAdapter_spec.js @@ -1,8 +1,7 @@ import { expect } from 'chai'; -import { spec, converter } from 'modules/nativeryBidAdapter'; +import { converter, dep, spec } from 'modules/nativeryBidAdapter'; import { newBidder } from 'src/adapters/bidderFactory.js'; import * as utils from 'src/utils.js'; -import * as ajax from 'src/ajax.js'; const ENDPOINT = 'https://hb.nativery.com/openrtb2/auction'; const MAX_IMPS_PER_REQUEST = 10; @@ -199,14 +198,14 @@ describe('NativeryAdapter', function () { expect(spec.onBidWon).to.exist.and.to.be.a('function'); }); it('should NOT call ajax when invalid or empty data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); spec.onBidWon(null); spec.onBidWon({}); spec.onBidWon(undefined); expect(ajaxStub.called).to.be.false; }); it('should call ajax with correct payload when valid data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); const validData = { bidder: 'nativery', adUnitCode: 'div-1' }; spec.onBidWon(validData); assertTrackEvent(ajaxStub, 'NAT_BID_WON', validData) @@ -218,14 +217,14 @@ describe('NativeryAdapter', function () { expect(spec.onAdRenderSucceeded).to.exist.and.to.be.a('function'); }); it('should NOT call ajax when invalid or empty data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); spec.onAdRenderSucceeded(null); spec.onAdRenderSucceeded({}); spec.onAdRenderSucceeded(undefined); expect(ajaxStub.called).to.be.false; }); it('should call ajax with correct payload when valid data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); const validData = { bidder: 'nativery', adUnitCode: 'div-1' }; spec.onAdRenderSucceeded(validData); assertTrackEvent(ajaxStub, 'NAT_AD_RENDERED', validData) @@ -237,7 +236,7 @@ describe('NativeryAdapter', function () { expect(spec.onTimeout).to.exist.and.to.be.a('function'); }); it('should NOT call ajax when invalid or empty data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); spec.onTimeout(null); spec.onTimeout({}); spec.onTimeout([]); @@ -245,7 +244,7 @@ describe('NativeryAdapter', function () { expect(ajaxStub.called).to.be.false; }); it('should call ajax with correct payload when valid data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); const validData = [{ bidder: 'nativery', adUnitCode: 'div-1' }]; spec.onTimeout(validData); assertTrackEvent(ajaxStub, 'NAT_TIMEOUT', validData) @@ -257,14 +256,14 @@ describe('NativeryAdapter', function () { expect(spec.onBidderError).to.exist.and.to.be.a('function'); }); it('should NOT call ajax when invalid or empty data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); spec.onBidderError(null); spec.onBidderError({}); spec.onBidderError(undefined); expect(ajaxStub.called).to.be.false; }); it('should call ajax with correct payload when valid data is provided', () => { - const ajaxStub = sandBox.stub(ajax, 'ajax'); + const ajaxStub = sandBox.stub(dep, 'ajax'); const validData = { error: 'error', bidderRequest: { diff --git a/test/spec/modules/naveggIdSystem_spec.js b/test/spec/modules/naveggIdSystem_spec.js index 2d4db3218b8..9ccfad6fd52 100644 --- a/test/spec/modules/naveggIdSystem_spec.js +++ b/test/spec/modules/naveggIdSystem_spec.js @@ -1,5 +1,4 @@ -import { naveggIdSubmodule, storage } from 'modules/naveggIdSystem.js'; -import * as ajaxLib from 'src/ajax.js'; +import { dep, naveggIdSubmodule, storage } from 'modules/naveggIdSystem.js'; const NAVEGGID_CONFIG_COOKIE_HTML5 = { storage: { @@ -44,7 +43,7 @@ describe('getId', function () { beforeEach(function() { ajaxStub = sinon.stub(); - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns(ajaxStub); + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns(ajaxStub); }); afterEach(function() { diff --git a/test/spec/modules/performaxBidAdapter_spec.js b/test/spec/modules/performaxBidAdapter_spec.js index f26024eb47d..0f0b0295f04 100644 --- a/test/spec/modules/performaxBidAdapter_spec.js +++ b/test/spec/modules/performaxBidAdapter_spec.js @@ -1,7 +1,6 @@ import { expect } from 'chai'; -import { spec, converter, storeData, readData, storage, resetUserSyncsInit } from 'modules/performaxBidAdapter.js'; +import { converter, dep, readData, resetUserSyncsInit, spec, storage, storeData } from 'modules/performaxBidAdapter.js'; import * as utils from '../../../src/utils.js'; -import * as ajax from 'src/ajax.js'; import sinon from 'sinon'; describe('Performax adapter', function () { @@ -362,7 +361,7 @@ describe('Performax adapter', function () { let randomStub; beforeEach(() => { - ajaxStub = sinon.stub(ajax, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); randomStub = sinon.stub(Math, 'random').returns(0); }); diff --git a/test/spec/modules/pgamdirectAnalyticsAdapter_spec.js b/test/spec/modules/pgamdirectAnalyticsAdapter_spec.js index 635015d9d96..122c3d6ac6a 100644 --- a/test/spec/modules/pgamdirectAnalyticsAdapter_spec.js +++ b/test/spec/modules/pgamdirectAnalyticsAdapter_spec.js @@ -2,8 +2,7 @@ import { expect } from 'chai'; import sinon from 'sinon'; import adapterManager from 'src/adapterManager.js'; import { EVENTS } from 'src/constants.js'; -import * as ajaxLib from 'src/ajax.js'; -import pgamdirectAnalytics, { normalise, maybePostAuctionContext } from 'modules/pgamdirectAnalyticsAdapter.js'; +import pgamdirectAnalytics, { dep, maybePostAuctionContext, normalise } from 'modules/pgamdirectAnalyticsAdapter.js'; /** * Spec for modules/pgamdirectAnalyticsAdapter.ts. @@ -207,7 +206,7 @@ describe('pgamdirect Analytics Adapter', () => { describe('maybePostAuctionContext', () => { let ajaxStub; beforeEach(() => { - ajaxStub = sinon.stub(ajaxLib, 'ajax'); + ajaxStub = sinon.stub(dep, 'ajax'); }); afterEach(() => { ajaxStub.restore(); diff --git a/test/spec/modules/r2b2AnalytiscAdapter_spec.js b/test/spec/modules/r2b2AnalytiscAdapter_spec.js index db34531f88d..d2a83f8bfdb 100644 --- a/test/spec/modules/r2b2AnalytiscAdapter_spec.js +++ b/test/spec/modules/r2b2AnalytiscAdapter_spec.js @@ -1,12 +1,11 @@ -import r2b2Analytics, { resetAnalyticAdapter } from '../../../modules/r2b2AnalyticsAdapter.js'; +import r2b2Analytics, { dep, resetAnalyticAdapter } from '../../../modules/r2b2AnalyticsAdapter.js'; import { expect } from 'chai'; -import { EVENTS, AD_RENDER_FAILED_REASON, REJECTION_REASON } from 'src/constants.js'; +import { AD_RENDER_FAILED_REASON, EVENTS, REJECTION_REASON } from 'src/constants.js'; import * as pbEvents from 'src/events.js'; -import * as ajax from 'src/ajax.js'; import * as utils from 'src/utils'; -import { getGlobal } from 'src/prebidGlobal'; import * as prebidGlobal from 'src/prebidGlobal'; + const adapterManager = require('src/adapterManager').default; const { @@ -371,7 +370,7 @@ describe('r2b2 Analytics', function () { getGlobalStub = sandbox.stub(prebidGlobal, 'getGlobal').returns({ getHighestCpmBids: () => [R2B2_AD_UNIT_2_BID] }); - ajaxStub = sandbox.stub(ajax, 'ajax'); + ajaxStub = sandbox.stub(dep, 'ajax'); adapterManager.registerAnalyticsAdapter({ code: 'r2b2', diff --git a/test/spec/modules/tadvertisingBidAdapter_spec.js b/test/spec/modules/tadvertisingBidAdapter_spec.js index 3bbd58699c6..9969e862ccf 100644 --- a/test/spec/modules/tadvertisingBidAdapter_spec.js +++ b/test/spec/modules/tadvertisingBidAdapter_spec.js @@ -1,14 +1,14 @@ import { expect } from 'chai'; import { - spec, - buildSuccessNotification, buildErrorNotification, + buildSuccessNotification, buildTimeoutNotification, + dep, + getBidFloor, sendNotification, - getBidFloor + spec } from 'modules/tadvertisingBidAdapter'; import * as utils from '../../../src/utils.js'; -import * as ajax from '../../../src/ajax.js'; import sinon from 'sinon'; describe('tadvertisingBidAdapter', () => { @@ -729,8 +729,8 @@ describe('tadvertisingBidAdapter', () => { beforeEach(function() { spec.notify_url = 'https://test.com/notify'; - sendBeaconStub = sinon.stub(ajax, 'sendBeacon'); - ajaxStub = sinon.stub(ajax, 'ajax'); + sendBeaconStub = sinon.stub(dep, 'sendBeacon'); + ajaxStub = sinon.stub(dep, 'ajax'); logErrorStub = sinon.stub(utils, 'logError'); }); diff --git a/test/spec/modules/timeoutRtdProvider_spec.js b/test/spec/modules/timeoutRtdProvider_spec.js index fd21f39b23e..b60f647e83f 100644 --- a/test/spec/modules/timeoutRtdProvider_spec.js +++ b/test/spec/modules/timeoutRtdProvider_spec.js @@ -22,7 +22,7 @@ describe('Timeout RTD submodule', () => { const ajaxStub = sandbox.stub().callsFake(function (url, callbackObj) { callbackObj.success(response); }); - sandbox.stub(ajax, 'ajaxBuilder').callsFake(function () { return ajaxStub }); + sandbox.stub(ajax, 'qualifiedAjaxBuilder').callsFake(function () { return ajaxStub }); const reqBidsConfigObj = {} const expectedLink = 'https://somelink.json' @@ -43,7 +43,7 @@ describe('Timeout RTD submodule', () => { it('should make a request to the endpoint url and ignore the rules object if the endpoint is provided', () => { const ajaxStub = sandbox.stub().callsFake((url, callbackObj) => {}); - sandbox.stub(ajax, 'ajaxBuilder').callsFake(() => ajaxStub); + sandbox.stub(ajax, 'qualifiedAjaxBuilder').callsFake(() => ajaxStub); const expectedLink = 'https://somelink.json' const config = { 'name': 'timeout', @@ -82,7 +82,7 @@ describe('Timeout RTD submodule', () => { it('should exit quietly if no relevant timeout config is found', () => { const callback = sandbox.stub() const ajaxStub = sandbox.stub().callsFake((url, callbackObj) => {}); - sandbox.stub(ajax, 'ajaxBuilder').callsFake(function() { return ajaxStub }); + sandbox.stub(ajax, 'qualifiedAjaxBuilder').callsFake(function() { return ajaxStub }); const handleTimeoutIncrementStub = sandbox.stub(timeoutRtdFunctions, 'handleTimeoutIncrement'); timeoutSubmodule.getBidRequestData({}, callback, {}); diff --git a/test/spec/modules/wurflRtdProvider_spec.js b/test/spec/modules/wurflRtdProvider_spec.js index 16a83fc24d9..26cd75ec92f 100644 --- a/test/spec/modules/wurflRtdProvider_spec.js +++ b/test/spec/modules/wurflRtdProvider_spec.js @@ -1,9 +1,9 @@ import { wurflSubmodule, storage, - __testing__ + __testing__, + dep } from 'modules/wurflRtdProvider'; -import * as ajaxModule from 'src/ajax'; import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; import * as prebidGlobalModule from 'src/prebidGlobal.js'; import { guardOrtb2Fragments } from 'libraries/objectGuard/ortbGuard.js'; @@ -388,7 +388,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -435,7 +435,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -533,7 +533,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] }); @@ -575,7 +575,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] }); @@ -624,7 +624,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] }); @@ -677,7 +677,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] }); @@ -1608,8 +1608,8 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(false); - const fetchAjaxStub = sandbox.stub(ajaxModule, 'fetch').returns(Promise.resolve()); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(false); + const fetchAjaxStub = sandbox.stub(dep, 'fetch').returns(Promise.resolve()); // Mock getGlobal().getHighestCpmBids() const mockHighestCpmBids = [ @@ -1691,7 +1691,7 @@ describe('wurflRtdProvider', function () { }); const testConsentClass = (description, userConsent, expectedClass, done) => { - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); const callback = () => { const auctionDetails = { @@ -1846,8 +1846,8 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon'); - const fetchStub = sandbox.stub(ajaxModule, 'fetch').returns(Promise.resolve()); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon'); + const fetchStub = sandbox.stub(dep, 'fetch').returns(Promise.resolve()); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -1891,7 +1891,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -1935,7 +1935,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -1999,7 +1999,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); const callback = () => { const auctionDetails = { @@ -2074,7 +2074,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); const callback = () => { const auctionDetails = { @@ -2350,7 +2350,7 @@ describe('wurflRtdProvider', function () { }); it('should set LCE_ERROR enrichment type when LCE device detection throws error', (done) => { - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); sandbox.stub(prebidGlobalModule, 'getGlobal').returns({ getHighestCpmBids: () => [] @@ -2448,7 +2448,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); const auctionDetails = { bidsReceived: [], @@ -2472,7 +2472,7 @@ describe('wurflRtdProvider', function () { sandbox.stub(storage, 'localStorageIsEnabled').returns(true); sandbox.stub(storage, 'hasLocalStorage').returns(true); - const sendBeaconStub = sandbox.stub(ajaxModule, 'sendBeacon').returns(true); + const sendBeaconStub = sandbox.stub(dep, 'sendBeacon').returns(true); const auctionDetails = { bidsReceived: [], diff --git a/test/spec/modules/yandexBidAdapter_spec.js b/test/spec/modules/yandexBidAdapter_spec.js index ebde0bf6269..19183d9a346 100644 --- a/test/spec/modules/yandexBidAdapter_spec.js +++ b/test/spec/modules/yandexBidAdapter_spec.js @@ -1,7 +1,6 @@ import { assert, expect } from 'chai'; -import { NATIVE_ASSETS, spec } from 'modules/yandexBidAdapter.js'; +import { dep, NATIVE_ASSETS, spec } from 'modules/yandexBidAdapter.js'; import * as utils from 'src/utils.js'; -import * as ajax from 'src/ajax.js'; import { config } from 'src/config.js'; import { setConfig as setCurrencyConfig } from '../../../modules/currency.js'; import { BANNER, NATIVE } from '../../../src/mediaTypes.js'; @@ -977,7 +976,7 @@ describe('Yandex adapter', function () { describe('onTimeout callback', () => { it('will always call server', () => { - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); expect(spec.onTimeout({ forTest: true })).to.not.throw; expect(ajaxStub.calledOnce).to.be.true; }); @@ -985,7 +984,7 @@ describe('Yandex adapter', function () { describe('on onBidderError callback', () => { it('will always call server', () => { - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); spec.onBidderError({ forTest: true }); expect(ajaxStub.calledOnce).to.be.true; }); @@ -993,7 +992,7 @@ describe('Yandex adapter', function () { describe('on onBidBillable callback', () => { it('will always call server', () => { - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); spec.onBidBillable({ forTest: true }); expect(ajaxStub.calledOnce).to.be.true; }); @@ -1001,7 +1000,7 @@ describe('Yandex adapter', function () { describe('on onAdRenderSucceeded callback', () => { it('will always call server', () => { - const ajaxStub = sandbox.stub(ajax, 'ajax'); + const ajaxStub = sandbox.stub(dep, 'ajax'); spec.onAdRenderSucceeded({ forTest: true }); expect(ajaxStub.calledOnce).to.be.true; }); diff --git a/test/spec/unit/core/ajax_spec.js b/test/spec/unit/core/ajax_spec.js index daf2f0713fc..c3fc9ae2683 100644 --- a/test/spec/unit/core/ajax_spec.js +++ b/test/spec/unit/core/ajax_spec.js @@ -1,4 +1,4 @@ -import { attachCallbacks, dep, fetcherFactory, toFetchRequest } from '../../../../src/ajax.js'; +import { ajaxBuilder, attachCallbacks, dep, fetch, ajax, fetcherFactory, toFetchRequest } from '../../../../src/ajax.js'; import { config } from 'src/config.js'; import { server } from '../../../mocks/xhr.js'; import * as utils from 'src/utils.js'; @@ -8,460 +8,545 @@ import { ACTIVITY_ACCESS_REQUEST_CREDENTIALS } from '../../../../src/activities/ const EXAMPLE_URL = 'https://www.example.com'; -describe('fetcherFactory', () => { - let clock; +describe('ajax', () => { + describe('fetcherFactory', () => { + let clock; - beforeEach(() => { - clock = sinon.useFakeTimers(); - server.autoTimeout = true; - }); - - afterEach(() => { - clock.runAll(); - clock.restore(); - config.resetConfig(); - }); - - Object.entries({ - 'URL': EXAMPLE_URL, - 'request object': new Request(EXAMPLE_URL) - }).forEach(([t, resource]) => { - it(`times out after timeout when fetching ${t}`, (done) => { - const fetch = fetcherFactory(1000); - const resp = fetch(resource); - clock.tick(900); - expect(server.requests[0].fetch.request.signal.aborted).to.be.false; - clock.tick(100); - expect(server.requests[0].fetch.request.signal.aborted).to.be.true; - resp.catch(() => done()); + beforeEach(() => { + clock = sinon.useFakeTimers(); + server.autoTimeout = true; }); - }); - describe('credentials', () => { - let resetRule, arqRule, denyCreds; - beforeEach(() => { - denyCreds = false; - arqRule = sinon.stub().callsFake(() => { - if (denyCreds) { - return { allow: false }; - } - }) - resetRule = registerActivityControl(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, 'test', arqRule) - }) afterEach(() => { - resetRule(); + clock.runAll(); + clock.restore(); config.resetConfig(); - }) + }); + Object.entries({ - 'URL': [EXAMPLE_URL, { credentials: 'include' }], - 'request object': [new Request(EXAMPLE_URL, { credentials: 'include' })], - }).forEach(([t, args]) => { - it('should be excluded when deviceAccess is false', () => { - config.setConfig({ deviceAccess: false }); - fetcherFactory()(...args); - expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + 'URL': EXAMPLE_URL, + 'request object': new Request(EXAMPLE_URL) + }).forEach(([t, resource]) => { + it(`times out after timeout when fetching ${t}`, (done) => { + const fetch = fetcherFactory(1000); + const resp = fetch(resource); + clock.tick(900); + expect(server.requests[0].fetch.request.signal.aborted).to.be.false; + clock.tick(100); + expect(server.requests[0].fetch.request.signal.aborted).to.be.true; + resp.catch(() => done()); }); - it('should be excluded when accessRequestCredentials is denied', () => { - denyCreds = true; - fetcherFactory(1000, undefined, 'prebid', 'test')(...args); - sinon.assert.calledWith(arqRule, sinon.match({ - componentType: 'prebid', - componentName: 'test' - })); - expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }); + + describe('credentials', () => { + let resetRule, arqRule, denyCreds; + beforeEach(() => { + denyCreds = false; + arqRule = sinon.stub().callsFake(() => { + if (denyCreds) { + return { allow: false }; + } + }) + resetRule = registerActivityControl(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, 'test', arqRule) + }) + afterEach(() => { + resetRule(); + config.resetConfig(); + }) + Object.entries({ + 'URL': [EXAMPLE_URL, { credentials: 'include' }], + 'request object': [new Request(EXAMPLE_URL, { credentials: 'include' })], + }).forEach(([t, args]) => { + it('should be excluded when deviceAccess is false', () => { + config.setConfig({ deviceAccess: false }); + fetcherFactory()(...args); + expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }); + it('should be excluded when accessRequestCredentials is denied', () => { + denyCreds = true; + fetcherFactory(1000, undefined, 'prebid', 'test')(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + componentType: 'prebid', + componentName: 'test' + })); + expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }) }) }) - }) - it('does not timeout after it completes', () => { - const fetch = fetcherFactory(1000); - const resp = fetch(EXAMPLE_URL); - server.requests[0].respond(); - return resp.then(() => { - clock.tick(2000); - expect(server.requests[0].fetch.request.signal.aborted).to.be.false; - }); - }); - - Object.entries({ - 'disableAjaxTimeout is set'() { - const fetcher = fetcherFactory(1000); - config.setConfig({ disableAjaxTimeout: true }); - return fetcher; - }, - 'timeout is null'() { - return fetcherFactory(null); - }, - }).forEach(([t, mkFetcher]) => { - it(`does not timeout if ${t}`, (done) => { - const fetch = mkFetcher(); - const pm = fetch(EXAMPLE_URL); - clock.tick(2000); + it('does not timeout after it completes', () => { + const fetch = fetcherFactory(1000); + const resp = fetch(EXAMPLE_URL); server.requests[0].respond(); - pm.then(() => done()); + return resp.then(() => { + clock.tick(2000); + expect(server.requests[0].fetch.request.signal.aborted).to.be.false; + }); }); - }); - Object.entries({ - 'local URL': ['/local.html', window.origin], - 'remote URL': [EXAMPLE_URL + '/remote.html', EXAMPLE_URL], - 'request with local URL': [new Request('/local.html'), window.origin], - 'request with remote URL': [new Request(EXAMPLE_URL + '/remote.html'), EXAMPLE_URL] - }).forEach(([t, [resource, expectedOrigin]]) => { - describe(`using ${t}`, () => { - it('calls request, passing origin', () => { - const request = sinon.stub(); - const fetch = fetcherFactory(1000, { request }); - fetch(resource); - sinon.assert.calledWith(request, expectedOrigin); + Object.entries({ + 'disableAjaxTimeout is set'() { + const fetcher = fetcherFactory(1000); + config.setConfig({ disableAjaxTimeout: true }); + return fetcher; + }, + 'timeout is null'() { + return fetcherFactory(null); + }, + }).forEach(([t, mkFetcher]) => { + it(`does not timeout if ${t}`, (done) => { + const fetch = mkFetcher(); + const pm = fetch(EXAMPLE_URL); + clock.tick(2000); + server.requests[0].respond(); + pm.then(() => done()); }); + }); - Object.entries({ - success: 'respond', - error: 'error' - }).forEach(([t, method]) => { - it(`calls done on ${t}, passing origin`, () => { - const done = sinon.stub(); - const fetch = fetcherFactory(1000, { done }); - const req = fetch(resource).catch(() => null).then(() => { - sinon.assert.calledWith(done, expectedOrigin); + Object.entries({ + 'local URL': ['/local.html', window.origin], + 'remote URL': [EXAMPLE_URL + '/remote.html', EXAMPLE_URL], + 'request with local URL': [new Request('/local.html'), window.origin], + 'request with remote URL': [new Request(EXAMPLE_URL + '/remote.html'), EXAMPLE_URL] + }).forEach(([t, [resource, expectedOrigin]]) => { + describe(`using ${t}`, () => { + it('calls request, passing origin', () => { + const request = sinon.stub(); + const fetch = fetcherFactory(1000, { request }); + fetch(resource); + sinon.assert.calledWith(request, expectedOrigin); + }); + + Object.entries({ + success: 'respond', + error: 'error' + }).forEach(([t, method]) => { + it(`calls done on ${t}, passing origin`, () => { + const done = sinon.stub(); + const fetch = fetcherFactory(1000, { done }); + const req = fetch(resource).catch(() => null).then(() => { + sinon.assert.calledWith(done, expectedOrigin); + }); + server.requests[0][method](); + return req; }); - server.requests[0][method](); - return req; }); }); }); }); -}); -describe('toFetchRequest', () => { - Object.entries({ - 'simple POST': { - url: EXAMPLE_URL, - data: 'data', - expect: { - request: { - url: EXAMPLE_URL + '/', - method: 'POST', - }, - text: 'data', - headers: { - 'content-type': 'text/plain' - } - } - }, - 'POST with headers': { - url: EXAMPLE_URL, - data: '{"json": "body"}', - options: { - contentType: 'application/json', - customHeaders: { - 'x-custom': 'value' + describe('toFetchRequest', () => { + Object.entries({ + 'simple POST': { + url: EXAMPLE_URL, + data: 'data', + expect: { + request: { + url: EXAMPLE_URL + '/', + method: 'POST', + }, + text: 'data', + headers: { + 'content-type': 'text/plain' + } } }, - expect: { - request: { - url: EXAMPLE_URL + '/', - method: 'POST', + 'POST with headers': { + url: EXAMPLE_URL, + data: '{"json": "body"}', + options: { + contentType: 'application/json', + customHeaders: { + 'x-custom': 'value' + } }, - text: '{"json": "body"}', - headers: { - 'content-type': 'application/json', - 'X-Custom': 'value' + expect: { + request: { + url: EXAMPLE_URL + '/', + method: 'POST', + }, + text: '{"json": "body"}', + headers: { + 'content-type': 'application/json', + 'X-Custom': 'value' + } } - } - }, - 'simple GET': { - url: EXAMPLE_URL, - data: { p1: 'v1', p2: 'v2' }, - options: { - method: 'GET', }, - expect: { - request: { - url: EXAMPLE_URL + '/?p1=v1&p2=v2', - method: 'GET' + 'simple GET': { + url: EXAMPLE_URL, + data: { p1: 'v1', p2: 'v2' }, + options: { + method: 'GET', }, - text: '', - headers: { - 'content-type': 'text/plain' + expect: { + request: { + url: EXAMPLE_URL + '/?p1=v1&p2=v2', + method: 'GET' + }, + text: '', + headers: { + 'content-type': 'text/plain' + } } - } - }, - 'GET with credentials': { - url: EXAMPLE_URL, - data: null, - options: { - method: 'GET', - withCredentials: true, }, - expect: { - request: { - url: EXAMPLE_URL + '/', + 'GET with credentials': { + url: EXAMPLE_URL, + data: null, + options: { method: 'GET', - credentials: 'include' + withCredentials: true, }, - text: '', - headers: { - 'content-type': 'text/plain' + expect: { + request: { + url: EXAMPLE_URL + '/', + method: 'GET', + credentials: 'include' + }, + text: '', + headers: { + 'content-type': 'text/plain' + } } } - } - }).forEach(([t, { url, data, options, expect: { request, text, headers } }]) => { - it(`can build ${t}`, () => { - const req = toFetchRequest(url, data, options); - return req.text().then(body => { - Object.entries(request).forEach(([prop, val]) => { - expect(req[prop]).to.eql(val); - }); - const hdr = new Headers(headers); - Array.from(req.headers.entries()).forEach(([name, val]) => { - expect(hdr.get(name)).to.eql(val); + }).forEach(([t, { url, data, options, expect: { request, text, headers } }]) => { + it(`can build ${t}`, () => { + const req = toFetchRequest(url, data, options); + return req.text().then(body => { + Object.entries(request).forEach(([prop, val]) => { + expect(req[prop]).to.eql(val); + }); + const hdr = new Headers(headers); + Array.from(req.headers.entries()).forEach(([name, val]) => { + expect(hdr.get(name)).to.eql(val); + }); + expect(body).to.eql(text); }); - expect(body).to.eql(text); }); }); - }); - describe('chrome options', () => { - ['browsingTopics'].forEach(option => { - Object.entries({ - [`${option} = true`]: [{ [option]: true }, true], - [`${option} = false`]: [{ [option]: false }, false], - [`${option} undef`]: [{}, false] - }).forEach(([t, [opts, shouldBeSet]]) => { - describe(`when options has ${t}`, () => { - const sandbox = sinon.createSandbox(); - afterEach(() => { - sandbox.restore(); - }); + describe('chrome options', () => { + ['browsingTopics'].forEach(option => { + Object.entries({ + [`${option} = true`]: [{ [option]: true }, true], + [`${option} = false`]: [{ [option]: false }, false], + [`${option} undef`]: [{}, false] + }).forEach(([t, [opts, shouldBeSet]]) => { + describe(`when options has ${t}`, () => { + const sandbox = sinon.createSandbox(); + afterEach(() => { + sandbox.restore(); + }); - it(`should ${!shouldBeSet ? 'not ' : ''}be set when in a secure context`, () => { - sandbox.stub(window, 'isSecureContext').get(() => true); - toFetchRequest(EXAMPLE_URL, null, opts); - sinon.assert.calledWithMatch(dep.makeRequest, sinon.match.any, { [option]: shouldBeSet ? true : undefined }); - }); - it(`should not be set when not in a secure context`, () => { - sandbox.stub(window, 'isSecureContext').get(() => false); - toFetchRequest(EXAMPLE_URL, null, opts); - sinon.assert.calledWithMatch(dep.makeRequest, sinon.match.any, { [option]: undefined }); - }); + it(`should ${!shouldBeSet ? 'not ' : ''}be set when in a secure context`, () => { + sandbox.stub(window, 'isSecureContext').get(() => true); + toFetchRequest(EXAMPLE_URL, null, opts); + sinon.assert.calledWithMatch(dep.makeRequest, sinon.match.any, { [option]: shouldBeSet ? true : undefined }); + }); + it(`should not be set when not in a secure context`, () => { + sandbox.stub(window, 'isSecureContext').get(() => false); + toFetchRequest(EXAMPLE_URL, null, opts); + sinon.assert.calledWithMatch(dep.makeRequest, sinon.match.any, { [option]: undefined }); + }); + }) }) }) }) - }) -}); - -describe('attachCallbacks', () => { - const sampleHeaders = new Headers({ - 'x-1': 'v1', - 'x-2': 'v2' }); - function responseFactory(body, props) { - props = Object.assign({ headers: sampleHeaders, url: EXAMPLE_URL }, props); - return function () { - return { - response: Object.defineProperties(new Response(body, props), { - url: { - get: () => props.url - } - }), - body: body || '' - }; - }; - } - - function expectNullXHR(response, reason) { - return new Promise((resolve, reject) => { - attachCallbacks(Promise.resolve(response), { - success: () => { - reject(new Error('should not succeed')); - }, - error(statusText, xhr) { - expect(statusText).to.eql(''); - sinon.assert.match(xhr, { - readyState: XMLHttpRequest.DONE, - status: 0, - statusText: '', - responseText: '', - response: '', - responseXML: null, - reason - }); - expect(xhr.getResponseHeader('any')).to.be.null; - resolve(); + describe('credentials', () => { + let resetRule, arqRule, denyCreds; + beforeEach(() => { + denyCreds = false; + arqRule = sinon.stub().callsFake(() => { + if (denyCreds) { + return { allow: false }; } }); + resetRule = registerActivityControl(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, 'test', arqRule); + }); + afterEach(() => { + resetRule(); + config.resetConfig(); + }); + Object.entries({ + 'fetch URL': { + factory: fetcherFactory, + fn: fetch, + args: [EXAMPLE_URL, { credentials: 'include' }] + }, + 'fetch request object': { + factory: fetcherFactory, + fn: fetch, + args: [new Request(EXAMPLE_URL, { credentials: 'include' })] + }, + 'ajax': { + factory: ajaxBuilder, + fn: ajax, + args: [EXAMPLE_URL, null, null, { withCredentials: true }] + } + }).forEach(([t, { factory, fn, args }]) => { + describe(t, () => { + it('should be excluded when deviceAccess is false', () => { + config.setConfig({ deviceAccess: false }); + factory(1000, {}, 'prebid', 'test')(...args); + expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }); + it('should be excluded when accessRequestCredentials is denied', () => { + denyCreds = true; + factory(1000, {}, 'prebid', 'test')(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + componentType: 'prebid', + componentName: 'test' + })); + expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }); + it('should be excluded when caller is not known', () => { + fn(...args); + expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); + }); + describe('should find moduleType/moduleName', () => { + it('from fn.withCallers', () => { + fn.withCallers([['prebid', 'test']])(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + component: 'prebid.test' + })); + }); + it('from factory.withCallers', () => { + factory.withCallers([['prebid', 'test']])()(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + component: 'prebid.test' + })); + }); + it('factory should give precedence to explicit moduleType/moduleName', () => { + factory.withCallers([['not', 'relevant']])(1000, {}, 'prebid', 'test')(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + component: 'prebid.test' + })); + sinon.assert.calledOnce(arqRule); + }); + it('fn should give precedence to explicit moduleType/moduleName', () => { + factory(1000, {}, 'prebid', 'test').withCallers([['not', 'relevant']])(...args); + sinon.assert.calledWith(arqRule, sinon.match({ + component: 'prebid.test' + })); + sinon.assert.calledOnce(arqRule); + }) + }); + }) }); - } - - it('runs error callback on rejections', () => { - const err = new Error(); - return expectNullXHR(Promise.reject(err), err); }); - it('sets timedOut = true on fetch timeout', (done) => { - const ctl = new AbortController(); - ctl.abort(); - attachCallbacks(fetch('/', { signal: ctl.signal }), { - error(_, xhr) { - expect(xhr.timedOut).to.be.true; - done(); - } + describe('attachCallbacks', () => { + const sampleHeaders = new Headers({ + 'x-1': 'v1', + 'x-2': 'v2' }); - }) - Object.entries({ - '2xx response': { - success: true, - makeResponse: responseFactory('body', { status: 200, statusText: 'OK' }) - }, - '2xx response with no body': { - success: true, - makeResponse: responseFactory(null, { status: 204, statusText: 'No content' }) - }, - '2xx response with XML': { - success: true, - xml: true, - makeResponse: responseFactory('', { - status: 200, - statusText: 'OK', - headers: { 'content-type': 'application/xml;charset=UTF8' } - }) - }, - '2xx response with HTML': { - success: true, - xml: true, - makeResponse: responseFactory('

', { - status: 200, - statusText: 'OK', - headers: { 'content-type': 'text/html;charset=UTF-8' } - }) - }, - '304 response': { - success: true, - makeResponse: responseFactory(null, { status: 304, statusText: 'Moved permanently' }) - }, - '4xx response': { - success: false, - makeResponse: responseFactory('body', { status: 400, statusText: 'Invalid request' }) - }, - '5xx response': { - success: false, - makeResponse: responseFactory('body', { status: 503, statusText: 'Gateway error' }) - }, - '4xx response with XML': { - success: false, - xml: true, - makeResponse: responseFactory('', { - status: 404, - statusText: 'Not found', - headers: { - 'content-type': 'application/xml' - } - }) + function responseFactory(body, props) { + props = Object.assign({ headers: sampleHeaders, url: EXAMPLE_URL }, props); + return function () { + return { + response: Object.defineProperties(new Response(body, props), { + url: { + get: () => props.url + } + }), + body: body || '' + }; + }; } - }).forEach(([t, { success, makeResponse, xml }]) => { - const cbType = success ? 'success' : 'error'; - describe(`for ${t}`, () => { - let sandbox, response, body; - beforeEach(() => { - sandbox = sinon.createSandbox(); - sandbox.spy(utils, 'logError'); - ({ response, body } = makeResponse()); - }); - - afterEach(() => { - sandbox.restore(); - }) - - function checkXHR(xhr) { - utils.logError.resetHistory(); - const serialized = JSON.parse(JSON.stringify(xhr)) - // serialization of `responseXML` should not generate console messages - sinon.assert.notCalled(utils.logError); - - sinon.assert.match(serialized, { - readyState: XMLHttpRequest.DONE, - status: response.status, - statusText: response.statusText, - responseType: '', - responseURL: response.url, - response: body, - responseText: body, - }); - if (xml) { - expect(xhr.responseXML.querySelectorAll('*').length > 0).to.be.true; - } else { - expect(serialized.responseXML).to.not.exist; - } - Array.from(response.headers.entries()).forEach(([name, value]) => { - expect(xhr.getResponseHeader(name)).to.eql(value); - }); - expect(xhr.getResponseHeader('$$missing-header')).to.be.null; - } - - it(`runs ${cbType} callback`, (done) => { + function expectNullXHR(response, reason) { + return new Promise((resolve, reject) => { attachCallbacks(Promise.resolve(response), { - success(payload, xhr) { - expect(success).to.be.true; - expect(payload).to.eql(body); - checkXHR(xhr); - done(); + success: () => { + reject(new Error('should not succeed')); }, error(statusText, xhr) { - expect(success).to.be.false; - expect(statusText).to.eql(response.statusText); - checkXHR(xhr); - done(); + expect(statusText).to.eql(''); + sinon.assert.match(xhr, { + readyState: XMLHttpRequest.DONE, + status: 0, + statusText: '', + responseText: '', + response: '', + responseXML: null, + reason + }); + expect(xhr.getResponseHeader('any')).to.be.null; + resolve(); } }); }); + } - it(`runs error callback if body cannot be retrieved`, () => { - const err = new Error(); - response.text = () => Promise.reject(err); - return expectNullXHR(response, err); + it('runs error callback on rejections', () => { + const err = new Error(); + return expectNullXHR(Promise.reject(err), err); + }); + + it('sets timedOut = true on fetch timeout', (done) => { + const ctl = new AbortController(); + ctl.abort(); + attachCallbacks(window.fetch('/', { signal: ctl.signal }), { + error(_, xhr) { + expect(xhr.timedOut).to.be.true; + done(); + } }); + }) - if (success) { - it('accepts a single function as success callback', (done) => { - attachCallbacks(Promise.resolve(response), function (payload, xhr) { - expect(payload).to.eql(body); - checkXHR(xhr); - done(); - }) + Object.entries({ + '2xx response': { + success: true, + makeResponse: responseFactory('body', { status: 200, statusText: 'OK' }) + }, + '2xx response with no body': { + success: true, + makeResponse: responseFactory(null, { status: 204, statusText: 'No content' }) + }, + '2xx response with XML': { + success: true, + xml: true, + makeResponse: responseFactory('', { + status: 200, + statusText: 'OK', + headers: { 'content-type': 'application/xml;charset=UTF8' } + }) + }, + '2xx response with HTML': { + success: true, + xml: true, + makeResponse: responseFactory('

', { + status: 200, + statusText: 'OK', + headers: { 'content-type': 'text/html;charset=UTF-8' } + }) + }, + '304 response': { + success: true, + makeResponse: responseFactory(null, { status: 304, statusText: 'Moved permanently' }) + }, + '4xx response': { + success: false, + makeResponse: responseFactory('body', { status: 400, statusText: 'Invalid request' }) + }, + '5xx response': { + success: false, + makeResponse: responseFactory('body', { status: 503, statusText: 'Gateway error' }) + }, + '4xx response with XML': { + success: false, + xml: true, + makeResponse: responseFactory('', { + status: 404, + statusText: 'Not found', + headers: { + 'content-type': 'application/xml' + } }) } - }); - }); + }).forEach(([t, { success, makeResponse, xml }]) => { + const cbType = success ? 'success' : 'error'; - describe('callback exceptions', () => { - Object.entries({ - success: responseFactory(null, { status: 204 }), - error: responseFactory('', { status: 400 }), - }).forEach(([cbType, makeResponse]) => { - it(`do not choke ${cbType} callbacks`, () => { - const { response } = makeResponse(); - const result = { success: false, error: false }; - return attachCallbacks(Promise.resolve(response), { - success() { - result.success = true; - throw new Error(); - }, - error() { - result.error = true; - throw new Error(); + describe(`for ${t}`, () => { + let sandbox, response, body; + beforeEach(() => { + sandbox = sinon.createSandbox(); + sandbox.spy(utils, 'logError'); + ({ response, body } = makeResponse()); + }); + + afterEach(() => { + sandbox.restore(); + }) + + function checkXHR(xhr) { + utils.logError.resetHistory(); + const serialized = JSON.parse(JSON.stringify(xhr)) + // serialization of `responseXML` should not generate console messages + sinon.assert.notCalled(utils.logError); + + sinon.assert.match(serialized, { + readyState: XMLHttpRequest.DONE, + status: response.status, + statusText: response.statusText, + responseType: '', + responseURL: response.url, + response: body, + responseText: body, + }); + if (xml) { + expect(xhr.responseXML.querySelectorAll('*').length > 0).to.be.true; + } else { + expect(serialized.responseXML).to.not.exist; } - }).catch(() => null) - .then(() => { - Object.entries(result).forEach(([typ, ran]) => { - expect(ran).to.be[typ === cbType ? 'true' : 'false']; - }); + Array.from(response.headers.entries()).forEach(([name, value]) => { + expect(xhr.getResponseHeader(name)).to.eql(value); }); + expect(xhr.getResponseHeader('$$missing-header')).to.be.null; + } + + it(`runs ${cbType} callback`, (done) => { + attachCallbacks(Promise.resolve(response), { + success(payload, xhr) { + expect(success).to.be.true; + expect(payload).to.eql(body); + checkXHR(xhr); + done(); + }, + error(statusText, xhr) { + expect(success).to.be.false; + expect(statusText).to.eql(response.statusText); + checkXHR(xhr); + done(); + } + }); + }); + + it(`runs error callback if body cannot be retrieved`, () => { + const err = new Error(); + response.text = () => Promise.reject(err); + return expectNullXHR(response, err); + }); + + if (success) { + it('accepts a single function as success callback', (done) => { + attachCallbacks(Promise.resolve(response), function (payload, xhr) { + expect(payload).to.eql(body); + checkXHR(xhr); + done(); + }) + }) + } + }); + }); + + describe('callback exceptions', () => { + Object.entries({ + success: responseFactory(null, { status: 204 }), + error: responseFactory('', { status: 400 }), + }).forEach(([cbType, makeResponse]) => { + it(`do not choke ${cbType} callbacks`, () => { + const { response } = makeResponse(); + const result = { success: false, error: false }; + return attachCallbacks(Promise.resolve(response), { + success() { + result.success = true; + throw new Error(); + }, + error() { + result.error = true; + throw new Error(); + } + }).catch(() => null) + .then(() => { + Object.entries(result).forEach(([typ, ran]) => { + expect(ran).to.be[typ === cbType ? 'true' : 'false']; + }); + }); + }); }); }); }); -}); +}) diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index 520295cde9f..358167720bd 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -639,7 +639,7 @@ describe('Unit: Prebid Module', function () { auction = auctionManagerInstance.createAuction({ adUnits, adUnitCodes }); indexStub = sinon.stub(auctionManager, 'index'); indexStub.get(() => auctionManagerInstance.index); - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() { + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(function() { return function(url, callback) { const fakeResponse = sinon.stub(); fakeResponse.returns('headerContent'); @@ -822,7 +822,7 @@ describe('Unit: Prebid Module', function () { const initTestConfig = (data) => { pbjs.bidderSettings = {}; - ajaxStub = sinon.stub(ajaxLib, 'ajaxBuilder').callsFake(function() { + ajaxStub = sinon.stub(ajaxLib, 'qualifiedAjaxBuilder').callsFake(function() { return function(url, callback) { const fakeResponse = sinon.stub(); fakeResponse.returns('headerContent'); From c6b9f71d93521de9385f5874dd158258f372e5d4 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 28 May 2026 07:07:05 -0700 Subject: [PATCH 010/124] Core: fix bug where hb_cache_host is sometimes not set to the right host (#14806) --- src/auction.ts | 7 ++++--- src/videoCache.ts | 13 ++++++++++--- test/spec/auctionmanager_spec.js | 6 ++++-- test/spec/videoCache_spec.js | 19 +++++-------------- 4 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/auction.ts b/src/auction.ts index fe561888903..1b53fa42601 100644 --- a/src/auction.ts +++ b/src/auction.ts @@ -1053,11 +1053,12 @@ export function getStandardBidderSettings(mediaType, bidderCode) { // Adding hb_cache_host if (config.getConfig('cache.url') && (!bidderCode || bidderSettings.get(bidderCode, 'sendStandardTargeting') !== false)) { - const urlInfo = parseUrl(config.getConfig('cache.url')); - if (typeof adserverTargeting.find(targetingKeyVal => targetingKeyVal.key === TARGETING_KEYS.CACHE_HOST) === 'undefined') { adserverTargeting.push(createKeyVal(TARGETING_KEYS.CACHE_HOST, function(bidResponse) { - return (bidResponse?.adserverTargeting?.[TARGETING_KEYS.CACHE_HOST] || urlInfo.hostname) as string; + if (bidResponse.cacheUrl) { + return parseUrl(bidResponse.cacheUrl).hostname + } + return bidResponse.adserverTargeting?.[TARGETING_KEYS.CACHE_HOST]; })); } } diff --git a/src/videoCache.ts b/src/videoCache.ts index 9442d89975e..8ed08edb17c 100644 --- a/src/videoCache.ts +++ b/src/videoCache.ts @@ -97,6 +97,11 @@ declare module './bidfactory' { * The cache key that was used for this bid. */ videoCacheKey?: string; + /** + * URL of the cache service Prebid used to cache this bid (`getConfig('cache.url')`). Undefined if Prebid did + * not cache this bid. + */ + cacheUrl?: string; } } @@ -238,8 +243,8 @@ export function store(bids: VideoBid[], done?: VideoCacheStoreCallback, getAjax }); } -export function getCacheUrl(id) { - return `${config.getConfig('cache.url')}?uuid=${id}`; +export function getCacheUrl(cacheUrl, id) { + return `${cacheUrl}?uuid=${id}`; } export const storeLocally = (bid) => { @@ -308,6 +313,7 @@ export function storeBatch(batch) { function err(msg) { logError(`Failed to save to the video cache: ${msg}. Video bids will be discarded:`, bids) } + const cacheUrl = config.getConfig('cache.url'); _internal.store(bids, function (error, cacheIds) { if (error) { err(error) @@ -319,7 +325,8 @@ export function storeBatch(batch) { if (cacheId.uuid === '') { logWarn(`Supplied video cache key was already in use by Prebid Cache; caching attempt was rejected. Video bid must be discarded.`); } else { - assignVastUrlAndCacheId(bidResponse, getCacheUrl(cacheId.uuid), cacheId.uuid); + bidResponse.cacheUrl = cacheUrl; + assignVastUrlAndCacheId(bidResponse, getCacheUrl(cacheUrl, cacheId.uuid), cacheId.uuid); addBidToAuction(auctionInstance, bidResponse); afterBidAdded(); } diff --git a/test/spec/auctionmanager_spec.js b/test/spec/auctionmanager_spec.js index fd11f0e166b..4a9ce5f2463 100644 --- a/test/spec/auctionmanager_spec.js +++ b/test/spec/auctionmanager_spec.js @@ -277,13 +277,14 @@ describe('auctionmanager.js', function () { it('No bidder level configuration defined - default for video', function () { config.setConfig({ cache: { - url: 'https://test.cache.url/endpoint' + url: 'ignored' } }); getGlobal().bidderSettings = {}; const videoBid = utils.deepClone(bid); videoBid.mediaType = 'video'; videoBid.videoCacheKey = 'abc123def'; + videoBid.cacheUrl = 'https://test.cache.url/endpoint'; const expected = getDefaultExpected(videoBid); const response = getKeyValueTargetingPairs(videoBid.bidderCode, videoBid); @@ -370,12 +371,13 @@ describe('auctionmanager.js', function () { it('Custom configuration for all bidders with video bid', function () { config.setConfig({ cache: { - url: 'https://test.cache.url/endpoint' + url: 'ignored' } }); const videoBid = utils.deepClone(bid); videoBid.mediaType = 'video'; videoBid.videoCacheKey = 'abc123def'; + videoBid.cacheUrl = 'https://test.cache.url/endpoint'; getGlobal().bidderSettings = { diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js index 4501fb10648..0ece4bbedac 100644 --- a/test/spec/videoCache_spec.js +++ b/test/spec/videoCache_spec.js @@ -365,7 +365,7 @@ describe('The video cache', function () { sinon.assert.notCalled(batch[0].afterBidAdded); sinon.assert.called(utils.logError); }); - it('should set bids\' videoCacheKey and vastUrl', () => { + it('should set bids\' videoCacheKey, vastUrl, and cacheUrl', () => { config.setConfig({ cache: { url: 'mock-cache' @@ -376,7 +376,8 @@ describe('The video cache', function () { storeBatch([el]); sinon.assert.match(el.bidResponse, { videoCacheKey: 'mock-id', - vastUrl: 'mock-cache?uuid=mock-id' + vastUrl: 'mock-cache?uuid=mock-id', + cacheUrl: 'mock-cache', }) }); }) @@ -598,21 +599,11 @@ describe('The video cache', function () { }); describe('The getCache function', function () { - beforeEach(function () { - config.setConfig({ - cache: { - url: 'https://test.cache.url/endpoint' - } - }) - }); - - afterEach(function () { - config.resetConfig(); - }); + const CACHE_URL = 'https://test.cache.url/endpoint'; it('should return the expected URL', function () { const uuid = 'c488b101-af3e-4a99-b538-00423e5a3371'; - const url = getCacheUrl(uuid); + const url = getCacheUrl(CACHE_URL, uuid); url.should.equal(`https://test.cache.url/endpoint?uuid=${uuid}`); }); }) From 594dbcbc1649beafa9cfe9bfbc4fd5fd9f63bfb5 Mon Sep 17 00:00:00 2001 From: thenexusengine dev Date: Thu, 28 May 2026 15:11:03 +0100 Subject: [PATCH 011/124] TNE Catalyst Bid Adapter: optional params + ortb2 passthrough (#14941) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Combines the AMX-style permissive-params refactor with full ortb2.* passthrough so the adapter integrates with a single '{ bidder: tne_catalyst }' entry while honouring everything the wrapper already populates. Permissive params (AMX-style) - All bid params optional. isBidRequestValid accepts a bid with no params; rejects bids with wrong-typed values via a nullOrType helper. - slot defaults to bid.adUnitCode and is mirrored into imp.tagid. - site.publisher.id omitted when no override; exchange resolves publisher from site.domain via sellers.json. - New optional params.endpoint and params.testMode (the latter is resolved per-imp so individual placements can be marked as test). ortb2 passthrough - ortb2.user / regs / device / app flow through to the outbound. - bid.userIdAsEids still read and merged with ortb2.user.eids (de-duped by source). - Per the module rules, wrapper-set fields are authoritative; derived signals (gdprConsent, uspConsent, gppConsent) only fill gaps the wrapper hasn't already populated. site / app mutex - OpenRTB 2.6 §3.2.1: site and app are mutually exclusive. When ortb2.app is present, site is omitted entirely; publisherId stamps onto app.publisher.id. Site is also omitted when no site fields would be populated. schain - Read from ortb2.source.ext.schain (Prebid 9.x normalized location) with fallback to ortb2.source.schain (OpenRTB 2.6 top-level) and finally legacy bid.schain for older wrapper builds. Outbound goes on source.schain so modern adapters don't need to ext-fish. 101 tests passing. Co-authored-by: thenexusengine <250033251+thenexusengine@users.noreply.github.com> --- modules/tne_catalystBidAdapter.md | 47 ++-- modules/tne_catalystBidAdapter.ts | 207 ++++++++++++----- .../modules/tne_catalystBidAdapter_spec.js | 209 ++++++++++++++++-- 3 files changed, 372 insertions(+), 91 deletions(-) diff --git a/modules/tne_catalystBidAdapter.md b/modules/tne_catalystBidAdapter.md index b6fd3421e6a..5a2fa36f14b 100644 --- a/modules/tne_catalystBidAdapter.md +++ b/modules/tne_catalystBidAdapter.md @@ -2,15 +2,19 @@ ## Overview -TNE Catalyst is a programmatic exchange that manages demand relationships server-side. Publishers configure a single bidder with their account ID and placement slot; TNE routes the request to its configured SSP partners and returns the winning bid. No SSP-specific IDs or configuration is required on the publisher side. +TNE Catalyst is a programmatic exchange that manages demand relationships server-side. Publishers can integrate with a single `{ bidder: 'tne_catalyst' }` entry — no params are required. Publisher identity is resolved server-side from the page domain via sellers.json, and the slot key defaults to `adUnitCode`. TNE routes the request to its configured SSP partners and returns the winning bid. No SSP-specific IDs or configuration is required on the publisher side. ## Bid Parameters +All params are optional. Supply them to override the server-side defaults. + | Param | Scope | Type | Description | |-------|-------|------|-------------| -| `publisherId` | required | string | Publisher account ID assigned by TNE (e.g. `NXS003`) | -| `slot` | required | string | Placement identifier matching the slot configured in the TNE dashboard (e.g. `billboard`) | -| `bidfloor` | optional | number | Minimum acceptable CPM in USD | +| `publisherId` | optional | string | Override domain-based publisher resolution (e.g. `NXS003`) | +| `slot` | optional | string | Override the default slot key (defaults to `adUnitCode`) | +| `bidfloor` | optional | number | Minimum acceptable CPM in USD (also read from the Floors module via `getFloor()`) | +| `endpoint` | optional | string | Override the auction endpoint URL (testing / staging) | +| `testMode` | optional | boolean | Marks the request as test traffic via `imp.ext.tne_catalyst.testMode` | ## Supported Media Types @@ -37,7 +41,7 @@ ops@thenexusengine.io ## Example Ad Units -### Banner +### Banner (minimal — recommended) ```javascript var adUnits = [ @@ -46,30 +50,35 @@ var adUnits = [ mediaTypes: { banner: { sizes: [[970, 250], [728, 90]] } }, - bids: [{ - bidder: 'tne_catalyst', - params: { - publisherId: 'NXS003', - slot: 'billboard' - } - }] + bids: [{ bidder: 'tne_catalyst' }] }, { code: 'div-rectangle', mediaTypes: { banner: { sizes: [[300, 250], [300, 600]] } }, - bids: [{ - bidder: 'tne_catalyst', - params: { - publisherId: 'NXS003', - slot: 'rectangle' - } - }] + bids: [{ bidder: 'tne_catalyst' }] } ]; ``` +### Banner (with overrides) + +```javascript +var adUnits = [{ + code: 'div-billboard', + mediaTypes: { banner: { sizes: [[970, 250], [728, 90]] } }, + bids: [{ + bidder: 'tne_catalyst', + params: { + publisherId: 'NXS003', // optional override + slot: 'billboard', // optional override (defaults to adUnitCode) + bidfloor: 0.5 // optional + } + }] +}]; +``` + ### Native ```javascript diff --git a/modules/tne_catalystBidAdapter.ts b/modules/tne_catalystBidAdapter.ts index 87f0235ff93..995d69cdc89 100644 --- a/modules/tne_catalystBidAdapter.ts +++ b/modules/tne_catalystBidAdapter.ts @@ -1,13 +1,23 @@ import { BidderSpec, registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; -import { generateUUID, deepAccess, isArray, isFn } from '../src/utils.js'; +import { generateUUID, deepAccess, isArray, isFn, logWarn } from '../src/utils.js'; /** * TNE Catalyst Bid Adapter * - * Single-bidder adapter for the TNE Catalyst exchange. Publishers configure - * one bidder with { publisherId, slot }; TNE handles all SSP relationships - * and demand decisions server-side. No SSP IDs are required or exposed. + * Single-bidder adapter for the TNE Catalyst exchange. TNE manages all SSP + * relationships and demand decisions server-side, so no SSP IDs are required + * or exposed. + * + * All params are optional. With no params at all, the adapter derives slot + * identity from `adUnitCode` and publisher identity from the page domain + * (resolved server-side via sellers.json). Publishers can still override: + * + * - `publisherId` — override the server-side domain resolution + * - `slot` — override the default `adUnitCode` slot key + * - `bidfloor` — fallback floor when `getFloor()` is absent + * - `endpoint` — route to an alternate auction endpoint (testing) + * - `testMode` — flag the request as test traffic * * @see https://thenexusengine.io * Maintainer: ops@thenexusengine.io @@ -19,9 +29,23 @@ const SYNC_URL = 'https://ads.thenexusengine.com/cookie_sync'; const GVLID = 1494; interface TneCatalystBidParams { - publisherId: string; - slot: string; + publisherId?: string; + slot?: string; bidfloor?: number; + endpoint?: string; + testMode?: boolean; +} + +// Permits absent values; rejects supplied values of the wrong type. The +// switch keeps each typeof comparison against a string literal so the +// valid-typeof eslint rule stays satisfied without a directive. +function nullOrType(value: unknown, type: 'string' | 'number' | 'boolean'): boolean { + if (value == null) return true; + switch (type) { + case 'string': return typeof value === 'string'; + case 'number': return typeof value === 'number'; + case 'boolean': return typeof value === 'boolean'; + } } declare module '../src/adUnits' { @@ -36,11 +60,16 @@ export const spec: BidderSpec = { supportedMediaTypes: [BANNER, NATIVE, VIDEO], isBidRequestValid(bid) { - const params = bid && (bid as any).params; - return !!( - params && - typeof params.publisherId === 'string' && params.publisherId !== '' && - typeof params.slot === 'string' && params.slot !== '' + // All params are optional. When supplied, they must be the right type — + // otherwise reject so a typo doesn't silently fall back to defaults. + if (!bid) return false; + const params = (bid as any).params || {}; + return ( + nullOrType(params.publisherId, 'string') && + nullOrType(params.slot, 'string') && + nullOrType(params.endpoint, 'string') && + nullOrType(params.bidfloor, 'number') && + nullOrType(params.testMode, 'boolean') ); }, @@ -49,12 +78,40 @@ export const spec: BidderSpec = { return []; } - const publisherId = (validBidRequests[0] as any).params.publisherId; + // Request-level params: endpoint must be batch-level since the request is + // a single HTTP call. publisherId is also batch-level since `site.publisher` + // is one-per-request; if different imps in the same auction carry different + // values we honour the first and log so the discrepancy surfaces. Per-imp + // params (slot, bidfloor, testMode) are resolved inside the loop below. + const firstParams = (validBidRequests[0] as any).params || {}; + const publisherId: string | undefined = firstParams.publisherId; + const endpoint: string = firstParams.endpoint || ENDPOINT_URL; + if (publisherId != null) { + for (const b of validBidRequests) { + const pid = (b as any).params?.publisherId; + if (pid != null && pid !== publisherId) { + logWarn(`tne_catalyst: mixed publisherId across imps in one auction (using ${publisherId}, ignoring ${pid})`); + break; + } + } + } const imps = validBidRequests.map((bid: any) => { + const params = bid.params || {}; + // Slot defaults to the Prebid adUnitCode (div ID). The server uses this + // as a placement key when no slot override is supplied — same pattern as + // AMX's `adUnitId` fallback. + const slot: string = params.slot || bid.adUnitCode; + const slotExt: any = { slot }; + // testMode is per-imp: individual placements can be flagged as test + // traffic without affecting siblings in the same auction. + if (params.testMode === true) slotExt.testMode = true; const imp: any = { id: bid.bidId, - ext: { tne_catalyst: { slot: bid.params.slot } } + // OpenRTB tagid mirrors the slot key, giving the server two places to + // look without forcing publishers to set anything explicit. + tagid: slot, + ext: { tne_catalyst: slotExt } }; const mediaTypes = bid.mediaTypes || {}; @@ -101,80 +158,118 @@ export const spec: BidderSpec = { floorApplied = true; } } - if (!floorApplied && bid.params.bidfloor) { - imp.bidfloor = bid.params.bidfloor; + if (!floorApplied && params.bidfloor) { + imp.bidfloor = params.bidfloor; imp.bidfloorcur = 'USD'; } return imp; }); - const site: any = { publisher: { id: publisherId } }; - const ri = deepAccess(bidderRequest, 'refererInfo'); - if (ri) { - if (ri.page) site.page = ri.page; - if (ri.domain) site.domain = ri.domain; - if (ri.ref) site.ref = ri.ref; - } - - const ortb2Site = deepAccess(bidderRequest, 'ortb2.site'); - if (ortb2Site) { - Object.assign(site, ortb2Site); - site.publisher = { id: publisherId }; - } - const ortbRequest: any = { id: generateUUID(), imp: imps, - site, }; if ((bidderRequest as any).timeout) { ortbRequest.tmax = (bidderRequest as any).timeout; } - const regsExt: any = {}; - const gdpr = deepAccess(bidderRequest, 'gdprConsent'); - if (gdpr) { - regsExt.gdpr = gdpr.gdprApplies ? 1 : 0; + // ortb2 passthrough — the wrapper's modern source of truth for user + // identity, compliance, device, site/app context. Per Prebid module rules + // ("Bidder params should always only override that information coming on + // the request"), we treat ortb2.* as authoritative and only layer our + // derived overrides (consent strings synthesized from gdprConsent, etc.) + // when the wrapper hasn't already populated the same key. + const ortb2 = deepAccess(bidderRequest, 'ortb2') || {}; + if (ortb2.user) ortbRequest.user = { ...ortb2.user }; + if (ortb2.regs) ortbRequest.regs = { ...ortb2.regs }; + if (ortb2.device) ortbRequest.device = { ...ortb2.device }; + + // site OR app, never both — OpenRTB 2.6 §3.2.1 requires these to be + // mutually exclusive. App context (CTV/in-app) takes precedence when + // present in ortb2; otherwise build a site object from refererInfo, + // ortb2.site, and the optional publisher override. + if (ortb2.app) { + ortbRequest.app = { ...ortb2.app }; + if (publisherId) { + ortbRequest.app.publisher = { ...(ortbRequest.app.publisher || {}), id: publisherId }; + } + } else { + const site: any = publisherId ? { publisher: { id: publisherId } } : {}; + const ri = deepAccess(bidderRequest, 'refererInfo'); + if (ri) { + if (ri.page) site.page = ri.page; + if (ri.domain) site.domain = ri.domain; + if (ri.ref) site.ref = ri.ref; + } + const ortb2Site = ortb2.site; + if (ortb2Site) { + Object.assign(site, ortb2Site); + if (publisherId) site.publisher = { id: publisherId }; + } + if (Object.keys(site).length > 0) { + ortbRequest.site = site; + } } + + const gdpr = deepAccess(bidderRequest, 'gdprConsent'); const usp = deepAccess(bidderRequest, 'uspConsent'); - if (usp) { - regsExt.us_privacy = usp; - } const gpp = deepAccess(bidderRequest, 'gppConsent'); - if (gpp && gpp.gppString) { - ortbRequest.regs = ortbRequest.regs || {}; - ortbRequest.regs.gpp = gpp.gppString; - ortbRequest.regs.gpp_sid = gpp.applicableSections || []; - } - if (Object.keys(regsExt).length > 0) { + + // regs.* — only set fields the wrapper didn't already supply via ortb2. + if (gdpr || usp || (gpp && gpp.gppString)) { ortbRequest.regs = ortbRequest.regs || {}; - ortbRequest.regs.ext = regsExt; + if (gpp && gpp.gppString) { + if (ortbRequest.regs.gpp == null) ortbRequest.regs.gpp = gpp.gppString; + if (ortbRequest.regs.gpp_sid == null) ortbRequest.regs.gpp_sid = gpp.applicableSections || []; + } + if (gdpr || usp) { + const regsExt = { ...(ortbRequest.regs.ext || {}) }; + if (gdpr && regsExt.gdpr == null) regsExt.gdpr = gdpr.gdprApplies ? 1 : 0; + if (usp && regsExt.us_privacy == null) regsExt.us_privacy = usp; + ortbRequest.regs.ext = regsExt; + } } - const userExt: any = {}; - if (gdpr && gdpr.consentString) { - userExt.consent = gdpr.consentString; - } - const eids = deepAccess(validBidRequests[0], 'userIdAsEids'); - if (isArray(eids) && eids.length > 0) { + // user.eids — merge the legacy bid.userIdAsEids list with whatever the + // wrapper already put on ortb2.user.eids. De-duplicate by source so a + // legacy provider doesn't show up twice. + const legacyEids = deepAccess(validBidRequests[0], 'userIdAsEids'); + if (isArray(legacyEids) && legacyEids.length > 0) { ortbRequest.user = ortbRequest.user || {}; - ortbRequest.user.eids = eids; + const existing: any[] = isArray(ortbRequest.user.eids) ? ortbRequest.user.eids : []; + const seen = new Set(existing.map((e: any) => e && e.source).filter(Boolean)); + const merged = existing.concat(legacyEids.filter((e: any) => e && e.source && !seen.has(e.source))); + ortbRequest.user.eids = merged; } - if (Object.keys(userExt).length > 0) { + + // user.ext.consent — synthesize from gdprConsent only when ortb2 didn't + // already carry one. + if (gdpr && gdpr.consentString) { ortbRequest.user = ortbRequest.user || {}; - ortbRequest.user.ext = userExt; + ortbRequest.user.ext = { ...(ortbRequest.user.ext || {}) }; + if (ortbRequest.user.ext.consent == null) { + ortbRequest.user.ext.consent = gdpr.consentString; + } } - const schain = deepAccess(validBidRequests[0], 'schain'); + // schain — prefer the ortb2-normalized location (Prebid 9.x writes here + // via the schain core module + schain RTD providers); fall back to the + // legacy bid.schain shape for older wrapper builds. The outbound goes on + // source.schain (OpenRTB 2.6 top-level), which modern adapters consume + // without ext-fishing. + const schain = + deepAccess(bidderRequest, 'ortb2.source.ext.schain') || + deepAccess(bidderRequest, 'ortb2.source.schain') || + deepAccess(validBidRequests[0], 'schain'); if (schain) { - ortbRequest.source = { schain }; + ortbRequest.source = { ...(ortbRequest.source || {}), schain }; } return [{ method: 'POST', - url: ENDPOINT_URL, + url: endpoint, data: ortbRequest, // text/plain avoids the CORS preflight that application/json would // trigger, keeping auction latency down. diff --git a/test/spec/modules/tne_catalystBidAdapter_spec.js b/test/spec/modules/tne_catalystBidAdapter_spec.js index 04056247644..dd0edbc145d 100644 --- a/test/spec/modules/tne_catalystBidAdapter_spec.js +++ b/test/spec/modules/tne_catalystBidAdapter_spec.js @@ -109,34 +109,42 @@ describe('TNE Catalyst Bid Adapter', () => { // isBidRequestValid // ------------------------------------------------------------------------- describe('isBidRequestValid', () => { - it('returns true for a valid bid', () => { + it('returns true for a fully-specified bid', () => { expect(spec.isBidRequestValid(makeBidRequest())).to.equal(true); }); - it('returns false when params is missing', () => { + it('returns true when params is missing entirely', () => { const bid = makeBidRequest(); delete bid.params; - expect(spec.isBidRequestValid(bid)).to.equal(false); + expect(spec.isBidRequestValid(bid)).to.equal(true); }); - it('returns false when publisherId is missing', () => { - const bid = makeBidRequest({ params: { slot: 'billboard' } }); - expect(spec.isBidRequestValid(bid)).to.equal(false); + it('returns true when params is an empty object', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: {} }))).to.equal(true); }); - it('returns false when publisherId is empty string', () => { - const bid = makeBidRequest({ params: { publisherId: '', slot: 'billboard' } }); - expect(spec.isBidRequestValid(bid)).to.equal(false); + it('returns true with only publisherId', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { publisherId: 'NXS003' } }))).to.equal(true); }); - it('returns false when slot is missing', () => { - const bid = makeBidRequest({ params: { publisherId: 'NXS003' } }); - expect(spec.isBidRequestValid(bid)).to.equal(false); + it('returns true with only slot', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { slot: 'billboard' } }))).to.equal(true); }); - it('returns false when slot is empty string', () => { - const bid = makeBidRequest({ params: { publisherId: 'NXS003', slot: '' } }); - expect(spec.isBidRequestValid(bid)).to.equal(false); + it('returns false when publisherId is the wrong type', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { publisherId: 123 } }))).to.equal(false); + }); + + it('returns false when slot is the wrong type', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { slot: 42 } }))).to.equal(false); + }); + + it('returns false when bidfloor is the wrong type', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { bidfloor: 'free' } }))).to.equal(false); + }); + + it('returns false when testMode is the wrong type', () => { + expect(spec.isBidRequestValid(makeBidRequest({ params: { testMode: 'yes' } }))).to.equal(false); }); it('returns false for a null bid', () => { @@ -333,6 +341,159 @@ describe('TNE Catalyst Bid Adapter', () => { }); }); + describe('permissive params (AMX-style)', () => { + it('falls back to adUnitCode when params.slot is absent', () => { + const bid = makeBidRequest({ + params: { publisherId: 'NXS003' }, + adUnitCode: 'div-billboard', + }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].data.imp[0].ext.tne_catalyst.slot).to.equal('div-billboard'); + }); + + it('mirrors the resolved slot into imp.tagid', () => { + const bid = makeBidRequest({ + params: {}, + adUnitCode: 'div-leaderboard', + }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].data.imp[0].tagid).to.equal('div-leaderboard'); + }); + + it('explicit params.slot wins over adUnitCode', () => { + const bid = makeBidRequest({ + params: { slot: 'override-slot' }, + adUnitCode: 'div-billboard', + }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].data.imp[0].ext.tne_catalyst.slot).to.equal('override-slot'); + expect(reqs[0].data.imp[0].tagid).to.equal('override-slot'); + }); + + it('omits site.publisher when publisherId is absent', () => { + const bid = makeBidRequest({ params: { slot: 'billboard' } }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].data.site.publisher).to.be.undefined; + }); + + it('still merges ortb2.site fields when publisherId is absent', () => { + const bid = makeBidRequest({ params: { slot: 'billboard' } }); + const br = makeBidderRequest({ ortb2: { site: { cat: ['IAB1'] } } }); + const reqs = spec.buildRequests([bid], br); + expect(reqs[0].data.site.cat).to.deep.equal(['IAB1']); + expect(reqs[0].data.site.publisher).to.be.undefined; + }); + + it('uses params.endpoint when provided', () => { + const bid = makeBidRequest({ + params: { endpoint: 'https://staging.thenexusengine.com/openrtb2/auction' }, + }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].url).to.equal('https://staging.thenexusengine.com/openrtb2/auction'); + }); + + it('marks the request as test mode when params.testMode is true', () => { + const bid = makeBidRequest({ + params: { publisherId: 'NXS003', slot: 'billboard', testMode: true }, + }); + const reqs = spec.buildRequests([bid], makeBidderRequest()); + expect(reqs[0].data.imp[0].ext.tne_catalyst.testMode).to.equal(true); + }); + + it('does not set testMode flag when params.testMode is absent or false', () => { + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest()); + expect(reqs[0].data.imp[0].ext.tne_catalyst.testMode).to.be.undefined; + }); + }); + + describe('ortb2 passthrough', () => { + it('passes ortb2.user through unchanged', () => { + const ortb2 = { + user: { + eids: [{ source: 'uidapi.com', uids: [{ id: 'uid2-token' }] }], + ext: { consent: 'WRAPPER_CONSENT_STRING' }, + data: [{ name: 'contxtful', segment: [{ id: 'seg-1' }] }] + } + }; + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.user.eids).to.deep.equal(ortb2.user.eids); + expect(reqs[0].data.user.data).to.deep.equal(ortb2.user.data); + expect(reqs[0].data.user.ext.consent).to.equal('WRAPPER_CONSENT_STRING'); + }); + + it('passes ortb2.regs through and preserves gpp/gpp_sid from wrapper', () => { + const ortb2 = { regs: { gpp: 'WRAPPER_GPP', gpp_sid: [7, 8], coppa: 0 } }; + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.regs.gpp).to.equal('WRAPPER_GPP'); + expect(reqs[0].data.regs.gpp_sid).to.deep.equal([7, 8]); + expect(reqs[0].data.regs.coppa).to.equal(0); + }); + + it('passes ortb2.device through unchanged', () => { + const ortb2 = { device: { ua: 'Mozilla/5.0', devicetype: 1, language: 'en' } }; + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.device).to.deep.equal(ortb2.device); + }); + + it('passes ortb2.app through for in-app/CTV traffic', () => { + const ortb2 = { app: { bundle: 'com.example.app', name: 'Example App' } }; + const bid = makeBidRequest({ params: { slot: 'billboard' } }); // omit publisherId + const reqs = spec.buildRequests([bid], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.app).to.deep.equal(ortb2.app); + expect(reqs[0].data.site).to.be.undefined; // app + site are mutually exclusive + }); + + it('stamps explicit params.publisherId onto app.publisher.id', () => { + const ortb2 = { app: { bundle: 'com.example.app' } }; + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.app.publisher).to.deep.equal({ id: 'NXS003' }); + expect(reqs[0].data.site).to.be.undefined; + }); + + it('omits site entirely when ortb2.app is present (OpenRTB site/app mutex)', () => { + const ortb2 = { app: { bundle: 'com.example.app' }, site: { domain: 'should-be-ignored.com' } }; + const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest({ ortb2 })); + expect(reqs[0].data.site).to.be.undefined; + expect(reqs[0].data.app.bundle).to.equal('com.example.app'); + }); + + it('does not override wrapper-set ortb2.user.ext.consent with derived gdprConsent', () => { + const ortb2 = { user: { ext: { consent: 'WRAPPER_WINS' } } }; + const br = makeBidderRequest({ ortb2, gdprConsent: { gdprApplies: true, consentString: 'DERIVED_LOSES' } }); + const reqs = spec.buildRequests([makeBidRequest()], br); + expect(reqs[0].data.user.ext.consent).to.equal('WRAPPER_WINS'); + }); + + it('falls back to derived gdprConsent when ortb2 has no consent', () => { + const br = makeBidderRequest({ gdprConsent: { gdprApplies: true, consentString: 'DERIVED_CONSENT' } }); + const reqs = spec.buildRequests([makeBidRequest()], br); + expect(reqs[0].data.user.ext.consent).to.equal('DERIVED_CONSENT'); + }); + + it('merges legacy bid.userIdAsEids with ortb2.user.eids without duplicates', () => { + const ortb2 = { user: { eids: [{ source: 'uidapi.com', uids: [{ id: 'wrapper-uid2' }] }] } }; + const bid = makeBidRequest({ + userIdAsEids: [ + { source: 'uidapi.com', uids: [{ id: 'legacy-uid2' }] }, // dup source — wrapper wins + { source: 'id5-sync.com', uids: [{ id: 'legacy-id5' }] } // new source — included + ] + }); + const reqs = spec.buildRequests([bid], makeBidderRequest({ ortb2 })); + const eids = reqs[0].data.user.eids; + expect(eids).to.have.length(2); + expect(eids.find(e => e.source === 'uidapi.com').uids[0].id).to.equal('wrapper-uid2'); + expect(eids.find(e => e.source === 'id5-sync.com')).to.exist; + }); + + it('does not override wrapper-set ortb2.regs.gpp with derived gppConsent', () => { + const ortb2 = { regs: { gpp: 'WRAPPER_GPP', gpp_sid: [7] } }; + const br = makeBidderRequest({ ortb2, gppConsent: { gppString: 'DERIVED_GPP', applicableSections: [8] } }); + const reqs = spec.buildRequests([makeBidRequest()], br); + expect(reqs[0].data.regs.gpp).to.equal('WRAPPER_GPP'); + expect(reqs[0].data.regs.gpp_sid).to.deep.equal([7]); + }); + }); + describe('GDPR', () => { it('sets regs.ext.gdpr=1 when gdprApplies is true', () => { const br = makeBidderRequest({ gdprConsent: { gdprApplies: true, consentString: 'CONSENT_STRING' } }); @@ -392,13 +553,29 @@ describe('TNE Catalyst Bid Adapter', () => { }); describe('schain', () => { - it('sets source.schain when schain is present on the bid', () => { + it('sets source.schain when schain is present on the bid (legacy path)', () => { const schain = { ver: '1.0', complete: 1, nodes: [{ asi: 'thenexusengine.io', sid: 'NXS003' }] }; const bid = makeBidRequest({ schain }); const reqs = spec.buildRequests([bid], makeBidderRequest()); expect(reqs[0].data.source.schain).to.deep.equal(schain); }); + it('prefers ortb2.source.ext.schain over legacy bid.schain', () => { + const wrapperSchain = { ver: '1.0', complete: 1, nodes: [{ asi: 'wrapper.com', sid: 'W1' }] }; + const legacySchain = { ver: '1.0', complete: 1, nodes: [{ asi: 'legacy.com', sid: 'L1' }] }; + const bid = makeBidRequest({ schain: legacySchain }); + const br = makeBidderRequest({ ortb2: { source: { ext: { schain: wrapperSchain } } } }); + const reqs = spec.buildRequests([bid], br); + expect(reqs[0].data.source.schain).to.deep.equal(wrapperSchain); + }); + + it('reads ortb2.source.schain (OpenRTB 2.6 top-level) when ext path absent', () => { + const schain = { ver: '1.0', complete: 1, nodes: [{ asi: 'wrapper.com', sid: 'W1' }] }; + const br = makeBidderRequest({ ortb2: { source: { schain } } }); + const reqs = spec.buildRequests([makeBidRequest()], br); + expect(reqs[0].data.source.schain).to.deep.equal(schain); + }); + it('omits source when schain is absent', () => { const reqs = spec.buildRequests([makeBidRequest()], makeBidderRequest()); expect(reqs[0].data.source).to.be.undefined; From d479acb5a2b4299b6a005745a0e43f096d7d0c17 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Thu, 28 May 2026 09:50:55 -0700 Subject: [PATCH 012/124] Core: migrate from deprecated GPT getTargeting/setTargeting to getConfig/setConfig (#14816) * Core: migrate from deprecated GPT getTargeting/setTargeting to getConfig/setConfig * use gptUtils/setKeyValue instead of setPageTargeting when possible; fix incorrect test setup * update types * lint * Add methods to fetch entire targeting map * Update relaido to use getTargetingMap methods * update relaido to use getTargetingMap methods * Update src/utils/gptTargeting.ts Co-authored-by: derdeka * update mock data to use arrays --------- Co-authored-by: derdeka --- libraries/browsiUtils/browsiUtils.js | 3 +- libraries/gptUtils/gptUtils.js | 13 +- .../intentIqUtils/gamPredictionReport.js | 25 +-- modules/imRtdProvider.js | 19 +-- modules/intentIqIdSystem.js | 41 ++--- modules/medianetAnalyticsAdapter.js | 4 +- modules/pubxaiAnalyticsAdapter.js | 3 +- modules/reconciliationRtdProvider.js | 3 +- modules/relaidoBidAdapter.js | 23 +-- modules/sirdataRtdProvider.js | 3 +- src/secureCreatives.js | 5 +- src/targeting.ts | 3 +- src/targeting/lock.ts | 3 +- src/utils/gptTargeting.ts | 76 +++++++++ test/fixtures/fixtures.js | 32 ---- .../libraries/gamPredictionReport_spec.js | 28 ---- test/spec/modules/intentIqIdSystem_spec.js | 1 + test/spec/unit/utils/gptTargeting_spec.js | 156 ++++++++++++++++++ 18 files changed, 296 insertions(+), 145 deletions(-) create mode 100644 src/utils/gptTargeting.ts create mode 100644 test/spec/unit/utils/gptTargeting_spec.js diff --git a/libraries/browsiUtils/browsiUtils.js b/libraries/browsiUtils/browsiUtils.js index 9b520ff53a9..87a1534c2b8 100644 --- a/libraries/browsiUtils/browsiUtils.js +++ b/libraries/browsiUtils/browsiUtils.js @@ -1,5 +1,6 @@ import { isGptPubadsDefined, logError } from '../../src/utils.js'; import { setKeyValue as setGptKeyValue } from '../../libraries/gptUtils/gptUtils.js'; +import { getSlotTargeting } from '../../src/utils/gptTargeting.js'; /** @type {string} */ const VIEWABILITY_KEYNAME = 'browsiViewability'; @@ -234,7 +235,7 @@ export function getMacroId(macro, slot) { if (macro) { try { const macroResult = evaluate(macro, slot.getSlotElementId(), slot.getAdUnitPath(), (match, p1) => { - return (p1 && slot.getTargeting(p1).join('_')) || 'NA'; + return (p1 && getSlotTargeting(slot, p1).join('_')) || 'NA'; }); return macroResult; } catch (e) { diff --git a/libraries/gptUtils/gptUtils.js b/libraries/gptUtils/gptUtils.js index b98b890d35a..0fb36e4510e 100644 --- a/libraries/gptUtils/gptUtils.js +++ b/libraries/gptUtils/gptUtils.js @@ -1,5 +1,6 @@ import { CLIENT_SECTIONS } from '../../src/fpd/oneClient.js'; import { deepAccess, isGptPubadsDefined, uniques, isEmpty, isAdUnitCodeMatchingSlot } from '../../src/utils.js'; +import { setPageTargeting } from '../../src/utils/gptTargeting.js'; const slotInfoCache = new Map(); @@ -25,10 +26,14 @@ export function isSlotMatchingAdUnitCode(adUnitCode) { export function setKeyValue(key, value) { if (!key || typeof key !== 'string') return false; window.googletag = window.googletag || { cmd: [] }; - window.googletag.cmd = window.googletag.cmd || []; - window.googletag.cmd.push(() => { - window.googletag.pubads().setTargeting(key, value); - }); + setKeyValueOn(key, value, window.googletag) +} + +export function setKeyValueOn(key, value, gpt = window.googletag) { + gpt.cmd = gpt.cmd || []; + gpt.cmd.push(() => { + setPageTargeting(key, value, gpt); + }) } /** diff --git a/libraries/intentIqUtils/gamPredictionReport.js b/libraries/intentIqUtils/gamPredictionReport.js index 69a81a8a5e6..0533b887e4f 100644 --- a/libraries/intentIqUtils/gamPredictionReport.js +++ b/libraries/intentIqUtils/gamPredictionReport.js @@ -1,5 +1,6 @@ import { getEvents } from '../../src/events.js'; -import { isPlainObject, logError } from '../../src/utils.js'; +import { logError } from '../../src/utils.js'; +import { getSlotTargetingMap } from '../../src/utils/gptTargeting.js'; export function gamPredictionReport (gamObjectReference, sendData) { try { @@ -8,30 +9,12 @@ export function gamPredictionReport (gamObjectReference, sendData) { return } const getSlotTargeting = (slot) => { - const kvs = {}; try { - if (typeof slot.getConfig === 'function') { - const current = slot.getConfig('targeting'); - const targeting = isPlainObject(current?.targeting) - ? current.targeting - : (isPlainObject(current) ? current : {}); - for (const k in targeting) { - const v = targeting[k]; - if (v == null) continue; - kvs[k] = Array.isArray(v) ? v : [typeof v === 'string' ? v : String(v)]; - } - return kvs; - } - // Fallback in case an older version of Google Publisher Tag is used. - if (typeof slot.getTargetingKeys === 'function' && typeof slot.getTargeting === 'function') { - (slot.getTargetingKeys() || []).forEach((k) => { - kvs[k] = slot.getTargeting(k); - }); - } + return getSlotTargetingMap(slot); } catch (e) { logError('Failed to get slot targeting: ' + e); + return {} } - return kvs; }; const extractWinData = (gamEvent) => { diff --git a/modules/imRtdProvider.js b/modules/imRtdProvider.js index 5052b4c12a6..6da22eeab78 100644 --- a/modules/imRtdProvider.js +++ b/modules/imRtdProvider.js @@ -6,19 +6,12 @@ */ import { ajax } from '../src/ajax.js'; import { config } from '../src/config.js'; -import { getGlobal } from '../src/prebidGlobal.js' +import { getGlobal } from '../src/prebidGlobal.js'; import { getStorageManager } from '../src/storageManager.js'; -import { - deepSetValue, - deepAccess, - timestamp, - mergeDeep, - logError, - logInfo, - isFn -} from '../src/utils.js' +import { deepAccess, deepSetValue, isFn, logError, logInfo, mergeDeep, timestamp } from '../src/utils.js'; import { submodule } from '../src/hook.js'; import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; +import { setKeyValue } from '../libraries/gptUtils/gptUtils.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -112,11 +105,7 @@ export function setRealTimeData(bidConfig, moduleConfig, data) { deepSetValue(ortb2, 'user.ext.data.im_uid', data.im_uid); if (moduleConfig.params.setGptKeyValues || !moduleConfig.params.hasOwnProperty('setGptKeyValues')) { - window.googletag = window.googletag || { cmd: [] }; - window.googletag.cmd = window.googletag.cmd || []; - window.googletag.cmd.push(() => { - window.googletag.pubads().setTargeting('im_segments', segments); - }); + setKeyValue('im_segments', segments) } } diff --git a/modules/intentIqIdSystem.js b/modules/intentIqIdSystem.js index c064719ae88..eac6867ab71 100644 --- a/modules/intentIqIdSystem.js +++ b/modules/intentIqIdSystem.js @@ -5,28 +5,40 @@ * @requires module:modules/userId */ -import { logError, isPlainObject, isStr, isNumber } from '../src/utils.js'; +import { isNumber, isPlainObject, isStr, logError } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; -import { submodule } from '../src/hook.js' +import { submodule } from '../src/hook.js'; import { detectBrowser } from '../libraries/intentIqUtils/detectBrowserUtils.js'; import { appendSPData } from '../libraries/intentIqUtils/urlUtils.js'; -import { isCHSupported } from '../libraries/intentIqUtils/chUtils.js' +import { isCHSupported } from '../libraries/intentIqUtils/chUtils.js'; import { appendVrrefAndFui } from '../libraries/intentIqUtils/getRefferer.js'; import { getCmpData } from '../libraries/intentIqUtils/getCmpData.js'; -import { readData, storeData, defineStorageType, removeDataByKey, tryParse } from '../libraries/intentIqUtils/storageUtils.js'; import { - FIRST_PARTY_KEY, + defineStorageType, + readData, + removeDataByKey, + storeData, + tryParse +} from '../libraries/intentIqUtils/storageUtils.js'; +import { + CH_KEYS, CLIENT_HINTS_KEY, EMPTY, + FIRST_PARTY_KEY, GVLID, - VERSION, INVALID_ID, SYNC_REFRESH_MILL, META_DATA_CONSTANT, PREBID, - HOURS_72, CH_KEYS + HOURS_72, + INVALID_ID, + META_DATA_CONSTANT, + PREBID, + SYNC_REFRESH_MILL, + VERSION } from '../libraries/intentIqConstants/intentIqConstants.js'; import { SYNC_KEY } from '../libraries/intentIqUtils/getSyncKey.js'; -import { iiqPixelServerAddress, getIiqServerAddress } from '../libraries/intentIqUtils/intentIqConfig.js'; +import { getIiqServerAddress, iiqPixelServerAddress } from '../libraries/intentIqUtils/intentIqConfig.js'; import { handleAdditionalParams } from '../libraries/intentIqUtils/handleAdditionalParams.js'; import { decryptData, encryptData } from '../libraries/intentIqUtils/cryptionUtils.js'; import { defineABTestingGroup } from '../libraries/intentIqUtils/defineABTestingGroupUtils.js'; +import { setKeyValueOn } from '../libraries/gptUtils/gptUtils.js'; /** * @typedef {import('../modules/userId/index.js').Submodule} Submodule @@ -207,18 +219,7 @@ function sendSyncRequest(allowedStorage, url, partner, firstPartyData, newUser) export function setGamReporting(gamObjectReference, gamParameterName, userGroup, isBlacklisted = false) { if (isBlacklisted) return; if (isPlainObject(gamObjectReference) && gamObjectReference.cmd) { - gamObjectReference.cmd.push(() => { - if (typeof gamObjectReference.setConfig === 'function') { - gamObjectReference.setConfig({ - targeting: { - [gamParameterName]: userGroup - } - }); - return; - } - // Fallback in case an older version of Google Publisher Tag is used. - gamObjectReference?.pubads?.()?.setTargeting?.(gamParameterName, userGroup); - }); + setKeyValueOn(gamParameterName, userGroup, gamObjectReference); } } diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index c503d496323..12959bda3ef 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -65,6 +65,7 @@ import { WINNING_BID_ABSENT_ERROR, ERROR_IWB_BID_MISSING, POST_ENDPOINT_RA } from '../libraries/medianetUtils/constants.js'; import { getGlobal } from '../src/prebidGlobal.js'; +import { getSlotTargetingKeys } from '../src/utils/gptTargeting.js'; // General Constants const ADAPTER_CODE = 'medianetAnalytics'; @@ -549,8 +550,7 @@ function setupSlotResponseReceivedListener() { mnetGlobals.infoByAdIdMap[adId] = mnetGlobals.infoByAdIdMap[adId] || {}; mnetGlobals.infoByAdIdMap[adId].srrEvt = slotInf; }; - - slot.getTargetingKeys() + getSlotTargetingKeys(slot) .filter((key) => key.startsWith(TARGETING_KEYS.AD_ID)) .forEach((key) => setSlotResponseInf(slot.getTargeting(key)[0])); }); diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index 6becd6e73b2..03749dc9ec1 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -12,6 +12,7 @@ import { getStorageManager } from '../src/storageManager.js'; import { deepAccess, parseSizesInput, getWindowLocation, buildUrl, cyrb53Hash } from '../src/utils.js'; +import { getSlotTargeting } from '../src/utils/gptTargeting.js'; let initOptions; @@ -106,7 +107,7 @@ const getAdServerDataForBid = (bid) => { key.startsWith('pubx-') || (key.startsWith('hb_') && (key.match(/_/g) || []).length === 1) ) - .map((key) => [key, gptSlot.getTargeting(key)]) + .map((key) => [key, getSlotTargeting(gptSlot, key)]) ); } return {}; // TODO: support more ad servers diff --git a/modules/reconciliationRtdProvider.js b/modules/reconciliationRtdProvider.js index 11074b9a286..631a4730075 100644 --- a/modules/reconciliationRtdProvider.js +++ b/modules/reconciliationRtdProvider.js @@ -19,6 +19,7 @@ import { submodule } from '../src/hook.js'; import { ajaxBuilder } from '../src/ajax.js'; import { generateUUID, isGptPubadsDefined, logError, timestamp } from '../src/utils.js'; +import { getSlotTargeting } from '../src/utils/gptTargeting.js'; /** * @typedef {import('../modules/rtdModule/index.js').RtdSubmodule} RtdSubmodule @@ -65,7 +66,7 @@ function handleAdMessage(e) { // 3. Get AdUnit IDs for the selected slot if (adSlot) { adUnitId = adSlot.getAdUnitPath(); - adDeliveryId = adSlot.getTargeting('RSDK_ADID'); + adDeliveryId = getSlotTargeting(adSlot, 'RSDK_ADID'); adDeliveryId = adDeliveryId.length ? adDeliveryId[0] : `${timestamp()}-${generateUUID()}`; diff --git a/modules/relaidoBidAdapter.js b/modules/relaidoBidAdapter.js index 2423bf69149..abb44c21d85 100644 --- a/modules/relaidoBidAdapter.js +++ b/modules/relaidoBidAdapter.js @@ -1,14 +1,14 @@ import { deepAccess, - logWarn, - parseQueryStringParameters, - triggerPixel, generateUUID, + getBidIdParameter, isArray, + isGptPubadsDefined, isNumber, + logWarn, + parseQueryStringParameters, parseSizesInput, - getBidIdParameter, - isGptPubadsDefined + triggerPixel } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { BANNER, VIDEO } from '../src/mediaTypes.js'; @@ -16,6 +16,7 @@ import { Renderer } from '../src/Renderer.js'; import { getStorageManager } from '../src/storageManager.js'; import sha1 from 'crypto-js/sha1'; import { isSlotMatchingAdUnitCode } from '../libraries/gptUtils/gptUtils.js'; +import { getPageTargetingMap, getSlotTargetingMap } from '../src/utils/gptTargeting.js'; const BIDDER_CODE = 'relaido'; const BIDDER_DOMAIN = 'api.relaido.jp'; @@ -369,19 +370,11 @@ function getTargeting(bidRequest) { const targetings = {}; const pubads = getPubads(); if (pubads) { - const keys = pubads.getTargetingKeys(); - for (const key of keys) { - const values = pubads.getTargeting(key); - targetings[key] = values; - } + Object.assign(targetings, getPageTargetingMap()) } const adUnitSlot = getAdUnit(bidRequest.adUnitCode); if (adUnitSlot) { - const keys = adUnitSlot.getTargetingKeys(); - for (const key of keys) { - const values = adUnitSlot.getTargeting(key); - targetings[key] = values; - } + Object.assign(targetings, getSlotTargetingMap(adUnitSlot)); } return targetings; } diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 77c6f939a95..9072d92f849 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -18,6 +18,7 @@ import { getRefererInfo } from '../src/refererDetection.js'; import { getStorageManager } from '../src/storageManager.js'; import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; import { submodule } from '../src/hook.js'; +import { setSlotTargeting } from '../src/utils/gptTargeting.js'; /** @type {string} */ const MODULE_NAME = 'realTimeData'; @@ -674,7 +675,7 @@ export function addSegmentData(reqBids, data, adUnits, onDone) { window.googletag.cmd.push(() => { window.googletag.pubads().getSlots().forEach(slot => { if (typeof slot.setTargeting !== 'undefined' && sirdataMergedList.length > 0) { - slot.setTargeting('sd_rtd', sirdataMergedList); + setSlotTargeting(slot, 'sd_rtd', sirdataMergedList); } }); }); diff --git a/src/secureCreatives.js b/src/secureCreatives.js index f87b3af3ac4..90be280ed2a 100644 --- a/src/secureCreatives.js +++ b/src/secureCreatives.js @@ -17,6 +17,7 @@ import { getCreativeRendererSource, PUC_MIN_VERSION } from './creativeRenderers. import { PbPromise } from './utils/promise.js'; import { getAdUnitElement } from './utils/adUnits.js'; import { auctionManager } from './auctionManager.js'; +import { getSlotTargetingKeys, getSlotTargeting } from './utils/gptTargeting.js'; const { REQUEST, RESPONSE, NATIVE, EVENT } = MESSAGES; @@ -210,8 +211,8 @@ export function resizeRemoteCreative({ instl, element, adId, adUnitCode, width, function getDfpElementId(adId) { const slot = window.googletag.pubads().getSlots().find(slot => { - return slot.getTargetingKeys().find(key => { - return slot.getTargeting(key).includes(adId); + return getSlotTargetingKeys(slot).find(key => { + return getSlotTargeting(slot, key).includes(adId); }); }); return slot ? slot.getSlotElementId() : null; diff --git a/src/targeting.ts b/src/targeting.ts index 5d36ddc8e65..83b2b421091 100644 --- a/src/targeting.ts +++ b/src/targeting.ts @@ -25,6 +25,7 @@ import type { AdUnitCode, ByAdUnit, Identifier } from './types/common.d.ts'; import type { DefaultTargeting } from './auction.ts'; import { lock } from "./targeting/lock.ts"; import { isBidUsable } from './targeting/filters.ts'; +import { updateSlotTargetingFromMap } from "./utils/gptTargeting.ts"; var pbTargetingKeys = []; @@ -306,7 +307,7 @@ export function newTargeting(auctionManager) { targeting[targetId][key] = value; }); logMessage(`Attempting to ${operation} targeting-map for slot: ${slot.getSlotElementId()} with targeting-map:`, targeting[targetId]); - slot.updateTargetingFromMap(Object.assign({}, resetMap, targeting[targetId])) + updateSlotTargetingFromMap(slot, Object.assign({}, resetMap, targeting[targetId])); if (postUpdate != null) postUpdate(targeting[targetId]); }) }) diff --git a/src/targeting/lock.ts b/src/targeting/lock.ts index f88a2b1c40c..90a7985365e 100644 --- a/src/targeting/lock.ts +++ b/src/targeting/lock.ts @@ -3,6 +3,7 @@ import { config } from "../config.ts"; import { ttlCollection } from "../utils/ttlCollection.ts"; import { isGptPubadsDefined } from "../utils.js"; import SlotRenderEndedEvent = googletag.events.SlotRenderEndedEvent; +import { getSlotTargeting } from "../utils/gptTargeting.ts"; const DEFAULT_LOCK_TIMEOUT = 3000; @@ -45,7 +46,7 @@ export function targetingLock() { const [setupGpt, tearDownGpt] = (() => { let enabled = false; function onGptRender({ slot }: SlotRenderEndedEvent) { - keys?.forEach(key => slot.getTargeting(key)?.forEach(locked.delete)); + keys?.forEach(key => getSlotTargeting(slot, key)?.forEach(locked.delete)); } return [ () => { diff --git a/src/utils/gptTargeting.ts b/src/utils/gptTargeting.ts new file mode 100644 index 00000000000..47a76727a8f --- /dev/null +++ b/src/utils/gptTargeting.ts @@ -0,0 +1,76 @@ +// shim for the deprecation of GPT setTargeting / getTargeting methods + +/** + * The new config API on gpt and Slot we assume with the hasConfigApi typeguard. + */ +interface ConfigApi { + getConfig(key: string): { targeting?: Record }; + setConfig(config: { targeting: Record }): void; +} + +/** + * Typeguard to check if the target has the new GPT config API (getConfig/setConfig). + */ +function hasConfigApi(target: unknown): target is ConfigApi { + // look for getConfig still, as setConfig was there before the deprecation + return typeof (target as ConfigApi).getConfig === 'function'; +} + +function getTargetingConfig(target: ConfigApi): Record { + return target.getConfig('targeting').targeting ?? {}; +} + +export function updateSlotTargetingFromMap(slot: googletag.Slot, targeting: Record): void { + if (hasConfigApi(slot)) { + slot.setConfig({ targeting }); + } else { + slot.updateTargetingFromMap(targeting); + } +} + +export function getPageTargetingMap(gpt = googletag): Record { + if (hasConfigApi(gpt)) return getTargetingConfig(gpt); + const pubads = gpt.pubads(); + return Object.fromEntries(pubads.getTargetingKeys().map(key => [key, pubads.getTargeting(key)])); +} + +export function getSlotTargetingMap(slot: googletag.Slot): Record { + if (hasConfigApi(slot)) return getTargetingConfig(slot); + return Object.fromEntries(slot.getTargetingKeys().map(key => [key, slot.getTargeting(key)])); +} + +export function getPageTargetingKeys(gpt = googletag): string[] { + if (hasConfigApi(gpt)) return Object.keys(getTargetingConfig(gpt)); + return gpt.pubads().getTargetingKeys(); +} + +export function getPageTargeting(key: string, gpt = googletag): string[] { + if (hasConfigApi(gpt)) return getTargetingConfig(gpt)[key] ?? []; + return gpt.pubads().getTargeting(key); +} + +export function setPageTargeting(key: string, value: string | string[], gpt = googletag) { + if (hasConfigApi(gpt)) { + gpt.setConfig({ targeting: { [key]: value } }); + } else { + gpt.pubads().setTargeting(key, value); + } +} + +export function setSlotTargeting(slot: googletag.Slot, key: string, value: string | string[]): void { + if (hasConfigApi(slot)) { + slot.setConfig({ targeting: { [key]: value } }); + } else { + slot.setTargeting(key, value); + } +} + +export function getSlotTargeting(slot: googletag.Slot, key: string): string[] { + if (hasConfigApi(slot)) return getTargetingConfig(slot)[key] ?? []; + return slot.getTargeting(key); +} + +export function getSlotTargetingKeys(slot: googletag.Slot): string[] { + if (hasConfigApi(slot)) return Object.keys(getTargetingConfig(slot)); + return slot.getTargetingKeys(); +} diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index 7adcfdc3dbb..c410f598359 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -616,38 +616,6 @@ export function getBidResponses() { ]; } -export function getSlotTargeting() { - return { - '/19968336/header-bid-tag-0': [ - convertTargetingsFromOldToNew({ - 'hb_bidder': [ - 'appnexus' - ] - }), - convertTargetingsFromOldToNew({ - 'hb_adid': [ - '233bcbee889d46d' - ] - }), - convertTargetingsFromOldToNew({ - 'hb_pb': [ - '10.00' - ] - }), - convertTargetingsFromOldToNew({ - 'hb_size': [ - '300x250' - ] - }), - { - 'foobar': [ - '300x250' - ] - } - ] - }; -} - export function getAdUnits() { return [ { diff --git a/test/spec/libraries/gamPredictionReport_spec.js b/test/spec/libraries/gamPredictionReport_spec.js index 65690f9ccd3..46de582b844 100644 --- a/test/spec/libraries/gamPredictionReport_spec.js +++ b/test/spec/libraries/gamPredictionReport_spec.js @@ -50,20 +50,6 @@ describe('gamPredictionReport', function () { expect(sendData.firstCall.args[0].bidderCode).to.equal('test'); }); - it('reads targeting from slot.getConfig flat object', () => { - const sendData = sinon.spy(); - const slot = { - getConfig: sinon.stub().withArgs('targeting').returns({ hb_bidder: ['flat'] }), - getSlotElementId: () => 'div-2', - getAdUnitPath: () => '/456' - }; - - runWithSlot(slot, sendData); - - expect(sendData.calledOnce).to.equal(true); - expect(sendData.firstCall.args[0].bidderCode).to.equal('flat'); - }); - it('reads targeting from legacy slot.getTargeting APIs when getConfig is missing', () => { const sendData = sinon.spy(); const slot = { @@ -81,20 +67,6 @@ describe('gamPredictionReport', function () { expect(slot.getTargeting.calledOnce).to.equal(true); }); - it('coerces non-array targeting values to string arrays', () => { - const sendData = sinon.spy(); - const slot = { - getConfig: sinon.stub().withArgs('targeting').returns({ targeting: { hb_bidder: 42 } }), - getSlotElementId: () => 'div-4', - getAdUnitPath: () => '/101' - }; - - runWithSlot(slot, sendData); - - expect(sendData.calledOnce).to.equal(true); - expect(sendData.firstCall.args[0].bidderCode).to.equal('42'); - }); - it('logs and recovers when legacy targeting APIs throw', () => { const sendData = sinon.spy(); const slot = { diff --git a/test/spec/modules/intentIqIdSystem_spec.js b/test/spec/modules/intentIqIdSystem_spec.js index 61f87168ac8..09afe274450 100644 --- a/test/spec/modules/intentIqIdSystem_spec.js +++ b/test/spec/modules/intentIqIdSystem_spec.js @@ -226,6 +226,7 @@ describe('IntentIQ tests', function () { const pubadsSetTargetingSpy = sinon.spy(); const mockGAM = { cmd: [], + getConfig: sinon.stub(), setConfig: setConfigSpy, pubads: () => ({ setTargeting: pubadsSetTargetingSpy diff --git a/test/spec/unit/utils/gptTargeting_spec.js b/test/spec/unit/utils/gptTargeting_spec.js new file mode 100644 index 00000000000..963ebaad4f4 --- /dev/null +++ b/test/spec/unit/utils/gptTargeting_spec.js @@ -0,0 +1,156 @@ +import { + getPageTargeting, + getPageTargetingKeys, getPageTargetingMap, + getSlotTargeting, + getSlotTargetingKeys, getSlotTargetingMap, setPageTargeting, + setSlotTargeting, +} from '../../../../src/utils/gptTargeting.js'; + +describe('gpt targeting shim', () => { + let mockGam; + beforeEach(() => { + mockGam = {}; + }); + describe('when getConfig/setConfig is defined', () => { + let targetingConfig; + beforeEach(() => { + targetingConfig = undefined; + mockGam.getConfig = sinon.stub().callsFake((k) => { + if (k === 'targeting') { + return { targeting: targetingConfig }; + } else { + return {}; + } + }); + mockGam.setConfig = sinon.stub(); + }); + Object.entries({ + getPageTargetingKeys, + getSlotTargetingKeys + }).forEach(([name, fn]) => { + describe(name, () => { + it('returns an empty list when no targeting config is found', () => { + expect(fn(mockGam)).to.eql([]); + }); + it('returns keys from getConfig("targeting")', () => { + targetingConfig = { k1: ['v1'], k2: ['v2'] }; + expect(fn(mockGam)).to.eql(['k1', 'k2']); + }); + }); + }); + Object.entries({ + getPageTargeting: (target, key) => getPageTargeting(key, target), + getSlotTargeting + }).forEach(([name, fn]) => { + describe(name, () => { + it('returns an empty list when no targeting config is found', () => { + expect(fn(mockGam, 'key')).to.eql([]); + }); + it('returns the value from config otherwise', () => { + targetingConfig = { key: ['value'] }; + expect(fn(mockGam, 'key')).to.eql(['value']); + }); + }); + }); + + Object.entries({ + getPageTargetingMap, + getSlotTargetingMap + }).forEach(([name, fn]) => { + describe(name, () => { + it('returns an empty map when no targeting config is found', () => { + expect(fn(mockGam)).to.eql({}); + }); + it('returns the value from config otherwise', () => { + targetingConfig = { key: ['value'] }; + expect(fn(mockGam)).to.eql({ key: ['value'] }); + }) + }) + }) + + Object.entries({ + setPageTargeting: (target, key, value) => setPageTargeting(key, value, target), + setSlotTargeting, + }).forEach(([name, fn]) => { + describe(name, () => { + it('calls setConfig', () => { + fn(mockGam, 'key', 'value'); + sinon.assert.calledWith(mockGam.setConfig, { targeting: { 'key': 'value' } }); + }) + }) + }) + }); + + describe('when getConfig/setConfig is not defined', () => { + let pubads, mockSlot; + beforeEach(() => { + pubads = {}; + mockGam.pubads = () => pubads; + mockSlot = {}; + }); + + it('getPageTargetingKeys calls pubads.getTargetingKeys', () => { + pubads.getTargetingKeys = () => ['passthrough']; + expect(getPageTargetingKeys(mockGam)).to.eql(['passthrough']); + }); + it('getSlotTargetingKeys calls slot.getTargetingKeys', () => { + mockSlot.getTargetingKeys = () => ['passthrough']; + expect(getSlotTargetingKeys(mockSlot)).to.eql(['passthrough']); + }); + it('getPageTargeting calls pubads.getTargeting', () => { + pubads.getTargeting = (key) => [`passthrough-${key}`]; + expect(getPageTargeting('k', mockGam)).to.eql(['passthrough-k']); + }); + it('getSlotTargeting calls slot.getTargeting', () => { + mockSlot.getTargeting = (key) => [`passthrough-${key}`]; + expect(getSlotTargeting(mockSlot, 'k')).to.eql(['passthrough-k']); + }); + + it('setPageTargeting calls pubads.setTargeting', () => { + pubads.setTargeting = sinon.stub(); + setPageTargeting('key', 'value', mockGam); + sinon.assert.calledWith(pubads.setTargeting, 'key', 'value'); + }); + + it('setSlotTargeting calls slot.setTargeting', () => { + mockSlot.setTargeting = sinon.stub(); + setSlotTargeting(mockSlot, 'key', 'value'); + sinon.assert.calledWith(mockSlot.setTargeting, 'key', 'value'); + }); + + Object.entries({ + getPageTargetingMap: { + fn: getPageTargetingMap, + arg: () => mockGam, + mock: () => pubads + }, + getSlotTargetingMap: { + fn: getSlotTargetingMap, + arg: () => mockSlot, + mock: () => mockSlot + } + }).forEach(([name, { fn, arg, mock }]) => { + describe(name, () => { + it('calls getTargeting on each key from getTargetingkeys', () => { + Object.assign(mock(), { + getTargetingKeys: () => ['k1', 'k2'], + getTargeting: (key) => [`${key}value`] + }); + expect(fn(arg())).to.eql({ + k1: ['k1value'], + k2: ['k2value'] + }); + }); + }); + }) + + it('getSlotTargetingMap calls slot.getTargeting on each key from slot.getTargetingKeys', () => { + mockSlot.getTargetingKeys = () => ['k1', 'k2']; + mockSlot.getTargeting = (key) => [`${key}value`]; + expect(getSlotTargetingMap(mockSlot)).to.eql({ + k1: ['k1value'], + k2: ['k2value'] + }); + }) + }); +}); From 761f2055f727ac604d801d3108ee37061e2226ee Mon Sep 17 00:00:00 2001 From: 152Media <54035983+152Media@users.noreply.github.com> Date: Fri, 29 May 2026 09:40:58 -0300 Subject: [PATCH 013/124] Removed alias from appnexus and add it to microsoft adapter (#14965) Co-authored-by: Andy --- libraries/appnexusUtils/anUtils.js | 1 - modules/msftBidAdapter.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/appnexusUtils/anUtils.js b/libraries/appnexusUtils/anUtils.js index 191512f2fea..ce0dd3196b3 100644 --- a/libraries/appnexusUtils/anUtils.js +++ b/libraries/appnexusUtils/anUtils.js @@ -17,7 +17,6 @@ export const appnexusAliases = [ { code: 'newdream', gvlid: 32 }, { code: 'matomy', gvlid: 32 }, { code: 'featureforward', gvlid: 32 }, - { code: 'oftmedia', gvlid: 32 }, { code: 'adasta', gvlid: 32 }, { code: 'beintoo', gvlid: 618 }, { code: 'projectagora', gvlid: 1032 }, diff --git a/modules/msftBidAdapter.js b/modules/msftBidAdapter.js index cbb4d5e9986..9cccf5804b9 100644 --- a/modules/msftBidAdapter.js +++ b/modules/msftBidAdapter.js @@ -315,7 +315,7 @@ const converter = ortbConverter({ export const spec = { code: BIDDER_CODE, gvlid: GVLID, - aliases: [], // TODO fill in after full transition or as seperately requested + aliases: [{ code: 'oftmedia', gvlid: 32 }], // TODO fill in after full transition or as seperately requested supportedMediaTypes: [BANNER, NATIVE, VIDEO], isBidRequestValid: (bid) => { From 5d9faa3cb60d2f9793c00d326356f047c82a7325 Mon Sep 17 00:00:00 2001 From: Eugene Dorfman Date: Sat, 30 May 2026 04:37:02 +0200 Subject: [PATCH 014/124] 51Degrees RTD: enrich ORTB with IP/geo, 51DiD eids, preference/TCF/GPP consent forwarding (#14914) * 51Degrees RTD: enrich ORTB with IP/geo, 51DiD eids, and PMP-aware id.usage Adds device.ip/ipv6/geo from the cloud ip vendor, a 51d.es user.eids entry from fodid, and id.usage forwarding sourced from module params or PMP localStorage. * configure PMP in the example * proper casing * improve example with debug bids * set device.geo.region * reload PMP button * correct shape of user.eids[].uids * guard publisher set device.ip * warn on legacy ext.fiftyonedegrees_deviceId write The module writes the 51Degrees device id to both ortb2.device.ext.fod.deviceId (canonical) and ortb2.device.ext.fiftyonedegrees_deviceId (legacy mirror kept for adapters that read the older path, e.g. gumgumBidAdapter). Emit a one-shot logWarn the first time the legacy mirror is written so adapter authors can spot the duplication and migrate. Output is unchanged. * populate geo if locationconfidence is high/medium also set correct ipservice value * 51Degrees RTD: forward TCF/GPP consent strings to the cloud as evidence * update doc * update doc and remove params.idUsage * update configurator link * fix lint errors * migrate consumers to ext.fod.deviceId (formerly fiftyonedegrees_deviceId) --------- Co-authored-by: YaroslavVlasenko Co-authored-by: James Rosewell --- .../gpt/51DegreesRtdProvider_example.html | 212 +++++--- modules/51DegreesRtdProvider.js | 227 ++++++++- modules/51DegreesRtdProvider.md | 35 +- modules/gumgumBidAdapter.js | 2 +- .../spec/modules/51DegreesRtdProvider_spec.js | 476 +++++++++++++++++- test/spec/modules/gumgumBidAdapter_spec.js | 4 +- 6 files changed, 858 insertions(+), 98 deletions(-) diff --git a/integrationExamples/gpt/51DegreesRtdProvider_example.html b/integrationExamples/gpt/51DegreesRtdProvider_example.html index 1fcfa6df087..7a93168c5d3 100644 --- a/integrationExamples/gpt/51DegreesRtdProvider_example.html +++ b/integrationExamples/gpt/51DegreesRtdProvider_example.html @@ -1,6 +1,28 @@ + @@ -38,28 +60,12 @@ pbjs.initAdserverSet = true; } - pbjs.que.push(function () { - var adUnits = [{ - code: 'div-banner-native-1', - mediaTypes: { - banner: { - sizes: [ - [300, 250] - ] - }, - native: { - type: 'image' - }, - }, - bids: [{ - bidder: 'appnexus', - params: { - placementId: 13232392, - } - }] - }, - { - code: 'div-banner-native-2', + window.startPrebid = function () { + if (window.__prebidStarted) return; + window.__prebidStarted = true; + pbjs.que.push(function () { + var adUnits = [{ + code: 'div-banner-native-1', mediaTypes: { banner: { sizes: [ @@ -67,16 +73,8 @@ ] }, native: { - title: { - required: true - }, - image: { - required: true - }, - sponsoredBy: { - required: true - } - } + type: 'image' + }, }, bids: [{ bidder: 'appnexus', @@ -84,48 +82,96 @@ placementId: 13232392, } }] - } - ]; - - pbjs.setConfig({ - debug: true, // use only for testing, remove in production - realTimeData: { - auctionDelay: 1000, // should be set lower in production use - dataProviders: [ - { - name: '51Degrees', - waitForIt: true, + }, + { + code: 'div-banner-native-2', + mediaTypes: { + banner: { + sizes: [ + [300, 250] + ] + }, + native: { + title: { + required: true + }, + image: { + required: true + }, + sponsoredBy: { + required: true + } + } + }, + bids: [{ + bidder: 'appnexus', params: { - // Get your resource key from https://configure.51degrees.com/HNZ75HT1 - resourceKey: '', - // alternatively, you can use the on-premise version of the 51Degrees service and connect to your chosen end point - // onPremiseJSUrl: 'https://localhost/51Degrees.core.js' + placementId: 13232392, } - } - ] - }, - }); + }] + } + ]; + + pbjs.setConfig({ + debug: true, // verbose logging + debugging: { + enabled: true, // activates the debugging-module bid interceptor + intercept: [{ + when: { bidder: 'appnexus' }, + then: { + cpm: 1.50, + currency: 'USD', + ttl: 300, + creativeId: 'mock-creative', + netRevenue: true, + mediaType: 'banner', + width: 300, + height: 250, + ad: '
Mock bid $1.50
' + } + }] + }, + realTimeData: { + auctionDelay: 1000, // should be set lower in production use + dataProviders: [ + { + name: '51Degrees', + waitForIt: true, + params: { + resourceKey: RESOURCE_KEY, + // tdlUrl populates user.eids[].ext.tdl per data labels spec. + // Replace with your real TDL endpoint. + tdlUrl: 'https://tdl.example/replace-me', + // alternatively, you can use the on-premise version of the 51Degrees service and connect to your chosen end point + // onPremiseJSUrl: 'https://localhost/51Degrees.core.js' + } + } + ] + }, + }); - pbjs.addAdUnits(adUnits); + pbjs.addAdUnits(adUnits); - pbjs.onEvent('bidRequested', function (data) { - try { - fod.complete(() => { - document.getElementById('enriched-51').style.display = 'block'; - document.getElementById('enriched-51-data').textContent = JSON.stringify(data.ortb2.device, null, 2); + pbjs.onEvent('bidRequested', function (data) { + try { + fod.complete(() => { + document.getElementById('enriched-51').style.display = 'block'; + document.getElementById('enriched-51-data').textContent = JSON.stringify(data.ortb2.device, null, 2); + document.getElementById('enriched-51-eids').textContent = JSON.stringify(data.ortb2.user?.eids || [], null, 2); + }); + } catch (e) { + console.error('Error while trying to display enriched data', e); + } }); - } catch (e) { - console.error('Error while trying to display enriched data', e); - } - }); - pbjs.requestBids({ - timeout: PREBID_TIMEOUT, - bidsBackHandler: function (bidResponses) { - initAdserver(); - } + pbjs.requestBids({ + timeout: PREBID_TIMEOUT, + bidsBackHandler: function (bidResponses) { + initAdserver(); + } + }); }); - }); + }; setTimeout(initAdserver, FAILSAFE_TIMEOUT); @@ -161,6 +207,30 @@

51Degrees RTD submodule - example of usage

+
+ + + + — or pass ?resourceKey=... in the URL. +
+ +

div-banner-native-1

No response

@@ -186,14 +256,18 @@

Testing/Debugging Guidance

  1. Make sure you have debug: true under pbjs.setConfig in this example code (be sure to remove it for production!)
  2. Make sure you have replaced <YOUR RESOURCE KEY> in this example code with the one you have obtained - from the 51Degrees Configurator Tool
  3. + from the 51Degrees Configurator Tool +
  4. Replace the placeholder tdlUrl in the example with your real TDL endpoint
  5. +
  6. Pick a marketing preference in the PMP CMP overlay when it appears; the module reads localStorage['__51d_pmp_pref'] to derive the cloud's id.usage evidence
  7. Open DevTools Console in your browser and refresh the page
  8. -
  9. Observe the enriched ortb device data shown below and also in the console as part of the [51Degrees RTD Submodule]: reqBidsConfigObj: message (under reqBidsConfigObj.global.device)
  10. +
  11. Observe the enriched ORTB shown below: device, device.geo, and user.eids. Also check the console for [51Degrees RTD Submodule]: reqBidsConfigObj:
diff --git a/modules/51DegreesRtdProvider.js b/modules/51DegreesRtdProvider.js index dbdf10515ef..9773624d6a8 100644 --- a/modules/51DegreesRtdProvider.js +++ b/modules/51DegreesRtdProvider.js @@ -1,6 +1,7 @@ import { MODULE_TYPE_RTD } from '../src/activities/modules.js'; import { loadExternalScript } from '../src/adloader.js'; import { submodule } from '../src/hook.js'; +import { getStorageManager } from '../src/storageManager.js'; import { deepAccess, deepSetValue, @@ -111,6 +112,8 @@ export const extractConfig = (moduleConfig, reqBidsConfigObj) => { * @param {string} [pathData.resourceKey] Resource key * @param {string} [pathData.onPremiseJSUrl] On-premise JS URL * @param {Object} [pathData.hev] High entropy values + * @param {string} [pathData.tcString] TCF consent string to forward as tcstring + * @param {string} [pathData.gpp] GPP string to forward as gppstring * @param {Window} [win] Window object (mainly for testing) * @returns {string} 51Degrees JS URL */ @@ -129,6 +132,16 @@ export const get51DegreesJSURL = (pathData, win) => { deepSetNotEmptyValue(qs, '51D_ScreenPixelsHeight', _window?.screen?.height); deepSetNotEmptyValue(qs, '51D_ScreenPixelsWidth', _window?.screen?.width); deepSetNotEmptyValue(qs, '51D_PixelRatio', getDevicePixelRatio(_window)); + // id.usage contains a dot, so set it directly. + if (pathData.idUsage) { + qs['id.usage'] = pathData.idUsage; + } + if (pathData.tcString) { + qs.tcstring = pathData.tcString; + } + if (pathData.gpp) { + qs.gppstring = pathData.gpp; + } const _qs = formatQS(qs); const _qsString = _qs ? `${queryPrefix}${_qs}` : ''; @@ -220,19 +233,23 @@ export const deepSetNotEmptyValue = (obj, key, value) => { * * @param {Object} data51 Response from 51Degrees API * @param {Object} [data51.device] Device data + * @param {Object} [data51.ip] IP data (device.ip/ipv6 + device.geo) + * @param {Object} [data51.fodid] 51DiD data (mapped to user.eids) + * @param {Object} [options] + * @param {string} [options.tdlUrl] TDL URL passed through to the EID entry * * @returns {Object} Enriched ORTB2 object */ -export const convert51DegreesDataToOrtb2 = (data51) => { - let ortb2Data = {}; +export const convert51DegreesDataToOrtb2 = (data51, options = {}) => { + const ortb2Data = {}; if (!data51) { return ortb2Data; } - ortb2Data = convert51DegreesDeviceToOrtb2(data51.device); - - // placeholder for the next 51Degrees RTD submodule update + mergeDeep(ortb2Data, convert51DegreesDeviceToOrtb2(data51.device)); + mergeDeep(ortb2Data, convert51DegreesIpToOrtb2(data51.ip)); + mergeDeep(ortb2Data, convert51DegreesFoDiDToOrtb2(data51.fodid, options.tdlUrl)); return ortb2Data; }; @@ -293,8 +310,6 @@ export const convert51DegreesDeviceToOrtb2 = (device) => { deepSetNotEmptyValue(ortb2Device, 'w', device.screenpixelsphysicalwidth || device.screenpixelswidth); deepSetNotEmptyValue(ortb2Device, 'pxratio', device.pixelratio); deepSetNotEmptyValue(ortb2Device, 'ppi', devicePhysicalPPI || devicePPI); - // kept for backward compatibility - deepSetNotEmptyValue(ortb2Device, 'ext.fiftyonedegrees_deviceId', device.deviceid); deepSetNotEmptyValue(ortb2Device, 'ext.fod.deviceId', device.deviceid); if (['True', 'False'].includes(device.thirdpartycookiesenabled)) { deepSetValue(ortb2Device, 'ext.fod.tpc', device.thirdpartycookiesenabled === 'True' ? 1 : 0); @@ -303,6 +318,181 @@ export const convert51DegreesDeviceToOrtb2 = (device) => { return { device: ortb2Device }; } +/** + * Converts 51Degrees IP data to ORTB2 format. Maps device.ip, device.ipv6, + * and (when locationconfidence is high/medium) device.geo.* fields. + * + * @param {Object} ip 51Degrees ip object + * @param {string} [ip.ip] IPv4 address + * @param {string} [ip.ipv6] IPv6 address + * @param {string} [ip.locationconfidence] high|medium gates geo fields + * @param {number} [ip.latitude] + * @param {number} [ip.longitude] + * @param {string} [ip.countrycode3] ISO-3166-1 alpha-3 + * @param {string} [ip.iso31662lvl4] ISO-3166-2 subdivision code (e.g. GB-ENG) + * @param {string} [ip.zipcode] + * @param {number} [ip.timezoneoffset] minutes from UTC + * @param {number} [ip.accuracyradiusmin] km (multiplied by 1000 in output to convert to meters) + * @returns {Object} Enriched ORTB2 object fragment ({device:{...}}) + */ +export const convert51DegreesIpToOrtb2 = (ip) => { + const ortb2 = {}; + + if (!ip) { + return ortb2; + } + + // device.ip / device.ipv6 are not gated on confidence. + deepSetNotEmptyValue(ortb2, 'device.ip', ip.ip); + deepSetNotEmptyValue(ortb2, 'device.ipv6', ip.ipv6); + + const confidence = typeof ip.locationconfidence === 'string' + ? ip.locationconfidence.toLowerCase() + : undefined; + let ipservice; + if (confidence === 'high') { + ipservice = 511; + } else if (confidence === 'medium') { + ipservice = 512; + } else { + return ortb2; + } + + // Use null/undefined checks rather than truthy checks so 0 coordinates + // (Gulf of Guinea) and 0 accuracy survive. + const setIfDefined = (key, value) => { + if (value !== null && value !== undefined) { + deepSetValue(ortb2, key, value); + } + }; + + setIfDefined('device.geo.lat', ip.latitude); + setIfDefined('device.geo.lon', ip.longitude); + deepSetNotEmptyValue(ortb2, 'device.geo.country', ip.countrycode3); + deepSetNotEmptyValue(ortb2, 'device.geo.region', ip.iso31662lvl4); + deepSetNotEmptyValue(ortb2, 'device.geo.zip', ip.zipcode); + setIfDefined('device.geo.utcoffset', ip.timezoneoffset); + setIfDefined( + 'device.geo.accuracy', + ip.accuracyradiusmin === null || ip.accuracyradiusmin === undefined + ? undefined + : ip.accuracyradiusmin * 1000, + ); + + // Only stamp type+ipservice if at least one geo.* field actually landed. + // Otherwise we'd emit a device.geo with just metadata which is meaningless. + if (ortb2.device && ortb2.device.geo) { + deepSetValue(ortb2, 'device.geo.type', 2); + deepSetValue(ortb2, 'device.geo.ipservice', ipservice); + } + + return ortb2; +} + +/** + * Converts 51Degrees fodid (51DiD) data to an ORTB2 user.eids entry. + * Builds a single 51d.es source entry whose uids carry idproblic and + * idprobglobal in that order. ext.tdl is populated from the supplied URL + * when present; omitted otherwise. + * + * @param {Object} fodid 51Degrees fodid object + * @param {string} [fodid.idproblic] License-tier 51DiD + * @param {string} [fodid.idprobglobal] Global-tier 51DiD + * @param {string} [tdlUrl] TDL URL passed from module config + * @returns {Object} Enriched ORTB2 fragment ({user:{eids:[...]}}) or {} when + * no uids are available + */ +export const convert51DegreesFoDiDToOrtb2 = (fodid, tdlUrl) => { + if (!fodid) { + return {}; + } + + const uids = []; + if (fodid.idproblic) { + uids.push({ id: fodid.idproblic, atype: 1 }); + } + if (fodid.idprobglobal) { + uids.push({ id: fodid.idprobglobal, atype: 1 }); + } + if (uids.length === 0) { + return {}; + } + + const entry = { + inserter: '51degrees.com', + source: '51d.es', + mm: 5, + uids, + }; + if (tdlUrl) { + entry.ext = { tdl: [tdlUrl] }; + } else { + logWarn('tdlUrl is not configured; emitting eids entry without ext.tdl'); + } + + return { user: { eids: [entry] } }; +} + +// PMP localStorage contract, duplicated from pmp/src/storage.ts of the +// 51Degrees/cloud repo. If PMP bumps SCHEMA_VERSION the shape check fails +// closed and we fall through to undefined. +const PMP_STORAGE_KEY = '__51d_pmp_pref'; +const PMP_SCHEMA_VERSION = 1; + +// Storage manager scoped to this RTD module. Required by Prebid's storage +// activity rules and the no-restricted-globals lint. +const storageManager = getStorageManager({ + moduleType: MODULE_TYPE_RTD, + moduleName: MODULE_NAME, +}); + +/** + * Resolves the id.usage value from PMP localStorage. + * Returns undefined when no valid value is found, + * which signals the caller to omit id.usage from the cloud URL entirely. + * + * @param {Object} moduleConfig 51Degrees RTD module config + * @returns {string|undefined} + */ +export const resolveIdUsage = (moduleConfig) => { + try { + const stored = storageManager.getDataFromLocalStorage(PMP_STORAGE_KEY); + if (!stored) { + return undefined; + } + const parsed = JSON.parse(stored); + if (parsed && parsed.v === PMP_SCHEMA_VERSION && + (parsed.p === 'standard' || parsed.p === 'personalized')) { + return parsed.p; + } + } catch (_) { + // Storage unavailable or JSON malformed; fall through. + } + return undefined; +} + +/** + * Reads the raw TCF consent string from Prebid user consent. + * + * @param {Object} userConsent Prebid user consent object + * @returns {string|undefined} + */ +export const resolveTcString = (userConsent) => { + const tc = deepAccess(userConsent, 'gdpr.consentString'); + return (typeof tc === 'string' && tc.length > 0) ? tc : undefined; +} + +/** + * Reads the raw GPP string from Prebid user consent. + * + * @param {Object} userConsent Prebid user consent object + * @returns {string|undefined} + */ +export const resolveGpp = (userConsent) => { + const gpp = deepAccess(userConsent, 'gpp.gppString'); + return (typeof gpp === 'string' && gpp.length > 0) ? gpp : undefined; +} + /** * @param {Object} reqBidsConfigObj Bid request configuration object * @param {Function} callback Called on completion @@ -316,6 +506,14 @@ export const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, user logMessage('Resource key: ', resourceKey); logMessage('On-premise JS URL: ', onPremiseJSUrl); + const tdlUrl = deepAccess(moduleConfig, 'params.tdlUrl'); + const idUsage = resolveIdUsage(moduleConfig); + logMessage('Resolved id.usage: ', idUsage); + const tcString = resolveTcString(userConsent); + const gpp = resolveGpp(userConsent); + logMessage('TCF consent string present: ', !!tcString); + logMessage('GPP string present: ', !!gpp); + // Check if 51Degrees meta is present (cloud only) if (resourceKey) { logMessage('Checking if 51Degrees meta is present in the document head'); @@ -326,7 +524,7 @@ export const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, user getHighEntropyValues(['model', 'platform', 'platformVersion', 'fullVersionList']).then((hev) => { // Get 51Degrees JS URL, which is either cloud or on-premise - const scriptURL = get51DegreesJSURL({ resourceKey, onPremiseJSUrl, hev }); + const scriptURL = get51DegreesJSURL({ resourceKey, onPremiseJSUrl, hev, idUsage, tcString, gpp }); logMessage('URL of the script to be injected: ', scriptURL); // Inject 51Degrees script, get device data and merge it into the ORTB2 object @@ -336,10 +534,15 @@ export const getBidRequestData = (reqBidsConfigObj, callback, moduleConfig, user // Convert and merge device data in the callback fod.complete((data) => { logMessage('51Degrees raw data: ', data); - mergeDeep( - reqBidsConfigObj.ortb2Fragments.global, - convert51DegreesDataToOrtb2(data), - ); + const global = reqBidsConfigObj.ortb2Fragments.global; + const enrichment = convert51DegreesDataToOrtb2(data, { tdlUrl }); + // Don't clobber a publisher-observed device.ip / device.ipv6 with + // our IP-derived value. Publisher signal wins. + if (enrichment.device) { + if (deepAccess(global, 'device.ip')) delete enrichment.device.ip; + if (deepAccess(global, 'device.ipv6')) delete enrichment.device.ipv6; + } + mergeDeep(global, enrichment); logMessage('reqBidsConfigObj: ', reqBidsConfigObj); callback(); }); diff --git a/modules/51DegreesRtdProvider.md b/modules/51DegreesRtdProvider.md index b38fed3dfaf..c4efba38616 100644 --- a/modules/51DegreesRtdProvider.md +++ b/modules/51DegreesRtdProvider.md @@ -8,17 +8,25 @@ ## Description -51Degrees module enriches an OpenRTB request with [51Degrees Device Data](https://51degrees.com/documentation/index.html). +51Degrees module enriches an OpenRTB request with [51Degrees Device Data](https://51degrees.com/documentation/index.html) and (optionally) IP-derived geo plus a 51DiD (51Degrees identifier) entry in `user.eids`. 51Degrees module sets the following fields of the device object: `devicetype`, `make`, `model`, `hwv`, `os`, `osv`, `h`, `w`, `ppi`, `pxratio`. Interested bidder adapters may use these fields as needed. -The module also adds a `device.ext.fod` extension object (fod == fifty one degrees) and sets `device.ext.fod.deviceId` to a permanent device ID, which can be rapidly looked up in on-premise data, exposing over 250 properties, including device age, chipset, codec support, price, operating system and app/browser versions, age, and embedded features. +The module also adds a `device.ext.fod` extension object (fod == fifty one degrees) and sets `device.ext.fod.deviceId` to a permanent device ID, which can be rapidly looked up in on-premise data, exposing over 250 properties, including device age, chipset, codec support, price, operating system and app/browser versions, age, and embedded features. -It also sets `device.ext.fod.tpc` key to a binary value to indicate whether third-party cookies are enabled in the browser (1 if enabled, 0 if disabled). +It also sets `device.ext.fod.tpc` to a binary value to indicate whether third-party cookies are enabled in the browser (1 if enabled, 0 if disabled). + +When 51Degrees IPI is available in the cloud response, the module sets `device.ip` and `device.ipv6`, and (if the location confidence is `high` or `medium`) populates `device.geo.{lat,lon,country,zip,utcoffset,accuracy,type,ipservice}` per OpenRTB 2.6 and AdCOM 1.0. + +[51DiD](https://51degrees.com/documentation/4.5/_identifiers_51_did.html) is a 51Degrees privacy-safe identifier derived from device signals. Its production requires a marketing usage preference (`id.usage`). The recommended way to collect and store that preference is the [51Degrees Preference Management Platform (PMP)](https://51degrees.com/documentation/4.5/_identifiers__p_m_p.html) — a lightweight consent widget that writes the user's choice to `localStorage`. When PMP is present on the page the module picks up that preference automatically. When PMP is absent the module falls back to inferring the preference from the publisher's existing TCF or GPP consent string (see below). + +When 51DiD is available, the module appends an entry to `user.eids` with `source = "51d.es"`, `inserter = "51degrees.com"`, `mm = 5` (inference), and `uids` carrying `idproblic` and `idprobglobal`. The `ext.tdl` URL inside the entry comes from the `params.tdlUrl` module config. + +The module forwards the publisher's consent strings to the cloud as evidence when present. The TCF consent string (from Prebid's GDPR consent) is sent as `tcstring` and the GPP string (from Prebid's GPP consent) is sent as `gppstring`; the cloud can infer the marketing usage preference from either when PMP is not present, so 51DiD works for publishers running any TCF or GPP CMP. These come from Prebid's consent data, not module params. The module supports on-premise and cloud device detection services, with free options for both. -A free resource key for use with 51Degrees cloud service can be obtained from [51Degrees cloud configuration](https://configure.51degrees.com/jJqVnTJR). This is the simplest approach to trial the module. +A free resource key for use with 51Degrees cloud service can be obtained from [51Degrees cloud configuration](https://configure.51degrees.com/Q5cD1H9W). This is the simplest approach to trial the module. An interface-compatible self-hosted service can be used with .NET, Java, Node, PHP, and Python. See [51Degrees examples](https://51degrees.com/documentation/_examples__device_detection__getting_started__web__on_premise.html). @@ -40,7 +48,7 @@ gulp build --modules=rtdModule,51DegreesRtdProvider,appnexusBidAdapter,... #### Resource Key -In order to use the module, please first obtain a Resource Key using the [Configurator tool](https://configure.51degrees.com/jJqVnTJR) - choose the following properties: +In order to use the module, please first obtain a Resource Key using the [Configurator tool](https://configure.51degrees.com/Q5cD1H9W) - choose the following properties: * DeviceId * DeviceType @@ -113,7 +121,7 @@ pbjs.setConfig({ waitForIt: true, // should be true, otherwise the auctionDelay will be ignored params: { resourceKey: '', - // Get your resource key from https://configure.51degrees.com/jJqVnTJR + // Get your resource key from https://configure.51degrees.com/Q5cD1H9W // alternatively, you can use the on-premise version of the 51Degrees service and connect to your chosen endpoint // onPremiseJSUrl: 'https://localhost/51Degrees.core.js' }, @@ -127,13 +135,14 @@ pbjs.setConfig({ > Note that `resourceKey` and `onPremiseJSUrl` are mutually exclusive parameters. Use strictly one of them: either a `resourceKey` for cloud integration or `onPremiseJSUrl` for the on-premise self-hosted integration. -| Name | Type | Description | Default | -|:----------------------|:--------|:---------------------------------------------------------------------------------------------|:-------------------| -| name | String | Real-time data module name | Always '51Degrees' | -| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (mandatory) | `false` | -| params | Object | | | -| params.resourceKey | String | Your 51Degrees Cloud Resource Key | | -| params.onPremiseJSUrl | String | Direct URL to your self-hosted on-premise JS file (e.g. https://localhost/51Degrees.core.js) | | +| Name | Type | Description | Default | +|:----------------------|:--------|:-------------------------------------------------------------------------------------------------------------------------------------------|:-------------------| +| name | String | Real-time data module name | Always '51Degrees' | +| waitForIt | Boolean | Should be `true` if there's an `auctionDelay` defined (mandatory) | `false` | +| params | Object | | | +| params.resourceKey | String | Your 51Degrees Cloud Resource Key | | +| params.onPremiseJSUrl | String | Direct URL to your self-hosted on-premise JS file (e.g. https://localhost/51Degrees.core.js) | | +| params.tdlUrl | String | URL of your Terms Document Locator (TDL) — a machine-readable document declaring the data usage terms under which the identifier is shared, per the [data-labels proposal](https://github.com/jwrosewell/data-labels/tree/main) and its [OpenRTB extension](https://github.com/jwrosewell/data-labels/blob/main/OpenRTB.md). The URL is placed in the `ext.tdl` array of the `51d.es` eids entry. Omit if you do not publish a TDL; the module will log a warning and emit the eids entry without `ext.tdl`. | | > Note: if you use a third-party Prebid.js wrapper, there might be a chance that the UI will force you to input both `resourceKey` and `onPremiseJSUrl`. In this case, you can set a redundant parameter to a string equal to "0", which will be ignored by the module. diff --git a/modules/gumgumBidAdapter.js b/modules/gumgumBidAdapter.js index ea03c6d1436..05a258d1373 100644 --- a/modules/gumgumBidAdapter.js +++ b/modules/gumgumBidAdapter.js @@ -297,7 +297,7 @@ function _getDeviceData(ortb2Data) { pxratio: _device.pxratio, lmt: _device.lmt, ifa: _device.lmt !== 1 ? _device.ifa : undefined, - foddid: _device?.ext?.fiftyonedegrees_deviceId, + foddid: _device?.ext?.fod?.deviceId, }; // return device data params with only non-empty values diff --git a/test/spec/modules/51DegreesRtdProvider_spec.js b/test/spec/modules/51DegreesRtdProvider_spec.js index 7e1840e3dc7..730e63f83e7 100644 --- a/test/spec/modules/51DegreesRtdProvider_spec.js +++ b/test/spec/modules/51DegreesRtdProvider_spec.js @@ -5,10 +5,16 @@ import { deepSetNotEmptyValue, convert51DegreesDataToOrtb2, convert51DegreesDeviceToOrtb2, + convert51DegreesIpToOrtb2, + convert51DegreesFoDiDToOrtb2, + resolveIdUsage, + resolveTcString, + resolveGpp, getBidRequestData, fiftyOneDegreesSubmodule, } from 'modules/51DegreesRtdProvider'; import { mergeDeep } from '../../../src/utils.js'; +import { loadExternalScriptStub } from 'test/mocks/adloaderStub.js'; const inject51DegreesMeta = () => { const meta = document.createElement('meta'); @@ -61,7 +67,6 @@ describe('51DegreesRtdProvider', function() { ppi: 109, pxratio: 1, ext: { - fiftyonedegrees_deviceId: '17595-131215-132535-18092', fod: { deviceId: '17595-131215-132535-18092', tpc: 1, @@ -280,6 +285,74 @@ describe('51DegreesRtdProvider', function() { expect(get51DegreesJSURL(config, mockWindow)).to.equal('https://example.com/51Degrees.core.js'); expect(get51DegreesJSURL(config, window)).to.not.equal('https://example.com/51Degrees.core.js'); }); + + it('appends id.usage when idUsage is provided', function () { + // The previous test deletes screen/devicePixelRatio from the shared + // mockWindow, so build a fresh one here. + const freshWindow = { + screen: { height: 1117, width: 1728 }, + devicePixelRatio: 2, + }; + const config = { + resourceKey: 'TEST_RESOURCE_KEY', + idUsage: 'standard', + }; + expect(get51DegreesJSURL(config, freshWindow)).to.include('id.usage=standard'); + }); + + it('omits id.usage when idUsage is undefined', function () { + const freshWindow = { + screen: { height: 1117, width: 1728 }, + devicePixelRatio: 2, + }; + const config = { resourceKey: 'TEST_RESOURCE_KEY' }; + expect(get51DegreesJSURL(config, freshWindow)).to.not.include('id.usage'); + }); + + it('appends tcstring when tcString is provided', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const config = { resourceKey: 'TEST_RESOURCE_KEY', tcString: 'CONSENTX' }; + expect(get51DegreesJSURL(config, freshWindow)).to.include('tcstring=CONSENTX'); + }); + + it('keeps a realistic multi-segment TCF string intact', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const tc = 'CPysuENPyveLkADACBENADCsAP_AAH_AAAAAAAAA.YAAAAAAAAA'; + const config = { resourceKey: 'TEST_RESOURCE_KEY', tcString: tc }; + expect(get51DegreesJSURL(config, freshWindow)).to.include('tcstring=' + tc); + }); + + it('omits tcstring when tcString is undefined', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const config = { resourceKey: 'TEST_RESOURCE_KEY' }; + expect(get51DegreesJSURL(config, freshWindow)).to.not.include('tcstring'); + }); + + it('appends gppstring when gpp is provided', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const config = { resourceKey: 'TEST_RESOURCE_KEY', gpp: 'GPPX' }; + expect(get51DegreesJSURL(config, freshWindow)).to.include('gppstring=GPPX'); + }); + + it('omits gppstring when gpp is undefined', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const config = { resourceKey: 'TEST_RESOURCE_KEY' }; + expect(get51DegreesJSURL(config, freshWindow)).to.not.include('gppstring'); + }); + + it('appends id.usage, tcstring and gppstring together', function () { + const freshWindow = { screen: { height: 1117, width: 1728 }, devicePixelRatio: 2 }; + const config = { + resourceKey: 'TEST_RESOURCE_KEY', + idUsage: 'standard', + tcString: 'CONSENTX', + gpp: 'GPPX', + }; + const url = get51DegreesJSURL(config, freshWindow); + expect(url).to.include('id.usage=standard'); + expect(url).to.include('tcstring=CONSENTX'); + expect(url).to.include('gppstring=GPPX'); + }); }); describe('is51DegreesMetaPresent', function() { @@ -357,6 +430,45 @@ describe('51DegreesRtdProvider', function() { it('converts all 51Degrees data to ORTB2 format', function() { expect(convert51DegreesDataToOrtb2(fiftyOneDegreesData)).to.deep.equal(expectedORTB2Result); }); + + it('merges ip data into the result when data51.ip is present', function () { + const data51 = { + device: fiftyOneDegreesDevice, + ip: { + ip: '1.2.3.4', + locationconfidence: 'high', + latitude: 51.5, + longitude: -0.1, + countrycode3: 'GBR', + }, + }; + const result = convert51DegreesDataToOrtb2(data51); + expect(result.device.ip).to.equal('1.2.3.4'); + expect(result.device.geo.lat).to.equal(51.5); + expect(result.device.geo.ipservice).to.equal(511); + expect(result.device.make).to.equal('Apple'); + }); + + it('merges fodid data into user.eids when tdlUrl is supplied', function () { + const data51 = { + device: fiftyOneDegreesDevice, + fodid: { + idproblic: 'lic-uid', + idprobglobal: 'global-uid', + }, + }; + const result = convert51DegreesDataToOrtb2(data51, { tdlUrl: 'https://tdl.example/x' }); + expect(result.user.eids).to.have.lengthOf(1); + expect(result.user.eids[0].uids).to.deep.equal([{ id: 'lic-uid', atype: 1 }, { id: 'global-uid', atype: 1 }]); + expect(result.user.eids[0].ext.tdl).to.deep.equal(['https://tdl.example/x']); + }); + + it('returns only device mapping when ip and fodid are absent', function () { + const data51 = { device: fiftyOneDegreesDevice }; + const result = convert51DegreesDataToOrtb2(data51, { tdlUrl: 'https://tdl.example/x' }); + expect(result.device.make).to.equal('Apple'); + expect(result.user).to.be.undefined; + }); }); describe('convert51DegreesDeviceToOrtb2', function() { @@ -463,6 +575,296 @@ describe('51DegreesRtdProvider', function() { }); }); + describe('convert51DegreesIpToOrtb2', function() { + const fullIp = { + ip: '1.2.3.4', + ipv6: '2001:db8::1', + latitude: 51.5, + longitude: -0.1, + countrycode3: 'GBR', + iso31662lvl4: 'GB-ENG', + zipcode: 'SW1', + timezoneoffset: 0, + accuracyradiusmin: 1.5, + locationconfidence: 'high', + }; + + it('returns an empty object when ip is undefined', function() { + expect(convert51DegreesIpToOrtb2(undefined)).to.deep.equal({}); + }); + + it('returns an empty object when ip is null', function() { + expect(convert51DegreesIpToOrtb2(null)).to.deep.equal({}); + }); + + it('maps ip and ipv6 unconditionally when locationconfidence is missing', function() { + const result = convert51DegreesIpToOrtb2({ ip: '1.2.3.4', ipv6: '2001:db8::1' }); + expect(result).to.deep.equal({ + device: { ip: '1.2.3.4', ipv6: '2001:db8::1' }, + }); + }); + + it('maps full ip data with locationconfidence=high → ipservice=511', function() { + const result = convert51DegreesIpToOrtb2(fullIp); + expect(result).to.deep.equal({ + device: { + ip: '1.2.3.4', + ipv6: '2001:db8::1', + geo: { + lat: 51.5, + lon: -0.1, + country: 'GBR', + region: 'GB-ENG', + zip: 'SW1', + utcoffset: 0, + accuracy: 1500, + type: 2, + ipservice: 511, + }, + }, + }); + }); + + it('uses ipservice=512 when locationconfidence=medium', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, locationconfidence: 'medium' }); + expect(result.device.geo.ipservice).to.equal(512); + }); + + it('compares locationconfidence case-insensitively', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, locationconfidence: 'HIGH' }); + expect(result.device.geo.ipservice).to.equal(511); + }); + + it('skips all geo fields when locationconfidence=low', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, locationconfidence: 'low' }); + expect(result.device.geo).to.be.undefined; + expect(result.device.ip).to.equal('1.2.3.4'); + expect(result.device.ipv6).to.equal('2001:db8::1'); + }); + + it('skips all geo fields when locationconfidence=unknown', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, locationconfidence: 'Unknown' }); + expect(result.device.geo).to.be.undefined; + expect(result.device.ip).to.equal('1.2.3.4'); + expect(result.device.ipv6).to.equal('2001:db8::1'); + }); + + it('skips all geo fields when locationconfidence is absent', function() { + const { locationconfidence, ...withoutConfidence } = fullIp; + const result = convert51DegreesIpToOrtb2(withoutConfidence); + expect(result.device.geo).to.be.undefined; + }); + + it('multiplies accuracyradiusmin by 1000 for accuracy in meters', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, accuracyradiusmin: 2 }); + expect(result.device.geo.accuracy).to.equal(2000); + }); + + it('maps iso31662lvl4 to device.geo.region', function() { + const result = convert51DegreesIpToOrtb2(fullIp); + expect(result.device.geo.region).to.equal('GB-ENG'); + }); + + it('omits device.geo.region when iso31662lvl4 is absent', function() { + const { iso31662lvl4, ...withoutRegion } = fullIp; + const result = convert51DegreesIpToOrtb2(withoutRegion); + expect(result.device.geo.region).to.be.undefined; + }); + + it('preserves zero coordinates as valid values', function() { + const result = convert51DegreesIpToOrtb2({ + ...fullIp, + latitude: 0, + longitude: 0, + }); + expect(result.device.geo.lat).to.equal(0); + expect(result.device.geo.lon).to.equal(0); + }); + + it('preserves zero accuracyradiusmin', function() { + const result = convert51DegreesIpToOrtb2({ ...fullIp, accuracyradiusmin: 0 }); + expect(result.device.geo.accuracy).to.equal(0); + }); + + it('omits null/undefined source fields from output', function() { + const result = convert51DegreesIpToOrtb2({ + ip: '1.2.3.4', + locationconfidence: 'high', + latitude: 51.5, + }); + expect(result.device.geo).to.deep.equal({ + lat: 51.5, + type: 2, + ipservice: 511, + }); + }); + }); + + describe('convert51DegreesFoDiDToOrtb2', function() { + const fullFodid = { + idproblic: 'lic-uid-base64', + idprobglobal: 'global-uid-base64', + }; + const TDL_URL = 'https://tdl.example/x'; + + it('returns an empty object when fodid is undefined', function() { + expect(convert51DegreesFoDiDToOrtb2(undefined, TDL_URL)).to.deep.equal({}); + }); + + it('returns an empty object when fodid is null', function() { + expect(convert51DegreesFoDiDToOrtb2(null, TDL_URL)).to.deep.equal({}); + }); + + it('emits an empty object when both uids are absent', function() { + expect(convert51DegreesFoDiDToOrtb2({}, TDL_URL)).to.deep.equal({}); + }); + + it('emits a full eids entry with tdlUrl', function() { + const result = convert51DegreesFoDiDToOrtb2(fullFodid, TDL_URL); + expect(result).to.deep.equal({ + user: { + eids: [{ + inserter: '51degrees.com', + source: '51d.es', + mm: 5, + uids: [{ id: 'lic-uid-base64', atype: 1 }, { id: 'global-uid-base64', atype: 1 }], + ext: { tdl: [TDL_URL] }, + }], + }, + }); + }); + + it('omits ext.tdl when tdlUrl is falsy', function() { + const result = convert51DegreesFoDiDToOrtb2(fullFodid, undefined); + expect(result.user.eids[0].ext).to.be.undefined; + expect(result.user.eids[0].uids).to.deep.equal([{ id: 'lic-uid-base64', atype: 1 }, { id: 'global-uid-base64', atype: 1 }]); + }); + + it('emits entry with only idproblic when idprobglobal is absent', function() { + const result = convert51DegreesFoDiDToOrtb2({ idproblic: 'lic-only' }, TDL_URL); + expect(result.user.eids[0].uids).to.deep.equal([{ id: 'lic-only', atype: 1 }]); + }); + + it('emits entry with only idprobglobal when idproblic is absent', function() { + const result = convert51DegreesFoDiDToOrtb2({ idprobglobal: 'global-only' }, TDL_URL); + expect(result.user.eids[0].uids).to.deep.equal([{ id: 'global-only', atype: 1 }]); + }); + + it('uses constant inserter, source, and mm', function() { + const result = convert51DegreesFoDiDToOrtb2(fullFodid, TDL_URL); + expect(result.user.eids[0].inserter).to.equal('51degrees.com'); + expect(result.user.eids[0].source).to.equal('51d.es'); + expect(result.user.eids[0].mm).to.equal(5); + }); + + it('omits matcher field', function() { + const result = convert51DegreesFoDiDToOrtb2(fullFodid, TDL_URL); + expect(result.user.eids[0]).to.not.have.property('matcher'); + }); + }); + + describe('resolveIdUsage', function() { + const PMP_STORAGE_KEY = '__51d_pmp_pref'; + + afterEach(function() { + localStorage.removeItem(PMP_STORAGE_KEY); + }); + + it('reads "standard" from PMP storage when params absent', function() { + localStorage.setItem( + PMP_STORAGE_KEY, + JSON.stringify({ v: 1, p: 'standard', t: Date.now() }), + ); + expect(resolveIdUsage({ params: {} })).to.equal('standard'); + }); + + it('reads "personalized" from PMP storage when params absent', function() { + localStorage.setItem( + PMP_STORAGE_KEY, + JSON.stringify({ v: 1, p: 'personalized', t: Date.now() }), + ); + expect(resolveIdUsage({ params: {} })).to.equal('personalized'); + }); + + it('returns undefined when PMP storage has unknown schema version', function() { + localStorage.setItem( + PMP_STORAGE_KEY, + JSON.stringify({ v: 2, p: 'standard', t: Date.now() }), + ); + expect(resolveIdUsage({ params: {} })).to.be.undefined; + }); + + it('returns undefined when PMP storage has unknown preference value', function() { + localStorage.setItem( + PMP_STORAGE_KEY, + JSON.stringify({ v: 1, p: 'never-heard-of-it', t: Date.now() }), + ); + expect(resolveIdUsage({ params: {} })).to.be.undefined; + }); + + it('returns undefined when PMP storage is malformed JSON', function() { + localStorage.setItem(PMP_STORAGE_KEY, 'not-json{'); + expect(resolveIdUsage({ params: {} })).to.be.undefined; + }); + + it('returns undefined when both sources are absent', function() { + expect(resolveIdUsage({ params: {} })).to.be.undefined; + }); + + it('returns undefined when moduleConfig has no params', function() { + expect(resolveIdUsage({})).to.be.undefined; + }); + }); + + describe('resolveTcString', function() { + it('returns the consent string from userConsent.gdpr.consentString', function() { + expect(resolveTcString({ gdpr: { consentString: 'CONSENTX' } })).to.equal('CONSENTX'); + }); + + it('returns the string regardless of gdprApplies', function() { + expect(resolveTcString({ gdpr: { consentString: 'C', gdprApplies: false } })).to.equal('C'); + expect(resolveTcString({ gdpr: { consentString: 'C', gdprApplies: true } })).to.equal('C'); + }); + + it('returns undefined when consentString is empty', function() { + expect(resolveTcString({ gdpr: { consentString: '' } })).to.be.undefined; + }); + + it('returns undefined when consentString is not a string', function() { + expect(resolveTcString({ gdpr: { consentString: 123 } })).to.be.undefined; + }); + + it('returns undefined when gdpr is absent', function() { + expect(resolveTcString({})).to.be.undefined; + }); + + it('returns undefined when userConsent is undefined', function() { + expect(resolveTcString(undefined)).to.be.undefined; + }); + }); + + describe('resolveGpp', function() { + it('returns the gpp string from userConsent.gpp.gppString', function() { + expect(resolveGpp({ gpp: { gppString: 'GPPX' } })).to.equal('GPPX'); + }); + + it('returns undefined when gppString is empty', function() { + expect(resolveGpp({ gpp: { gppString: '' } })).to.be.undefined; + }); + + it('returns undefined when gppString is not a string', function() { + expect(resolveGpp({ gpp: { gppString: 123 } })).to.be.undefined; + }); + + it('returns undefined when gpp is absent', function() { + expect(resolveGpp({})).to.be.undefined; + }); + + it('returns undefined when userConsent is undefined', function() { + expect(resolveGpp(undefined)).to.be.undefined; + }); + }); + describe('getBidRequestData', function() { let initialHeadInnerHTML; let reqBidsConfigObj = {}; @@ -536,6 +938,78 @@ describe('51DegreesRtdProvider', function() { expect(callback.calledOnce).to.be.true; expect(reqBidsConfigObj.ortb2Fragments.global).to.deep.equal(expectedORTB2Result); }); + + it('enriches ortb2 with ip and user.eids when data51 contains them', async function() { + // Override the global window.fod for this case only; restore after. + const originalFod = window.fod; + const data51 = { + device: fiftyOneDegreesDevice, + ip: { ip: '5.6.7.8', locationconfidence: 'high', countrycode3: 'USA' }, + fodid: { idproblic: 'lic-uid', idprobglobal: 'global-uid' }, + }; + window.fod = { complete: (cb) => cb(data51) }; + + const callback = sinon.spy(); + const moduleConfig = { + params: { + resourceKey: 'INVALID_RESOURCE_KEY', + idUsage: 'standard', + tdlUrl: 'https://tdl.example/x', + }, + }; + + try { + getBidRequestData(reqBidsConfigObj, callback, moduleConfig, {}); + await new Promise(resolve => setTimeout(resolve, 100)); + + expect(callback.calledOnce).to.be.true; + expect(reqBidsConfigObj.ortb2Fragments.global.device.ip).to.equal('5.6.7.8'); + expect(reqBidsConfigObj.ortb2Fragments.global.device.geo.country).to.equal('USA'); + expect(reqBidsConfigObj.ortb2Fragments.global.user.eids).to.have.lengthOf(1); + expect(reqBidsConfigObj.ortb2Fragments.global.user.eids[0].uids) + .to.deep.equal([{ id: 'lic-uid', atype: 1 }, { id: 'global-uid', atype: 1 }]); + expect(reqBidsConfigObj.ortb2Fragments.global.user.eids[0].ext.tdl) + .to.deep.equal(['https://tdl.example/x']); + } finally { + window.fod = originalFod; + } + }); + + it('does not overwrite a publisher-set device.ip / device.ipv6', async function() { + const originalFod = window.fod; + window.fod = { + complete: (cb) => cb({ ip: { ip: '5.6.7.8', ipv6: 'fe80::51d', locationconfidence: 'high' } }), + }; + reqBidsConfigObj.ortb2Fragments.global.device = { ip: '10.0.0.1', ipv6: 'fe80::pub' }; + const callback = sinon.spy(); + const moduleConfig = { params: { resourceKey: 'INVALID_RESOURCE_KEY' } }; + + try { + getBidRequestData(reqBidsConfigObj, callback, moduleConfig, {}); + await new Promise(resolve => setTimeout(resolve, 100)); + expect(reqBidsConfigObj.ortb2Fragments.global.device.ip).to.equal('10.0.0.1'); + expect(reqBidsConfigObj.ortb2Fragments.global.device.ipv6).to.equal('fe80::pub'); + } finally { + window.fod = originalFod; + } + }); + + it('forwards tcstring and gppstring from userConsent to the script URL', async function() { + const callback = sinon.spy(); + const moduleConfig = { params: { resourceKey: 'INVALID_RESOURCE_KEY' } }; + const userConsent = { + gdpr: { consentString: 'TCSTRINGVAL', gdprApplies: true }, + gpp: { gppString: 'GPPSTRINGVAL' }, + }; + + getBidRequestData(reqBidsConfigObj, callback, moduleConfig, userConsent); + await new Promise(resolve => setTimeout(resolve, 100)); + + expect(loadExternalScriptStub.called).to.be.true; + const scriptUrl = loadExternalScriptStub.getCall(0).args[0]; + expect(scriptUrl).to.include('tcstring=TCSTRINGVAL'); + expect(scriptUrl).to.include('gppstring=GPPSTRINGVAL'); + }); }); describe('init', function() { diff --git a/test/spec/modules/gumgumBidAdapter_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js index 63f6ad0d416..7fa6eae4d55 100644 --- a/test/spec/modules/gumgumBidAdapter_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -1337,7 +1337,7 @@ describe('gumgumAdapter', function () { hwv: 'iPhone15,2', os: 'iOS', osv: '17.4', - ext: { fiftyonedegrees_deviceId: '17595-133085-133468-18092' }, + ext: { fod: { deviceId: '17595-133085-133468-18092' } }, ip: '127.0.0.1', ipv6: '51dc:5e20:fd6a:c955:66be:03b4:dfa3:35b2', lmt: 1, @@ -1358,7 +1358,7 @@ describe('gumgumAdapter', function () { expect(bidRequest.data.hwv).to.equal(ortb2.device.hwv); expect(bidRequest.data.os).to.equal(ortb2.device.os); expect(bidRequest.data.osv).to.equal(ortb2.device.osv); - expect(bidRequest.data.foddid).to.equal(ortb2.device.ext.fiftyonedegrees_deviceId); + expect(bidRequest.data.foddid).to.equal(ortb2.device.ext.fod.deviceId); expect(bidRequest.data.ip).to.equal(ortb2.device.ip); expect(bidRequest.data.ipv6).to.equal(ortb2.device.ipv6); expect(bidRequest.data.lmt).to.equal(ortb2.device.lmt); From 0212111e792c0c6d779f017c4d83072956eff0a6 Mon Sep 17 00:00:00 2001 From: Chris Southern <79725079+southern-growthcode@users.noreply.github.com> Date: Fri, 29 May 2026 22:42:27 -0400 Subject: [PATCH 015/124] Acxiom's realid userID prebid module (GCD-559) (#14948) * Add Acxiom Real ID Submodule to User ID system * Update Acxiom Real ID Submodule to use POST requests with JSON payload and simplify API URL handling * Simplify Acxiom Real ID Submodule by removing unused log prefix and redundant logInfo calls * Update Acxiom Real ID API endpoint * Refactor Acxiom Real ID Submodule to handle stored IDs and improve decode logic * Expand Acxiom Real ID Submodule to enforce consent-based suppression and add GPP (US privacy) handling * Update Acxiom Real ID to delete tokens with all suffixes for better consent compliance * Update Acxiom Real ID to handle userAgent retrieval using `getWindowSelf` for improved compatibility * Add detailed typedefs for Acxiom Real ID configuration and parameters * Migrate Acxiom Real ID Submodule to TypeScript for improved type safety and module clarity --------- Co-authored-by: Rameez Israr --- modules/.submodules.json | 1 + modules/acxiomRealIdSystem.md | 84 +++ modules/acxiomRealIdSystem.ts | 247 +++++++ modules/userId/eids.md | 7 + modules/userId/userId.md | 10 + test/spec/modules/acxiomRealIdSystem_spec.js | 640 +++++++++++++++++++ 6 files changed, 989 insertions(+) create mode 100644 modules/acxiomRealIdSystem.md create mode 100644 modules/acxiomRealIdSystem.ts create mode 100644 test/spec/modules/acxiomRealIdSystem_spec.js diff --git a/modules/.submodules.json b/modules/.submodules.json index b81f2e72e5a..c5c4100603c 100644 --- a/modules/.submodules.json +++ b/modules/.submodules.json @@ -3,6 +3,7 @@ "userId": [ "33acrossIdSystem", "abtshieldIdSystem", + "acxiomRealIdSystem", "admixerIdSystem", "adqueryIdSystem", "adplusIdSystem", diff --git a/modules/acxiomRealIdSystem.md b/modules/acxiomRealIdSystem.md new file mode 100644 index 00000000000..58566c85975 --- /dev/null +++ b/modules/acxiomRealIdSystem.md @@ -0,0 +1,84 @@ +## Acxiom Real ID Submodule + +Acxiom Real ID module surfaces an Acxiom Real ID in the bid request via the Prebid User ID system. The module sends a POST request to the lookup API with the partner ID, source ID, and user agent, and stores the returned token for use in bid requests. + +## Building Prebid with Acxiom Real ID Support + +Add the Acxiom Real ID submodule to your Prebid.js package: + +``` +gulp build --modules=acxiomRealIdSystem,userId +``` + +## Configuration + +The following configuration parameters are available: + +| Param | Scope | Type | Description | Example | +| --- | --- | --- | --- | --- | +| name | Required | String | Module identifier | `'acxiomRealId'` | +| params | Required | Object | Module configuration | | +| params.partnerId | Required | String | Partner ID issued by GrowthCode on behalf of Acxiom | `'ABC123'` | +| params.hem | Optional | String | SHA-256 hashed email for improved match rate | `'a1b2c3...'` | +| params.sourceId | Optional | String | EID source to request from the lookup API. Defaults to `'acxiom.id'` | `'acxiom.id'` | +| params.apiUrl | Optional | String | Override the full API endpoint URL | `'https://ids.api.gcprivacy.id/v1/eid/l'` | +| storage | Required | Object | Storage configuration | | +| storage.type | Required | String | Storage type | `'html5'` | +| storage.name | Required | String | Storage key | `'acxiomRealId'` | +| storage.expires | Required | Number | TTL in days | `7` | + +### Example Configuration + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'acxiomRealId', + params: { + partnerId: 'YOUR_PARTNER_ID' + }, + storage: { + type: 'html5', + name: 'acxiomRealId', + expires: 7 + } + }] + } +}); +``` + +### Configuration with Custom API URL and Hashed Email + +```javascript +pbjs.setConfig({ + userSync: { + userIds: [{ + name: 'acxiomRealId', + params: { + partnerId: 'YOUR_PARTNER_ID', + hem: 'sha256_hashed_email_here', + apiUrl: 'https://ids.api.gcprivacy.id/v1/eid/l' + }, + storage: { + type: 'html5', + name: 'acxiomRealId', + expires: 7 + } + }] + } +}); +``` + +### EID Output + +The module produces the following EID structure in `user.ext.eids`: + +```json +{ + "source": "acxiom.id", + "uids": [{ + "id": "", + "atype": 1 + }] +} +``` diff --git a/modules/acxiomRealIdSystem.ts b/modules/acxiomRealIdSystem.ts new file mode 100644 index 00000000000..7776ce61e2a --- /dev/null +++ b/modules/acxiomRealIdSystem.ts @@ -0,0 +1,247 @@ +/** + * This module adds Acxiom Real ID to the User ID module + * The {@link module:modules/userId} module is required + * @module modules/acxiomRealIdSystem + * @requires module:modules/userId + */ + +import { submodule } from '../src/hook.js'; +import { ajaxBuilder } from '../src/ajax.js'; +import { getStorageManager } from '../src/storageManager.js'; +import { MODULE_TYPE_UID } from '../src/activities/modules.js'; +import { logError, getWindowSelf } from '../src/utils.js'; +import { gdprDataHandler, uspDataHandler, gppDataHandler } from '../src/adapterManager.js'; + +import type { IdProviderSpec, UserIdConfig, EID } from './userId/spec.ts'; +import type { AllConsentData } from '../src/consentHandler.ts'; + +const MODULE_NAME = 'acxiomRealId' as const; +const DEFAULT_API_URL = 'https://ids.api.gcprivacy.id/v1/eid/l'; +const DEFAULT_SOURCE_ID = 'acxiom.id'; +export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); + +export type AcxiomRealIdParams = { + /** Partner ID issued by GrowthCode on behalf of Acxiom */ + partnerId: string; + /** SHA-256 hashed email for improved match rate */ + hem?: string; + /** EID source to request from the lookup API. Defaults to 'acxiom.id' */ + sourceId?: string; + /** Override the full API endpoint URL */ + apiUrl?: string; +} + +export type AcxiomRealIdValue = { + /** The resolved Acxiom Real ID token */ + id: string; + /** Agent type per OpenRTB spec (1 = cookie/device, 2 = in-app, 3 = person-based) */ + atype: number; +} + +declare module './userId/spec' { + interface UserId { + acxiomRealId: AcxiomRealIdValue; + } + interface ProvidersToId { + acxiomRealId: 'acxiomRealId'; + } + interface ProviderParams { + acxiomRealId: AcxiomRealIdParams; + } +} + +const US_GPP_SID_API: Record = { + 7: 'usnat', + 8: 'usca', + 9: 'usva', + 10: 'usco', + 11: 'usut', + 12: 'usct' +}; + +interface GppSectionData { + SaleOptOut?: number; + SharingOptOut?: number; + [key: string]: unknown; +} + +interface GppData { + applicableSections?: number[]; + parsedSections?: Record; +} + +function flatSection(subsections: GppSectionData | GppSectionData[]): GppSectionData { + if (!Array.isArray(subsections)) return subsections; + return subsections.reduceRight((merged, section) => Object.assign(section, merged), {} as GppSectionData); +} + +function isGppOptedOut(gppData: GppData | null | undefined): boolean { + if (!gppData || !gppData.applicableSections || !gppData.parsedSections) { + return false; + } + for (const sid of gppData.applicableSections) { + const apiName = US_GPP_SID_API[sid]; + if (!apiName) continue; + const sectionData = flatSection(gppData.parsedSections[apiName]); + if (sectionData && (sectionData.SaleOptOut === 1 || sectionData.SharingOptOut === 1)) { + return true; + } + } + return false; +} + +function isConsentBlocked(consentData: Partial | undefined): boolean { + if (!consentData) { + return false; + } + + const gdpr = consentData.gdpr; + if (gdpr && (gdpr.gdprApplies || gdpr.consentString)) { + return true; + } + + const usp = consentData.usp; + if (usp && typeof usp === 'string' && usp.length >= 3 && usp.charAt(2) === 'Y') { + return true; + } + + if (isGppOptedOut(consentData.gpp as GppData)) { + return true; + } + + return false; +} + +function isConsentBlockedByHandlers(): boolean { + const gdpr = gdprDataHandler.getConsentData(); + if (gdpr && (gdpr.gdprApplies || gdpr.consentString)) { + return true; + } + const usp = uspDataHandler.getConsentData(); + if (usp && typeof usp === 'string' && usp.length >= 3 && usp.charAt(2) === 'Y') { + return true; + } + const gpp = gppDataHandler.getConsentData(); + if (isGppOptedOut(gpp as GppData)) { + return true; + } + return false; +} + +function deleteStoredToken(config: UserIdConfig) { + const storageName = config?.storage?.name || MODULE_NAME; + const expired = new Date(0).toUTCString(); + if (storage.localStorageIsEnabled()) { + ['', '_exp', '_cst', '_last'].forEach(suffix => { + storage.removeDataFromLocalStorage(`${storageName}${suffix}`); + }); + } + if (storage.cookiesAreEnabled()) { + ['', '_cst', '_last'].forEach(suffix => { + storage.setCookie(`${storageName}${suffix}`, '', expired); + }); + } +} + +function buildLookupUrl(apiUrl: string | undefined): string { + return (apiUrl || DEFAULT_API_URL).replace(/\/+$/, ''); +} + +export const acxiomRealIdSubmodule: IdProviderSpec = { + name: MODULE_NAME, + + decode(value, config) { + if (isConsentBlockedByHandlers()) { + deleteStoredToken(config); + return undefined; + } + if (value && typeof value === 'string') { + return { acxiomRealId: { id: value, atype: 1 } }; + } + if (value && typeof value === 'object' && (value as AcxiomRealIdValue).id) { + const v = value as AcxiomRealIdValue; + return { acxiomRealId: { id: v.id, atype: v.atype || 1 } }; + } + return undefined; + }, + + getId(config, consentData, storedId) { + const configParams = config?.params || {} as AcxiomRealIdParams; + const { partnerId, apiUrl, sourceId, hem } = configParams; + + if (!partnerId) { + logError('AcxiomRealId: partnerId is required.'); + return undefined; + } + + if (isConsentBlocked(consentData)) { + deleteStoredToken(config); + return undefined; + } + + if (storedId) { + return { id: storedId }; + } + + const url = buildLookupUrl(apiUrl); + const payload: Record = { + partnerId, + ip: '', + userAgent: getWindowSelf().navigator?.userAgent || '', + sourceId: sourceId || DEFAULT_SOURCE_ID + }; + if (hem) { + payload.hem = hem; + } + const body = JSON.stringify(payload); + + return { + callback: (cb) => { + const ajax = ajaxBuilder(); + ajax( + url, + { + success: (response) => { + try { + const parsed = JSON.parse(response); + const eids = parsed?.user?.eids; + const uid = eids?.[0]?.uids?.[0]; + if (uid?.id) { + cb({ id: uid.id, atype: uid.atype }); + } else { + cb(undefined); + } + } catch (e) { + cb(undefined); + } + }, + error: () => { + cb(undefined); + } + }, + body, + { + method: 'POST', + contentType: 'application/json', + withCredentials: true + } + ); + } + }; + }, + + onDataDeletionRequest(config) { + deleteStoredToken(config); + }, + + eids: { + 'acxiomRealId': (values) => { + return values.map(data => ({ + source: DEFAULT_SOURCE_ID, + uids: [{ id: data.id, atype: data.atype as EID['uids'][number]['atype'] }] + })); + } + } +}; + +submodule('userId', acxiomRealIdSubmodule); diff --git a/modules/userId/eids.md b/modules/userId/eids.md index b33fbbe241c..c19002d9b3a 100644 --- a/modules/userId/eids.md +++ b/modules/userId/eids.md @@ -19,6 +19,13 @@ userIdAsEids = [ } }] }, + { + source: 'acxiom.id', + uids: [{ + id: 'some-random-id-value', + atype: 1 + }] + }, { source: 'utiq.com', uids: [{ diff --git a/modules/userId/userId.md b/modules/userId/userId.md index 857a76165ce..e538a78b7e7 100644 --- a/modules/userId/userId.md +++ b/modules/userId/userId.md @@ -9,6 +9,16 @@ pbjs.setConfig({ uid2: ['uid2', 'liveIntentId'] } userIds: [{ + name: "acxiomRealId", + params: { + partnerId: "YOUR_PARTNER_ID" // Example Partner ID + }, + storage: { + type: "html5", + name: "acxiomRealId", + expires: 7 + } + }, { name: "33acrossId", storage: { type: "cookie", diff --git a/test/spec/modules/acxiomRealIdSystem_spec.js b/test/spec/modules/acxiomRealIdSystem_spec.js new file mode 100644 index 00000000000..b534a2bbc03 --- /dev/null +++ b/test/spec/modules/acxiomRealIdSystem_spec.js @@ -0,0 +1,640 @@ +import { acxiomRealIdSubmodule, storage } from 'modules/acxiomRealIdSystem.ts'; +import * as ajaxLib from 'src/ajax.js'; +import { gdprDataHandler, uspDataHandler, gppDataHandler } from 'src/adapterManager.js'; +import { expect } from 'chai'; + +const PARTNER_ID = 'TEST_PARTNER_01'; +const REAL_ID_TOKEN = 'acxiom-real-id-token-abc123'; +const HEM = 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855'; +const STORAGE_NAME = 'acxiomRealId'; + +function makeEidResponse(token, atype) { + return JSON.stringify({ + requestId: '4b61d73a-test', + generatedAt: '2026-01-27T19:27:40Z', + expiresAt: '2026-02-26T19:27:40Z', + user: { + eids: [{ + source: 'acxiom.id', + uids: [{ id: token, atype: atype || 1 }] + }] + } + }); +} + +function makeEmptyResponse() { + return JSON.stringify({ + requestId: '4b61d73a-test', + generatedAt: '2026-01-27T19:27:40Z', + user: { + eids: [] + } + }); +} + +describe('acxiomRealIdSystem', () => { + describe('name', () => { + it('should expose the correct module name', () => { + expect(acxiomRealIdSubmodule.name).to.equal('acxiomRealId'); + }); + }); + + describe('decode', () => { + it('should return acxiomRealId object when given an object with id and atype', () => { + const stored = { id: REAL_ID_TOKEN, atype: 1 }; + const result = acxiomRealIdSubmodule.decode(stored); + expect(result).to.deep.equal({ acxiomRealId: { id: REAL_ID_TOKEN, atype: 1 } }); + }); + + it('should handle legacy string values with default atype', () => { + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN); + expect(result).to.deep.equal({ acxiomRealId: { id: REAL_ID_TOKEN, atype: 1 } }); + }); + + it('should preserve atype from stored object', () => { + const stored = { id: REAL_ID_TOKEN, atype: 3 }; + const result = acxiomRealIdSubmodule.decode(stored); + expect(result).to.deep.equal({ acxiomRealId: { id: REAL_ID_TOKEN, atype: 3 } }); + }); + + it('should return undefined for null', () => { + expect(acxiomRealIdSubmodule.decode(null)).to.be.undefined; + }); + + it('should return undefined for empty string', () => { + expect(acxiomRealIdSubmodule.decode('')).to.be.undefined; + }); + + it('should return undefined for object without id', () => { + expect(acxiomRealIdSubmodule.decode({ atype: 1 })).to.be.undefined; + }); + + describe('post-load consent suppression', () => { + let gdprStub, uspStub, gppStub; + let removeLocalStorageStub, setCookieStub; + + beforeEach(() => { + gdprStub = sinon.stub(gdprDataHandler, 'getConsentData'); + uspStub = sinon.stub(uspDataHandler, 'getConsentData'); + gppStub = sinon.stub(gppDataHandler, 'getConsentData'); + gdprStub.returns(null); + uspStub.returns(null); + gppStub.returns(null); + removeLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage'); + setCookieStub = sinon.stub(storage, 'setCookie'); + sinon.stub(storage, 'localStorageIsEnabled').returns(true); + sinon.stub(storage, 'cookiesAreEnabled').returns(true); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should return EID when no consent signals block', () => { + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN); + expect(result).to.deep.equal({ acxiomRealId: { id: REAL_ID_TOKEN, atype: 1 } }); + }); + + it('should suppress and delete token with all suffixes when GDPR handler reports gdprApplies', () => { + gdprStub.returns({ gdprApplies: true, consentString: 'BOtest' }); + const config = { storage: { name: STORAGE_NAME } }; + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN, config); + expect(result).to.be.undefined; + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + ['', '_cst', '_last'].forEach(suffix => { + expect(setCookieStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + + it('should suppress and delete token with all suffixes when USP handler reports opt-out', () => { + uspStub.returns('1YYN'); + const config = { storage: { name: STORAGE_NAME } }; + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN, config); + expect(result).to.be.undefined; + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + + it('should suppress and delete token with all suffixes when GPP handler reports SaleOptOut', () => { + gppStub.returns({ + applicableSections: [7], + parsedSections: { usnat: { Version: 1, SaleOptOut: 1, SharingOptOut: 2 } } + }); + const config = { storage: { name: STORAGE_NAME } }; + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN, config); + expect(result).to.be.undefined; + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + + it('should suppress and delete token with all suffixes when GPP handler reports SharingOptOut', () => { + gppStub.returns({ + applicableSections: [8], + parsedSections: { usca: { Version: 1, SaleOptOut: 2, SharingOptOut: 1 } } + }); + const config = { storage: { name: STORAGE_NAME } }; + const result = acxiomRealIdSubmodule.decode(REAL_ID_TOKEN, config); + expect(result).to.be.undefined; + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + }); + }); + + describe('getId', () => { + it('should return undefined when partnerId is missing', () => { + const result = acxiomRealIdSubmodule.getId({ params: {} }); + expect(result).to.be.undefined; + }); + + it('should return undefined when params are missing', () => { + const result = acxiomRealIdSubmodule.getId({}); + expect(result).to.be.undefined; + }); + + it('should return a callback function', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + expect(result).to.have.property('callback'); + expect(result.callback).to.be.a('function'); + }); + + describe('consent suppression', () => { + describe('EU/UK — TCF passive suppression', () => { + it('should suppress when gdprApplies is true and consentString is present', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { gdpr: { gdprApplies: true, consentString: 'BOtest' } } + ); + expect(result).to.be.undefined; + }); + + it('should suppress when gdprApplies is true even without consentString', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { gdpr: { gdprApplies: true } } + ); + expect(result).to.be.undefined; + }); + + it('should suppress when consentString is present even if gdprApplies is false', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { gdpr: { gdprApplies: false, consentString: 'BOtest' } } + ); + expect(result).to.be.undefined; + }); + }); + + describe('US — CCPA', () => { + it('should suppress when us_privacy position 3 = Y (opted out of sale)', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { usp: '1YYN' } + ); + expect(result).to.be.undefined; + }); + + it('should not suppress when us_privacy position 3 = N (not opted out)', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { usp: '1YNN' } + ); + expect(result).to.have.property('callback'); + }); + + it('should not suppress when us_privacy string is too short', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { usp: '1Y' } + ); + expect(result).to.have.property('callback'); + }); + }); + + describe('US — GPP', () => { + it('should suppress when GPP usnat SaleOptOut = 1', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [7], + parsedSections: { usnat: { Version: 1, SaleOptOut: 1, SharingOptOut: 2 } } + } + } + ); + expect(result).to.be.undefined; + }); + + it('should suppress when GPP usnat SharingOptOut = 1', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [7], + parsedSections: { usnat: { Version: 1, SaleOptOut: 2, SharingOptOut: 1 } } + } + } + ); + expect(result).to.be.undefined; + }); + + it('should suppress when GPP usca (California) SaleOptOut = 1', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [8], + parsedSections: { usca: { Version: 1, SaleOptOut: 1, SharingOptOut: 2 } } + } + } + ); + expect(result).to.be.undefined; + }); + + it('should not suppress when GPP section has no opt-out', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [7], + parsedSections: { usnat: { Version: 1, SaleOptOut: 2, SharingOptOut: 2 } } + } + } + ); + expect(result).to.have.property('callback'); + }); + + it('should not suppress when applicable section is non-US', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [2], + parsedSections: {} + } + } + ); + expect(result).to.have.property('callback'); + }); + + it('should handle subsection arrays by flattening', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + { + gpp: { + applicableSections: [7], + parsedSections: { usnat: [{ Version: 1, SaleOptOut: 2 }, { SaleOptOut: 1 }] } + } + } + ); + expect(result).to.be.undefined; + }); + }); + + describe('token deletion on consent block', () => { + let removeLocalStorageStub; + let setCookieStub; + + beforeEach(() => { + removeLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage'); + setCookieStub = sinon.stub(storage, 'setCookie'); + sinon.stub(storage, 'localStorageIsEnabled').returns(true); + sinon.stub(storage, 'cookiesAreEnabled').returns(true); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should delete stored token and all suffixes when consent is blocked', () => { + acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID }, storage: { name: STORAGE_NAME } }, + { usp: '1YYN' } + ); + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + ['', '_cst', '_last'].forEach(suffix => { + expect(setCookieStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + }); + + it('should not suppress when no consent data is provided', () => { + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + expect(result).to.have.property('callback'); + }); + }); + + describe('API call', () => { + let ajaxBuilderStub; + + afterEach(() => { + if (ajaxBuilderStub) { + ajaxBuilderStub.restore(); + ajaxBuilderStub = null; + } + }); + + it('should POST to the default API URL with partnerId and default sourceId in body', (done) => { + let capturedUrl, capturedBody, capturedOptions; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks, body, options) => { + capturedUrl = url; + capturedBody = body; + capturedOptions = options; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(capturedUrl).to.equal('https://ids.api.gcprivacy.id/v1/eid/l'); + const payload = JSON.parse(capturedBody); + expect(payload.partnerId).to.equal(PARTNER_ID); + expect(payload.sourceId).to.equal('acxiom.id'); + expect(payload.userAgent).to.be.a('string'); + expect(payload.ip).to.equal(''); + expect(capturedOptions.method).to.equal('POST'); + expect(capturedOptions.contentType).to.equal('application/json'); + expect(capturedOptions.withCredentials).to.be.true; + expect(id).to.deep.equal({ id: REAL_ID_TOKEN, atype: 1 }); + done(); + }); + }); + + it('should include HEM in POST body when provided', (done) => { + let capturedBody; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks, body) => { + capturedBody = body; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID, hem: HEM } }, + {} + ); + + result.callback((id) => { + const payload = JSON.parse(capturedBody); + expect(payload.hem).to.equal(HEM); + expect(id).to.deep.equal({ id: REAL_ID_TOKEN, atype: 1 }); + done(); + }); + }); + + it('should not include HEM in POST body when not provided', (done) => { + let capturedBody; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks, body) => { + capturedBody = body; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback(() => { + const payload = JSON.parse(capturedBody); + expect(payload).to.not.have.property('hem'); + done(); + }); + }); + + it('should use custom sourceId in POST body when provided', (done) => { + let capturedBody; + const customSourceId = 'custom.source'; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks, body) => { + capturedBody = body; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID, sourceId: customSourceId } }, + {} + ); + + result.callback((id) => { + const payload = JSON.parse(capturedBody); + expect(payload.sourceId).to.equal(customSourceId); + expect(id).to.deep.equal({ id: REAL_ID_TOKEN, atype: 1 }); + done(); + }); + }); + + it('should use custom API URL when provided', (done) => { + let capturedUrl; + const customUrl = 'https://custom.example.com/v1/eid/l'; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + capturedUrl = url; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID, apiUrl: customUrl } }, + {} + ); + + result.callback((id) => { + expect(capturedUrl).to.equal(customUrl); + expect(id).to.deep.equal({ id: REAL_ID_TOKEN, atype: 1 }); + done(); + }); + }); + + it('should strip trailing slashes from custom API URL', (done) => { + let capturedUrl; + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + capturedUrl = url; + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID, apiUrl: 'https://custom.example.com/v1/eid/l///' } }, + {} + ); + + result.callback(() => { + expect(capturedUrl).to.equal('https://custom.example.com/v1/eid/l'); + done(); + }); + }); + + it('should preserve atype from API response', (done) => { + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + callbacks.success(makeEidResponse(REAL_ID_TOKEN, 3)); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(id).to.deep.equal({ id: REAL_ID_TOKEN, atype: 3 }); + done(); + }); + }); + + it('should call callback with undefined on no-match response', (done) => { + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + callbacks.success(JSON.stringify({ requestId: 'test', user: {} })); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(id).to.be.undefined; + done(); + }); + }); + + it('should call callback with undefined when eids array is empty', (done) => { + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + callbacks.success(makeEmptyResponse()); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(id).to.be.undefined; + done(); + }); + }); + + it('should call callback with undefined on API error', (done) => { + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + callbacks.error('server error'); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(id).to.be.undefined; + done(); + }); + }); + + it('should call callback with undefined on malformed JSON response', (done) => { + ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + (url, callbacks) => { + callbacks.success('not json'); + } + ); + + const result = acxiomRealIdSubmodule.getId( + { params: { partnerId: PARTNER_ID } }, + {} + ); + + result.callback((id) => { + expect(id).to.be.undefined; + done(); + }); + }); + }); + }); + + describe('onDataDeletionRequest', () => { + let removeLocalStorageStub; + let setCookieStub; + + beforeEach(() => { + removeLocalStorageStub = sinon.stub(storage, 'removeDataFromLocalStorage'); + setCookieStub = sinon.stub(storage, 'setCookie'); + sinon.stub(storage, 'localStorageIsEnabled').returns(true); + sinon.stub(storage, 'cookiesAreEnabled').returns(true); + }); + + afterEach(() => { + sinon.restore(); + }); + + it('should delete token and all suffixes from localStorage and cookies', () => { + acxiomRealIdSubmodule.onDataDeletionRequest( + { storage: { name: STORAGE_NAME } } + ); + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + ['', '_cst', '_last'].forEach(suffix => { + expect(setCookieStub.calledWith(`${STORAGE_NAME}${suffix}`)).to.be.true; + }); + }); + + it('should use module name as fallback and delete all suffixes when storage name is not configured', () => { + acxiomRealIdSubmodule.onDataDeletionRequest({}); + ['', '_exp', '_cst', '_last'].forEach(suffix => { + expect(removeLocalStorageStub.calledWith(`acxiomRealId${suffix}`)).to.be.true; + }); + }); + }); + + describe('eids', () => { + it('should be a function that builds EID from decoded data', () => { + const eidFn = acxiomRealIdSubmodule.eids.acxiomRealId; + expect(eidFn).to.be.a('function'); + }); + + it('should produce correct EID with atype from data', () => { + const eidFn = acxiomRealIdSubmodule.eids.acxiomRealId; + const result = eidFn([{ id: REAL_ID_TOKEN, atype: 1 }]); + expect(result).to.deep.equal([{ + source: 'acxiom.id', + uids: [{ id: REAL_ID_TOKEN, atype: 1 }] + }]); + }); + + it('should preserve atype 3 from data', () => { + const eidFn = acxiomRealIdSubmodule.eids.acxiomRealId; + const result = eidFn([{ id: REAL_ID_TOKEN, atype: 3 }]); + expect(result).to.deep.equal([{ + source: 'acxiom.id', + uids: [{ id: REAL_ID_TOKEN, atype: 3 }] + }]); + }); + }); +}); From 2c943f2fea58fd75d24d7f1ff0615df502e1b17b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Lespagnol?= Date: Sat, 30 May 2026 20:33:33 +0200 Subject: [PATCH 016/124] Ogury Bid Adapter: add instream video support (#14962) --- modules/oguryBidAdapter.js | 40 ++- modules/oguryBidAdapter.md | 22 +- test/spec/modules/oguryBidAdapter_spec.js | 294 +++++++++++++++++++++- 3 files changed, 338 insertions(+), 18 deletions(-) diff --git a/modules/oguryBidAdapter.js b/modules/oguryBidAdapter.js index 96b03ad6737..587a53dd078 100644 --- a/modules/oguryBidAdapter.js +++ b/modules/oguryBidAdapter.js @@ -1,6 +1,6 @@ 'use strict'; -import { BANNER } from '../src/mediaTypes.js'; +import { BANNER, VIDEO } from '../src/mediaTypes.js'; import { getWindowSelf, getWindowTop, isFn, deepAccess, isPlainObject, deepSetValue, mergeDeep } from '../src/utils.js'; import { getDevicePixelRatio } from '../libraries/devicePixelRatio/devicePixelRatio.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; @@ -14,13 +14,12 @@ const DEFAULT_TIMEOUT = 1000; const BID_HOST = 'https://mweb-hb.presage.io/api/header-bidding-request'; const TIMEOUT_MONITORING_HOST = 'https://ms-ads-monitoring-events.presage.io'; const MS_COOKIE_SYNC_DOMAIN = 'https://ms-cookie-sync.presage.io'; -const ADAPTER_VERSION = '2.0.6'; +const ADAPTER_VERSION = '2.1.0'; export const ortbConverterProps = { context: { netRevenue: true, - ttl: 60, - mediaType: 'banner' + ttl: 60 }, request(buildRequest, imps, bidderRequest, context) { @@ -73,9 +72,13 @@ export const ortbConverterProps = { export const converter = ortbConverter(ortbConverterProps); function isBidRequestValid(bid) { - const adUnitSizes = getAdUnitSizes(bid); + const bannerSizes = getAdUnitSizes(bid); + const videoPlayerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); + + const hasBannerSize = Array.isArray(bannerSizes) && bannerSizes.length > 0; + const hasVideoSize = Array.isArray(videoPlayerSize) && videoPlayerSize.length > 0; + const isValidSize = hasBannerSize || hasVideoSize; - const isValidSize = (Boolean(adUnitSizes) && adUnitSizes.length > 0); const hasAssetKeyAndAdUnitId = !!deepAccess(bid, 'params.adUnitId') && !!deepAccess(bid, 'params.assetKey'); const hasPublisherIdAndAdUnitCode = !!deepAccess(bid, 'ortb2.site.publisher.id') && !!bid.adUnitCode; @@ -128,13 +131,24 @@ function getFloor(bid) { if (!isFn(bid.getFloor)) { return 0; } - const floorResult = bid.getFloor({ - currency: 'USD', - mediaType: 'banner', - size: '*' - }); - return (isPlainObject(floorResult) && floorResult.currency === 'USD') ? floorResult.floor : 0; + // Detect banner from mediaTypes.banner rather than via getAdUnitSizes — Prebid + // populates bid.sizes from mediaTypes.video.playerSize for video-only adUnits, + // which would otherwise make hasBanner falsely true and route the floor query + // to the banner mediaType for an imp that has no banner. + const hasBanner = Boolean(deepAccess(bid, 'mediaTypes.banner')); + const videoPlayerSize = deepAccess(bid, 'mediaTypes.video.playerSize'); + const hasVideo = Array.isArray(videoPlayerSize) && videoPlayerSize.length > 0; + + // Video-only bid: query the video floor. + // Banner-only and mixed banner+video bids: query the banner floor with the + // historical `size: '*'` wildcard. This preserves the exact pre-video-support + // behaviour for every banner imp (no regression on banner revenue) and treats + // mixed imps conservatively as banner. + const mediaType = (hasVideo && !hasBanner) ? VIDEO : BANNER; + const result = bid.getFloor({ currency: 'USD', mediaType, size: '*' }); + + return (isPlainObject(result) && result.currency === 'USD') ? result.floor : 0; } function getWindowContext() { @@ -163,7 +177,7 @@ function onTimeout(timeoutData) { export const spec = { code: BIDDER_CODE, gvlid: GVLID, - supportedMediaTypes: [BANNER], + supportedMediaTypes: [BANNER, VIDEO], isBidRequestValid, getUserSyncs, buildRequests, diff --git a/modules/oguryBidAdapter.md b/modules/oguryBidAdapter.md index 7264602de14..1a492d3ebb5 100644 --- a/modules/oguryBidAdapter.md +++ b/modules/oguryBidAdapter.md @@ -9,7 +9,7 @@ Maintainer: web.inventory@ogury.co # Description Module that connects to Ogury's SSP solution -Ogury bid adapter supports Banner media type. +Ogury bid adapter supports Banner and Video (instream) media types. # Test Parameters ``` @@ -33,6 +33,26 @@ Ogury bid adapter supports Banner media type. } } ] + }, + { + code: 'test-video', + mediaTypes: { + video: { + context: 'instream', + playerSize: [[640, 480]], + mimes: ['video/mp4'], + protocols: [2, 3, 5, 6] + } + }, + bids: [ + { + bidder: "ogury", + params: { + assetKey: 'OGY-CA41D116484F', + adUnitId: '2c4d61d0-90aa-0139-0cda-0242ac120004' + } + } + ] } ]; ``` \ No newline at end of file diff --git a/test/spec/modules/oguryBidAdapter_spec.js b/test/spec/modules/oguryBidAdapter_spec.js index 899c52b9278..eb731074457 100644 --- a/test/spec/modules/oguryBidAdapter_spec.js +++ b/test/spec/modules/oguryBidAdapter_spec.js @@ -41,10 +41,10 @@ describe('OguryBidAdapter', () => { floor: 0 }; - if (mediaType === 'banner') { - floorResult.floor = 4; - } else { + if (mediaType === 'video') { floorResult.floor = 1000; + } else { + floorResult.floor = 4; } return floorResult; @@ -676,7 +676,7 @@ describe('OguryBidAdapter', () => { expect(dataRequest.ext).to.deep.equal({ prebidversion: '$prebid.version$', - adapterversion: '2.0.6' + adapterversion: '2.1.0' }); expect(dataRequest.device).to.deep.equal({ @@ -815,6 +815,7 @@ describe('OguryBidAdapter', () => { id: 'advertId', impid: 'bidId', price: 100, + mtype: 1, nurl: 'url', adm: `
cookies
`, adomain: ['renault.fr'], @@ -834,6 +835,7 @@ describe('OguryBidAdapter', () => { id: 'advertId2', impid: 'bidId2', price: 150, + mtype: 1, nurl: 'url2', adm: `
cookies
`, adomain: ['peugeot.fr'], @@ -992,4 +994,288 @@ describe('OguryBidAdapter', () => { expect(JSON.parse(requests[0].requestBody).location).to.equal(window.location.href); }) }); + + describe('video support', () => { + let videoBidRequest; + let mixedBidRequest; + let windowTopStub; + + beforeEach(() => { + videoBidRequest = { + adUnitCode: 'adUnitCodeVideo', + ortb2Imp: { ext: { gpid: 'gpidVideo' } }, + auctionId: 'auctionId', + bidId: 'bidIdVideo', + bidder: 'ogury', + params: { + assetKey: 'OGY-assetkey', + adUnitId: 'adunitIdVideo' + }, + mediaTypes: { + video: { + playerSize: [[640, 480]], + context: 'outstream', + mimes: ['video/mp4'], + protocols: [2, 3, 5, 6] + } + }, + getFloor: ({ mediaType }) => ({ + currency: 'USD', + floor: mediaType === 'video' ? 7 : 3 + }), + transactionId: 'transactionIdVideo' + }; + + mixedBidRequest = utils.deepClone(bidRequests[0]); + mixedBidRequest.mediaTypes.video = { + playerSize: [[640, 480]], + context: 'outstream', + mimes: ['video/mp4'] + }; + + windowTopStub = sinon.stub(utils, 'getWindowTop'); + windowTopStub.returns({ location: { href: currentLocation }, devicePixelRatio: 1 }); + }); + + afterEach(() => { + windowTopStub.restore(); + }); + + describe('supportedMediaTypes', () => { + it('should declare both BANNER and VIDEO', () => { + expect(spec.supportedMediaTypes).to.include.members(['banner', 'video']); + }); + }); + + describe('isBidRequestValid', () => { + it('should validate a video-only bid with playerSize', () => { + expect(spec.isBidRequestValid(videoBidRequest)).to.be.true; + }); + + it('should not validate a video-only bid without playerSize', () => { + const invalidBid = utils.deepClone(videoBidRequest); + delete invalidBid.mediaTypes.video.playerSize; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + + it('should not validate a video-only bid with empty playerSize', () => { + const invalidBid = utils.deepClone(videoBidRequest); + invalidBid.mediaTypes.video.playerSize = []; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + + it('should validate a mixed banner+video bid', () => { + expect(spec.isBidRequestValid(mixedBidRequest)).to.be.true; + }); + + it('should validate a video-only bid using publisherId + adUnitCode flow', () => { + const validBid = utils.deepClone(videoBidRequest); + delete validBid.params.adUnitId; + delete validBid.params.assetKey; + validBid.ortb2 = { site: { publisher: { id: 'publisherId' } } }; + expect(spec.isBidRequestValid(validBid)).to.be.true; + }); + + it('should not validate a bid with empty mediaTypes.banner and no video', () => { + // Guard the edge case where mediaTypes.banner is declared but carries no + // sizes. isBidRequestValid must reject it — neither banner sizes nor + // video playerSize are present. This keeps getFloor's banner detection + // (Boolean(mediaTypes.banner)) safe: a malformed bid never reaches it. + const invalidBid = utils.deepClone(bidRequests[0]); + invalidBid.mediaTypes = { banner: {} }; + delete invalidBid.sizes; + expect(spec.isBidRequestValid(invalidBid)).to.be.false; + }); + }); + + if (FEATURES.VIDEO) { + describe('buildRequests', () => { + it('should build imp.video from mediaTypes.video.playerSize', () => { + const request = spec.buildRequests([videoBidRequest], { ...bidderRequestBase, bids: [videoBidRequest] }); + expect(request.data.imp[0].video).to.exist; + expect(request.data.imp[0].video.w).to.equal(640); + expect(request.data.imp[0].video.h).to.equal(480); + expect(request.data.imp[0].banner).to.be.an('undefined'); + }); + + it('should set imp.bidfloor from video floor for video-only bids', () => { + const request = spec.buildRequests([videoBidRequest], { ...bidderRequestBase, bids: [videoBidRequest] }); + expect(request.data.imp[0].bidfloor).to.equal(7); + }); + + it('should build both imp.banner and imp.video for mixed bids', () => { + const request = spec.buildRequests([mixedBidRequest], { ...bidderRequestBase, bids: [mixedBidRequest] }); + expect(request.data.imp[0].banner).to.exist; + expect(request.data.imp[0].video).to.exist; + }); + + it('should use banner floor on mixed banner+video bids (preserves pre-video banner behavior)', () => { + const request = spec.buildRequests([mixedBidRequest], { ...bidderRequestBase, bids: [mixedBidRequest] }); + expect(request.data.imp[0].bidfloor).to.equal(4); + }); + + it('should use banner floor on mixed bids even when video floor is higher', () => { + const bid = utils.deepClone(mixedBidRequest); + bid.getFloor = ({ mediaType }) => ({ + currency: 'USD', + floor: mediaType === 'video' ? 10 : 5 + }); + + const request = spec.buildRequests([bid], { ...bidderRequestBase, bids: [bid] }); + expect(request.data.imp[0].bidfloor).to.equal(5); + }); + + it('should not set imp.bidfloor on a video-only bid when getFloor is not a function', () => { + const bid = utils.deepClone(videoBidRequest); + bid.getFloor = undefined; + + const request = spec.buildRequests([bid], { ...bidderRequestBase, bids: [bid] }); + expect(request.data.imp[0].bidfloor).to.be.an('undefined'); + }); + + it('should query video floor on a video-only bid even when bid.sizes is auto-populated from playerSize', () => { + // Prebid populates bid.sizes from mediaTypes.video.playerSize when no + // banner mediaType is declared. The adapter must not interpret that as + // a banner imp — banner detection lives on mediaTypes.banner, not on + // bid.sizes / getAdUnitSizes. + const bid = utils.deepClone(videoBidRequest); + bid.sizes = [[640, 480]]; + bid.getFloor = ({ mediaType }) => ({ + currency: 'USD', + floor: mediaType === 'video' ? 9 : 2 + }); + + const request = spec.buildRequests([bid], { ...bidderRequestBase, bids: [bid] }); + expect(request.data.imp[0].bidfloor).to.equal(9); + }); + + it('should not query video floor when mediaTypes.video is declared without playerSize', () => { + const bid = utils.deepClone(bidRequests[0]); + bid.mediaTypes.video = { context: 'outstream', mimes: ['video/mp4'] }; + bid.getFloor = ({ mediaType }) => ({ + currency: 'USD', + floor: mediaType === 'video' ? 1 : 6 + }); + + const request = spec.buildRequests([bid], { ...bidderRequestBase, bids: [bid] }); + expect(request.data.imp[0].bidfloor).to.equal(6); + }); + + it('should pass mediaType:"banner" to getFloor on a banner-only bid (ISO with pre-video behaviour)', () => { + // Blindage non-régression banner: detect that the new + // Boolean(mediaTypes.banner) check still routes pure banner bids to + // the banner floor query. If a future refactor reverses the + // hasBanner/hasVideo branching, this test will fail. + // We exercise spec.getFloor directly (not via buildRequests) to + // isolate the adapter's own getFloor invocation from the + // ortbConverter auto-floor processor (which also calls + // bid.getFloor when the priceFloors module is loaded by a sibling + // spec in the same Karma chunk). + const bid = utils.deepClone(bidRequests[0]); + const calls = []; + bid.getFloor = (args) => { + calls.push(args); + return { currency: 'USD', floor: 3 }; + }; + + const floor = spec.getFloor(bid); + expect(calls).to.have.lengthOf(1); + expect(calls[0].mediaType).to.equal('banner'); + expect(calls[0].size).to.equal('*'); + expect(floor).to.equal(3); + }); + + it('should query banner floor with size:"*" (wildcard) rather than iterating per banner size', () => { + const bid = utils.deepClone(bidRequests[0]); + bid.mediaTypes.banner.sizes = [[300, 250], [728, 90]]; + bid.getFloor = ({ size }) => { + if (size === '*') { + return { currency: 'USD', floor: 99 }; + } + return { currency: 'USD', floor: 1 }; + }; + + const request = spec.buildRequests([bid], { ...bidderRequestBase, bids: [bid] }); + expect(request.data.imp[0].bidfloor).to.equal(99); + }); + }); + + describe('interpretResponse', () => { + it('should mark bidResponse.mediaType as video for a video imp', () => { + const request = spec.buildRequests([videoBidRequest], { ...bidderRequestBase, bids: [videoBidRequest] }); + const videoOrtbResponse = { + body: { + id: 'video_response', + seatbid: [{ + bid: [{ + id: 'advertIdVideo', + impid: 'bidIdVideo', + price: 12, + mtype: 2, + nurl: 'urlVideo', + adm: '', + adomain: ['ogury.com'], + w: 640, + h: 480 + }] + }] + } + }; + + const result = spec.interpretResponse(videoOrtbResponse, request); + expect(result).to.have.lengthOf(1); + expect(result[0].mediaType).to.equal('video'); + expect(result[0].vastXml).to.contain(' { + let instreamBidRequest; + + beforeEach(() => { + instreamBidRequest = utils.deepClone(videoBidRequest); + instreamBidRequest.mediaTypes.video.context = 'instream'; + }); + + it('should validate an instream video bid with playerSize', () => { + expect(spec.isBidRequestValid(instreamBidRequest)).to.be.true; + }); + + it('should build imp.video from an instream bid', () => { + const request = spec.buildRequests([instreamBidRequest], { ...bidderRequestBase, bids: [instreamBidRequest] }); + expect(request.data.imp[0].video).to.exist; + expect(request.data.imp[0].video.w).to.equal(640); + expect(request.data.imp[0].video.h).to.equal(480); + expect(request.data.imp[0].banner).to.be.an('undefined'); + }); + + it('should return a video bid with vastXml from a VAST instream response', () => { + const request = spec.buildRequests([instreamBidRequest], { ...bidderRequestBase, bids: [instreamBidRequest] }); + const instreamOrtbResponse = { + body: { + id: 'instream_response', + seatbid: [{ + bid: [{ + id: 'advertIdInstream', + impid: 'bidIdVideo', + price: 15, + mtype: 2, + nurl: 'urlInstream', + adm: '', + adomain: ['ogury.com'], + w: 640, + h: 480 + }] + }] + } + }; + + const result = spec.interpretResponse(instreamOrtbResponse, request); + expect(result).to.have.lengthOf(1); + expect(result[0].mediaType).to.equal('video'); + expect(result[0].vastXml).to.contain(' Date: Mon, 1 Jun 2026 14:02:13 +0300 Subject: [PATCH 017/124] Vidazoo utils: Additional validation for request (#14952) * adding devicetype value validation to prevent errors from request in bidder * make a deep clone in order to validate value without changing device info in the initial object --------- Co-authored-by: Anna Yablonsky --- libraries/vidazooUtils/bidderUtils.js | 9 +++++++-- .../libraries/vidazooUtils/bidderUtils_spec.js | 15 +++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/libraries/vidazooUtils/bidderUtils.js b/libraries/vidazooUtils/bidderUtils.js index f3ca8f32a92..ace0e992ba7 100644 --- a/libraries/vidazooUtils/bidderUtils.js +++ b/libraries/vidazooUtils/bidderUtils.js @@ -7,7 +7,7 @@ import { parseUrl, triggerPixel, uniques, - getWinDimensions + getWinDimensions, deepClone } from '../../src/utils.js'; import { chunk } from '../chunk/chunk.js'; import { @@ -315,7 +315,12 @@ export function buildRequestData(bid, topWindowUrl, sizes, bidderRequest, bidder const userData = bidderRequest?.ortb2?.user?.data || []; const contentLang = bidderRequest?.ortb2?.site?.content?.language || document.documentElement.lang; const coppa = bidderRequest?.ortb2?.regs?.coppa ?? 0; - const device = bidderRequest?.ortb2?.device || {}; + const device = bidderRequest?.ortb2?.device ? deepClone(bidderRequest?.ortb2?.device) : {}; + + // delete device.devicetype if invalid + if (!Number.isInteger(device.devicetype)) { + delete device.devicetype; + } if (isFn(bid.getFloor)) { const floorInfo = bid.getFloor({ diff --git a/test/spec/libraries/vidazooUtils/bidderUtils_spec.js b/test/spec/libraries/vidazooUtils/bidderUtils_spec.js index b536fa7e76a..1c7673d1ab7 100644 --- a/test/spec/libraries/vidazooUtils/bidderUtils_spec.js +++ b/test/spec/libraries/vidazooUtils/bidderUtils_spec.js @@ -969,6 +969,21 @@ describe('Vidazoo Bidder Utils Tests', function () { expect(data.dsa).to.deep.equal({ required: 1 }); }); + it('should not include device.deviceType if original is not a number', function () { + const bidderRequest = { + ...baseBidderRequest, + ortb2: { + ...baseBidderRequest.ortb2, + regs: { coppa: 0, ext: { dsa: { required: 1 } } } + } + }; + bidderRequest.ortb2.device.devicetype = ''; + const data = utilities.buildRequestData( + baseBid, 'https://publisher.com', [[300, 250]], bidderRequest, 3000, storageMock, '1.0.0', 'vidazoo', null + ); + expect(data?.device?.devicetype).not.exist; + }); + it('should include placementId when set in params', function () { const bid = { ...baseBid, From 05c33887e63e47f96a315728de794cbf37cd56ad Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Mon, 1 Jun 2026 10:31:11 -0400 Subject: [PATCH 018/124] Adnow & DistroScale Adapters: remove deleted GVL IDs (#14966) ### Motivation - The IAB vendor list marks GVL IDs `1210` and `754` as deleted, so adapters must not advertise those vendor IDs. - Keep adapter runtime behavior unchanged while preventing Prebid from registering deleted TCF vendors. - Ensure module metadata and per-module disclosure entries no longer reference deleted vendor IDs or disclosure URLs. ### Description - Remove the `GVLID` constants and the `gvlid` fields from `modules/adnowBidAdapter.js` and `modules/distroscaleBidAdapter.js` so adapters no longer expose `1210` or `754`. - Update generated metadata files `metadata/modules.json`, `metadata/modules/adnowBidAdapter.json`, and `metadata/modules/distroscaleBidAdapter.json` to set the corresponding `gvlid` values to `null` and clear `disclosures`/`disclosureURL` entries. - Preserve the `ds` alias for DistroScale and leave all other adapter behaviour and supported media types unchanged. ### Testing - Ran `npx eslint modules/adnowBidAdapter.js modules/distroscaleBidAdapter.js --cache --cache-strategy content` and it completed successfully. - Ran the adapter unit tests with `npx gulp test --nolint --file test/spec/modules/adnowBidAdapter_spec.js` and `npx gulp test --nolint --file test/spec/modules/distroscaleBidAdapter_spec.js` and both test runs passed. - Performed metadata validation and JSON parse checks (build-time GVL/metadata checks) and they passed without errors. --- modules/adnowBidAdapter.js | 2 -- modules/distroscaleBidAdapter.js | 2 -- 2 files changed, 4 deletions(-) diff --git a/modules/adnowBidAdapter.js b/modules/adnowBidAdapter.js index d04ec1173f7..bd5e08820df 100644 --- a/modules/adnowBidAdapter.js +++ b/modules/adnowBidAdapter.js @@ -5,7 +5,6 @@ import { deepAccess, parseQueryStringParameters, parseSizesInput } from '../src/ import { convertOrtbRequestToProprietaryNative } from '../src/native.js'; const BIDDER_CODE = 'adnow'; -const GVLID = 1210; const ENDPOINT = 'https://n.nnowa.com/a'; /** @@ -29,7 +28,6 @@ const ENDPOINT = 'https://n.nnowa.com/a'; /** @type {BidderSpec} */ export const spec = { code: BIDDER_CODE, - gvlid: GVLID, supportedMediaTypes: [NATIVE, BANNER], /** diff --git a/modules/distroscaleBidAdapter.js b/modules/distroscaleBidAdapter.js index a2eea9e9130..85fffd0cce0 100644 --- a/modules/distroscaleBidAdapter.js +++ b/modules/distroscaleBidAdapter.js @@ -9,7 +9,6 @@ const LOG_WARN_PREFIX = 'DistroScale: '; const ENDPOINT = 'https://hb.jsrdn.com/hb?from=pbjs'; const DEFAULT_CURRENCY = 'USD'; const AUCTION_TYPE = 1; -const GVLID = 754; const UNDEF = undefined; const SUPPORTED_MEDIATYPES = [BANNER]; @@ -116,7 +115,6 @@ function _createImpressionObject(bid) { export const spec = { code: BIDDER_CODE, - gvlid: GVLID, supportedMediaTypes: SUPPORTED_MEDIATYPES, aliases: [SHORT_CODE], From 61f99593f7e6ceef8233e6fb07f0df727456c830 Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 1 Jun 2026 17:50:47 +0200 Subject: [PATCH 019/124] =?UTF-8?q?=F0=9F=90=9B=20Criteo=20Id=20System:=20?= =?UTF-8?q?store=20raw=20bidId=20values=20(#14973)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: v.raybaud --- modules/criteoIdSystem.js | 40 ++++++++++++++++++++---- test/spec/modules/criteoIdSystem_spec.js | 35 +++++++++++++++++++-- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/modules/criteoIdSystem.js b/modules/criteoIdSystem.js index 7b7207e9d6d..71da89e795d 100644 --- a/modules/criteoIdSystem.js +++ b/modules/criteoIdSystem.js @@ -39,6 +39,34 @@ const STORAGE_TYPE_COOKIES = 'cookie'; const pastDateString = new Date(0).toString(); const expirationString = new Date(timestamp() + cookiesMaxAge).toString(); +function normalizeBidId(value) { + let bidId = value; + let previousBidId; + + do { + previousBidId = bidId; + + if (bidId && typeof bidId === 'object' && typeof bidId.criteoId === 'string') { + bidId = bidId.criteoId; + } else if (typeof bidId === 'string' && bidId.trim().charAt(0) === '{') { + try { + const parsedBidId = JSON.parse(bidId); + if (parsedBidId && typeof parsedBidId.criteoId === 'string') { + bidId = parsedBidId.criteoId; + } else { + return bidId; + } + } catch (error) { + break; + } + } else { + break; + } + } while (bidId !== previousBidId); + + return typeof bidId === 'string' && bidId ? bidId : undefined; +} + function extractProtocolHost(url, returnOnlyHost = false) { const parsedUrl = parseUrl(url, { noDecodeWholeURL: true }) return returnOnlyHost @@ -100,7 +128,7 @@ function getCriteoDataFromStorage(submoduleConfig) { return { bundle: getFromStorage(submoduleConfig, bundleStorageKey), dnaBundle: getFromStorage(submoduleConfig, dnaBundleStorageKey), - bidId: getFromStorage(submoduleConfig, bididStorageKey), + bidId: normalizeBidId(getFromStorage(submoduleConfig, bididStorageKey)), } } @@ -194,8 +222,7 @@ function callCriteoUserSync(submoduleConfig, parsedCriteoData, callback) { if (jsonResponse.bidId) { saveOnStorage(submoduleConfig, bididStorageKey, jsonResponse.bidId, domain); - const criteoId = { criteoId: jsonResponse.bidId }; - callback(criteoId); + callback(jsonResponse.bidId); } else { deleteFromAllStorages(bididStorageKey, domain); callback(); @@ -224,13 +251,14 @@ export const criteoIdSubmodule = { * @returns {{criteoId: string} | undefined} */ decode(bidId) { - return bidId; + const normalizedBidId = normalizeBidId(bidId); + return normalizedBidId ? { criteoId: normalizedBidId } : undefined; }, /** * get the Criteo Id from local storages and initiate a new user sync * @function * @param {SubmoduleConfig} [submoduleConfig] - * @returns {{id: {criteoId: string} | undefined}}} + * @returns {{id: string | undefined, callback: function}} */ getId(submoduleConfig) { const localData = getCriteoDataFromStorage(submoduleConfig); @@ -238,7 +266,7 @@ export const criteoIdSubmodule = { const result = (callback) => callCriteoUserSync(submoduleConfig, localData, callback); return { - id: localData.bidId ? { criteoId: localData.bidId } : undefined, + id: localData.bidId, callback: result } }, diff --git a/test/spec/modules/criteoIdSystem_spec.js b/test/spec/modules/criteoIdSystem_spec.js index b82b4d56cb1..3a96285139b 100644 --- a/test/spec/modules/criteoIdSystem_spec.js +++ b/test/spec/modules/criteoIdSystem_spec.js @@ -8,6 +8,16 @@ import { expect } from 'chai/index.mjs'; const pastDateString = new Date(0).toString() +function wrapCriteoId(value, depth) { + let wrappedValue = value; + + for (let i = 0; i < depth; i++) { + wrappedValue = JSON.stringify({ criteoId: wrappedValue }); + } + + return wrappedValue; +} + describe('CriteoId module', function () { const cookiesMaxAge = 13 * 30 * 24 * 60 * 60 * 1000; @@ -63,6 +73,10 @@ describe('CriteoId module', function () { { submoduleConfig: { storage: { type: 'cookie' } }, cookie: undefined, localStorage: 'bidId2', expected: undefined }, { submoduleConfig: { storage: { type: 'html5' } }, cookie: 'bidId', localStorage: 'bidId2', expected: 'bidId2' }, { submoduleConfig: { storage: { type: 'html5' } }, cookie: 'bidId', localStorage: undefined, expected: undefined }, + { submoduleConfig: undefined, cookie: '{"criteoId":"bidId"}', localStorage: undefined, expected: 'bidId' }, + { submoduleConfig: undefined, cookie: '{"criteoId":"{\\"criteoId\\":\\"bidId\\"}"}', localStorage: undefined, expected: 'bidId' }, + { submoduleConfig: undefined, cookie: wrapCriteoId('bidId', 11), localStorage: undefined, expected: 'bidId' }, + { submoduleConfig: { storage: { type: 'html5' } }, cookie: 'bidId', localStorage: { criteoId: 'bidId2' }, expected: 'bidId2' }, ] storageTestCases.forEach(testCase => it('getId() should return the user id depending on the storage type enabled and the data available', function () { @@ -70,13 +84,28 @@ describe('CriteoId module', function () { getLocalStorageStub.withArgs('cto_bidid').returns(testCase.localStorage); const result = criteoIdSubmodule.getId(testCase.submoduleConfig); - expect(result.id).to.be.deep.equal(testCase.expected ? { criteoId: testCase.expected } : undefined); + expect(result.id).to.equal(testCase.expected); expect(result.callback).to.be.a('function'); })) it('decode() should return the bidId when it exists in local storages', function () { const id = criteoIdSubmodule.decode('testDecode'); - expect(id).to.equal('testDecode') + expect(id).to.deep.equal({ criteoId: 'testDecode' }) + }); + + it('decode() should unwrap serialized bidId values', function () { + const id = criteoIdSubmodule.decode('{"criteoId":"rawBidId"}'); + expect(id).to.deep.equal({ criteoId: 'rawBidId' }) + }); + + it('decode() should unwrap deeply nested serialized bidId values', function () { + const id = criteoIdSubmodule.decode(wrapCriteoId('rawBidId', 11)); + expect(id).to.deep.equal({ criteoId: 'rawBidId' }) + }); + + it('decode() should not throw on invalid serialized bidId values', function () { + const id = criteoIdSubmodule.decode('{"criteoId":'); + expect(id).to.deep.equal({ criteoId: '{"criteoId":' }) }); it('should call user sync url with the right params', function () { @@ -121,7 +150,7 @@ describe('CriteoId module', function () { it('should save bidId if it exists', function () { const result = criteoIdSubmodule.getId(response.submoduleConfig); result.callback((id) => { - expect(id).to.be.deep.equal(response.bidId ? { criteoId: response.bidId } : undefined); + expect(id).to.equal(response.bidId); }); const request = server.requests[0]; From d2dd18c0a18a816a7f6ce32a5617fa0aba1fb96c Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Mon, 1 Jun 2026 12:57:08 -0400 Subject: [PATCH 020/124] Core: add deprecated GPT targeting CodeQL check (#14967) --- .../queries/deprecatedGptTargetingApi.ql | 40 +++++++++++++++++++ modules/medianetAnalyticsAdapter.js | 4 +- modules/pubxaiAnalyticsAdapter.js | 5 +-- modules/sirdataRtdProvider.js | 2 +- 4 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 .github/codeql/queries/deprecatedGptTargetingApi.ql diff --git a/.github/codeql/queries/deprecatedGptTargetingApi.ql b/.github/codeql/queries/deprecatedGptTargetingApi.ql new file mode 100644 index 00000000000..a3ae4180835 --- /dev/null +++ b/.github/codeql/queries/deprecatedGptTargetingApi.ql @@ -0,0 +1,40 @@ +/** + * @id prebid/deprecated-gpt-targeting-api + * @name Deprecated GPT targeting API usage + * @kind problem + * @problem.severity warning + * @description GPT targeting should go through src/utils/gptTargeting so that the modern getConfig/setConfig API is used when available. + */ + +import javascript + +predicate legacyGptTargetingApi(string name) { + name = "setTargeting" or + name = "getTargeting" or + name = "getTargetingKeys" or + name = "clearTargeting" or + name = "updateTargetingFromMap" +} + +predicate allowedCompatibilityShim(PropAccess access) { + access.getFile().getBaseName() = "gptTargeting.ts" +} + +predicate gptLikeReceiver(Expr receiver) { + receiver.toString().matches("%googletag%") or + receiver.toString().matches("%pubads%") or + receiver.toString().matches("%gpt%") or + receiver.toString().matches("%Gpt%") or + receiver.toString().matches("%GPT%") or + receiver.toString().matches("%slot%") or + receiver.toString().matches("%Slot%") +} + +from PropAccess access, string apiName +where + access.getPropertyName() = apiName and + legacyGptTargetingApi(apiName) and + gptLikeReceiver(access.getBase()) and + not allowedCompatibilityShim(access) +select access, + "Use src/utils/gptTargeting helpers instead of deprecated GPT targeting API " + apiName + "." diff --git a/modules/medianetAnalyticsAdapter.js b/modules/medianetAnalyticsAdapter.js index 12959bda3ef..679d5d04ede 100644 --- a/modules/medianetAnalyticsAdapter.js +++ b/modules/medianetAnalyticsAdapter.js @@ -65,7 +65,7 @@ import { WINNING_BID_ABSENT_ERROR, ERROR_IWB_BID_MISSING, POST_ENDPOINT_RA } from '../libraries/medianetUtils/constants.js'; import { getGlobal } from '../src/prebidGlobal.js'; -import { getSlotTargetingKeys } from '../src/utils/gptTargeting.js'; +import { getSlotTargeting, getSlotTargetingKeys } from '../src/utils/gptTargeting.js'; // General Constants const ADAPTER_CODE = 'medianetAnalytics'; @@ -552,7 +552,7 @@ function setupSlotResponseReceivedListener() { }; getSlotTargetingKeys(slot) .filter((key) => key.startsWith(TARGETING_KEYS.AD_ID)) - .forEach((key) => setSlotResponseInf(slot.getTargeting(key)[0])); + .forEach((key) => setSlotResponseInf(getSlotTargeting(slot, key)[0])); }); }); } diff --git a/modules/pubxaiAnalyticsAdapter.js b/modules/pubxaiAnalyticsAdapter.js index 03749dc9ec1..ebdc693d8eb 100644 --- a/modules/pubxaiAnalyticsAdapter.js +++ b/modules/pubxaiAnalyticsAdapter.js @@ -12,7 +12,7 @@ import { getStorageManager } from '../src/storageManager.js'; import { deepAccess, parseSizesInput, getWindowLocation, buildUrl, cyrb53Hash } from '../src/utils.js'; -import { getSlotTargeting } from '../src/utils/gptTargeting.js'; +import { getSlotTargeting, getSlotTargetingKeys } from '../src/utils/gptTargeting.js'; let initOptions; @@ -100,8 +100,7 @@ const getAdServerDataForBid = (bid) => { const gptSlot = getGptSlotForAdUnitCode(bid); if (gptSlot) { return Object.fromEntries( - gptSlot - .getTargetingKeys() + getSlotTargetingKeys(gptSlot) .filter( (key) => key.startsWith('pubx-') || diff --git a/modules/sirdataRtdProvider.js b/modules/sirdataRtdProvider.js index 9072d92f849..60df7fc8ffd 100644 --- a/modules/sirdataRtdProvider.js +++ b/modules/sirdataRtdProvider.js @@ -674,7 +674,7 @@ export function addSegmentData(reqBids, data, adUnits, onDone) { window.googletag.cmd.push(() => { window.googletag.pubads().getSlots().forEach(slot => { - if (typeof slot.setTargeting !== 'undefined' && sirdataMergedList.length > 0) { + if (sirdataMergedList.length > 0) { setSlotTargeting(slot, 'sd_rtd', sirdataMergedList); } }); From 50b675652c1537ff09a90d9203db06dd565576bb Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Mon, 1 Jun 2026 12:58:24 -0400 Subject: [PATCH 021/124] UnifiedId Adapter: add typed userId mappings (#14904) * UnifiedId Adapter: add typed userId mappings * UnifiedId Adapter: align tdid typing with runtime shapes * UnifiedId Adapter: require partner or url in types (#14961) --------- Co-authored-by: Demetrio Girardi --- modules/unifiedIdSystem.d.ts | 38 ++++++++++++++++++++++++++++++++++++ modules/unifiedIdSystem.js | 3 ++- src/types/objects.d.ts | 6 ++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 modules/unifiedIdSystem.d.ts diff --git a/modules/unifiedIdSystem.d.ts b/modules/unifiedIdSystem.d.ts new file mode 100644 index 00000000000..ddf88060680 --- /dev/null +++ b/modules/unifiedIdSystem.d.ts @@ -0,0 +1,38 @@ +import type { Ext } from '../src/types/ortb/common'; +import type { RequireAtLeastOne } from '../src/types/objects'; + +export type UnifiedIdSystemModuleName = 'unifiedId'; + +export interface UnifiedIdObject { + id: string; + ext?: Ext; +} + +export type UnifiedId = string | UnifiedIdObject; + +export type UnifiedIdConfig = RequireAtLeastOne<{ + /** + * This is the partner ID value obtained from registering with The Trade Desk or working with a Prebid.js managed services provider. + */ + partner?: string; + /** + * If specified for UnifiedId, overrides the default Trade Desk URL. + */ + url?: string; +}, 'partner' | 'url'>; + +declare module './userId/spec' { + interface UserId { + tdid: UnifiedId; + } + + interface ProvidersToId { + unifiedId: 'tdid'; + } + + interface ProviderParams { + unifiedId: UnifiedIdConfig; + } +} + +export {}; diff --git a/modules/unifiedIdSystem.js b/modules/unifiedIdSystem.js index a6335b33b63..6eb9f857a8d 100644 --- a/modules/unifiedIdSystem.js +++ b/modules/unifiedIdSystem.js @@ -14,6 +14,7 @@ import { UID1_EIDS } from '../libraries/uid1Eids/uid1Eids.js'; * @typedef {import('../modules/userId/index.js').Submodule} Submodule * @typedef {import('../modules/userId/index.js').SubmoduleConfig} SubmoduleConfig * @typedef {import('../modules/userId/index.js').IdResponse} IdResponse + * @typedef {import('./unifiedIdSystem.d.ts').UnifiedId} UnifiedId */ const MODULE_NAME = 'unifiedId'; @@ -33,7 +34,7 @@ export const unifiedIdSubmodule = { * decode the stored id value for passing to bid requests * @function * @param {{TDID:string}} value - * @returns {{tdid:Object}} + * @returns {{tdid: UnifiedId}|undefined} */ decode(value) { return (value && typeof value['TDID'] === 'string') ? { 'tdid': value['TDID'] } : undefined; diff --git a/src/types/objects.d.ts b/src/types/objects.d.ts index 4849c224a51..9024343d60c 100644 --- a/src/types/objects.d.ts +++ b/src/types/objects.d.ts @@ -1,3 +1,9 @@ +export type RequireAtLeastOne = + Omit & { + [K in Keys]-?: Required> & + Partial>> + }[Keys]; + export type DeepPartial = { [K in keyof T]?: T[K] extends object ? DeepPartial : T[K]; }; From 76cd290ff803525d34673e5a2615a42fdabb1ac7 Mon Sep 17 00:00:00 2001 From: Ben Brachmann <49547103+bevenio@users.noreply.github.com> Date: Mon, 1 Jun 2026 19:00:33 +0200 Subject: [PATCH 022/124] Goldbach Bid Adapter: server-driven syncs and identity rework (#14925) * Goldbach Bid Adapter: Endpoint adjustment, server-side cookie sync * Goldbach Bid Adapter: adjusted consent check, player size tuple check --- modules/goldbachBidAdapter.js | 218 ++++---- modules/goldbachBidAdapter.md | 132 ++--- test/spec/modules/goldbachBidAdapter_spec.js | 552 ++++++++++++++++--- 3 files changed, 658 insertions(+), 244 deletions(-) diff --git a/modules/goldbachBidAdapter.js b/modules/goldbachBidAdapter.js index c5da61dae90..f8500277983 100644 --- a/modules/goldbachBidAdapter.js +++ b/modules/goldbachBidAdapter.js @@ -1,31 +1,28 @@ import { ajax } from '../src/ajax.js'; import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; -import { deepAccess, generateUUID } from '../src/utils.js'; +import { deepAccess } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; import { ortbConverter } from '../libraries/ortbConverter/converter.js'; import { Renderer } from '../src/Renderer.js'; import { hasPurpose1Consent } from '../src/utils/gdpr.js'; -import { getStorageManager } from '../src/storageManager.js'; /* General config */ const IS_LOCAL_MODE = false; const BIDDER_CODE = 'goldbach'; -const BIDDER_UID_KEY = 'goldbach_uid'; const GVLID = 580; const URL = 'https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction'; const URL_LOCAL = 'http://localhost:3000/openrtb/2.5/auction'; -const URL_LOGGING = 'https://l.da-services.ch/pb'; -const URL_COOKIESYNC = 'https://goldlayer-api.prod.gbads.net/cookiesync'; +const URL_METRICS = 'https://goldlayer-api.prod.gbads.net/metrics'; +const URL_METRICS_LOCAL = 'http://localhost:3000/metrics'; const METHOD = 'POST'; const DEFAULT_CURRENCY = 'USD'; -const LOGGING_PERCENTAGE_REGULAR = 0.001; -const LOGGING_PERCENTAGE_ERROR = 0.001; -const COOKIE_EXP = 1000 * 60 * 60 * 24 * 365; +const METRICS_SAMPLE_RATE_REGULAR = 0.001; +const METRICS_SAMPLE_RATE_ERROR = 0.001; /* Renderer settings */ const RENDERER_OPTIONS = { OUTSTREAM_GP: { - URL: 'https://goldplayer.prod.gbads.net/scripts/goldplayer.js' + URL: 'https://goldplayer.prod.gbadtech.io/scripts/goldplayer.js' } }; @@ -38,42 +35,10 @@ const EVENTS = { ERROR: 'error' }; -/* Goldbach storage */ -export const storage = getStorageManager({ bidderCode: BIDDER_CODE }); export const dep = { ajax }; -const setUid = (uid) => { - if (storage.localStorageIsEnabled()) { - storage.setDataInLocalStorage(BIDDER_UID_KEY, uid); - } else if (storage.cookiesAreEnabled()) { - const cookieExpiration = new Date(Date.now() + COOKIE_EXP).toISOString(); - storage.setCookie(BIDDER_UID_KEY, uid, cookieExpiration, 'None'); - } -}; - -const getUid = () => { - if (storage.localStorageIsEnabled()) { - return storage.getDataFromLocalStorage(BIDDER_UID_KEY); - } else if (storage.cookiesAreEnabled()) { - return storage.getCookie(BIDDER_UID_KEY); - } - return null; -}; - -const ensureUid = (gdprConsent) => { - // Check if the user has given consent for purpose 1 - if (!gdprConsent || !hasPurpose1Consent(gdprConsent)) return null; - // Check if the UID already exists - const existingUid = getUid(); - if (existingUid) return existingUid; - // Generate a new UID if it doesn't exist - const uid = generateUUID(); - setUid(uid); - return uid; -}; - /* Custom extensions */ const getRendererForBid = (bidRequest, bidResponse) => { if (!bidRequest.renderer) { @@ -88,12 +53,14 @@ const getRendererForBid = (bidRequest, bidResponse) => { renderer.setRender((bid, doc) => { const videoParams = bidRequest?.mediaTypes?.video || {}; const playerSize = videoParams.playerSize; + const playerSizeTuple = Array.isArray(playerSize?.[0]) ? playerSize[0] : playerSize; const playbackmethod = videoParams.playbackmethod; const isMuted = typeof playbackmethod === 'number' ? [2, 6].includes(playbackmethod) : false; const isAutoplay = typeof playbackmethod === 'number' ? [1, 2].includes(playbackmethod) : false; bid.renderer.push(() => { if (doc.defaultView?.GoldPlayer) { + const container = doc.getElementById(bid.adUnitCode); const options = { vastUrl: bid.vastUrl, vastXML: bid.vastXml, @@ -102,8 +69,9 @@ const getRendererForBid = (bidRequest, bidResponse) => { controls: true, resizeMode: 'auto', styling: { progressbarColor: '#000' }, - publisherProvidedWidth: playerSize?.[0], - publisherProvidedHeight: playerSize?.[1], + publisherProvidedWidth: playerSizeTuple?.[0], + publisherProvidedHeight: playerSizeTuple?.[1], + divContainerElement: container, }; const GP = doc.defaultView.GoldPlayer; const player = new GP(options); @@ -135,16 +103,15 @@ const converter = ortbConverter({ const { bidRequests = [] } = context; const firstBidRequest = bidRequests?.[0]; - // Read gdpr consent data - const gdprConsent = bidderRequest?.gdprConsent; - - // Apply custom extensions to the request + // Apply custom extensions to the request. User identity comes from goldlayer-api's + // own first-party cookie on bid requests (withCredentials: true), not from a + // client-minted UID — so no `ext.goldbach.uid` here. if (bidRequests.length > 0) { ortbRequest.ext = ortbRequest.ext || {}; ortbRequest.ext[BIDDER_CODE] = ortbRequest.ext[BIDDER_CODE] || {}; - ortbRequest.ext[BIDDER_CODE].uid = ensureUid(gdprConsent); ortbRequest.ext[BIDDER_CODE].publisherId = firstBidRequest?.params?.publisherId; ortbRequest.ext[BIDDER_CODE].mockResponse = firstBidRequest?.params?.mockResponse || false; + ortbRequest.ext[BIDDER_CODE].auctionStartTime = Date.now(); } // Apply gdpr consent data @@ -176,6 +143,11 @@ const converter = ortbConverter({ bidResponse.meta.primaryCatId = deepAccess(bid, 'ext.prebid.video.primary_category'); bidResponse.meta.secondaryCatIds = deepAccess(bid, 'ext.prebid.video.secondary_categories'); + // Setting extensions: goldbach + bidResponse.ext = bidResponse.ext || {}; + bidResponse.ext[BIDDER_CODE] = bidResponse.ext[BIDDER_CODE] || {}; + bidResponse.ext[BIDDER_CODE].publisherId = deepAccess(bid, 'ext.goldbach.publisherId') || bidRequest?.params?.publisherId; + // Setting extensions: outstream video renderer if (bidResponse.mediaType === VIDEO && bidRequest.mediaTypes.video.context === 'outstream' && (bidResponse.vastUrl || bidResponse.vastXml)) { bidResponse.renderer = getRendererForBid(bidRequest, bidResponse); @@ -184,16 +156,27 @@ const converter = ortbConverter({ } }); -/* Logging */ -const sendLog = (data, percentage = 0.0001) => { - if (Math.random() > percentage) return; - const encodedData = `data=${window.btoa(JSON.stringify({ ...data, source: 'goldbach_pbjs', projectedAmount: (1 / percentage) }))}`; - dep.ajax(URL_LOGGING, null, encodedData, { - withCredentials: false, - method: METHOD, - crossOrigin: true, - contentType: 'application/x-www-form-urlencoded', - }); +/* Metrics */ +const sendMetrics = (data, sampleRate = 0.0001) => { + try { + if (Math.random() > sampleRate) return + const url = IS_LOCAL_MODE ? URL_METRICS_LOCAL : URL_METRICS + const payload = { + ...data, + source: 'goldbach_pbjs', + projected: 1 / sampleRate, + ts: Date.now() + } + dep.ajax(url, null, JSON.stringify(payload), { + withCredentials: false, + method: 'POST', + crossOrigin: true, + contentType: 'text/plain', + keepalive: true, + }) + } catch (error) { + // Silent catch + } } export const spec = { @@ -211,8 +194,8 @@ export const spec = { url: url, data: data, options: { - withCredentials: false, - contentType: 'application/json', + withCredentials: true, + contentType: 'text/plain', } }; }, @@ -220,66 +203,107 @@ export const spec = { const bids = converter.fromORTB({ response: ortbResponse.body, request: request.data }).bids; return bids }, - getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) { - const syncs = [] - const uid = ensureUid(gdprConsent); - if (hasPurpose1Consent(gdprConsent)) { - const type = (syncOptions.pixelEnabled) ? 'image' : null ?? (syncOptions.iframeEnabled) ? 'iframe' : null - if (type) { - syncs.push({ - type: type, - url: `https://ib.adnxs.com/getuid?${URL_COOKIESYNC}?uid=${uid}&xandrId=$UID&gdpr_consent=${gdprConsent.consentString}&gdpr=${gdprConsent.gdprApplies ? 1 : 0}`, - }) - } + getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { + const syncs = []; + if (!hasPurpose1Consent(gdprConsent)) return syncs; + + const serverSyncs = deepAccess(serverResponses, '0.body.ext.goldbach.syncs'); + if (!Array.isArray(serverSyncs)) return syncs; + + const gdprApplies = gdprConsent?.gdprApplies ? 1 : 0; + const gdprConsentEncoded = encodeURIComponent(gdprConsent?.consentString || ''); + const usPrivacy = uspConsent ? encodeURIComponent(uspConsent) : ''; + const gppString = encodeURIComponent(gppConsent?.gppString || ''); + const gppSid = encodeURIComponent((gppConsent?.applicableSections || []).join(',')); + + for (const sync of serverSyncs) { + if (typeof sync?.url !== 'string') continue; + if (sync.type === 'image' && !syncOptions.pixelEnabled) continue; + if (sync.type === 'iframe' && !syncOptions.iframeEnabled) continue; + if (sync.type !== 'image' && sync.type !== 'iframe') continue; + syncs.push({ + type: sync.type, + url: sync.url + .replace(/\{\{GDPR\}\}/g, gdprApplies) + .replace(/\{\{GDPR_CONSENT\}\}/g, gdprConsentEncoded) + .replace(/\{\{USP\}\}/g, usPrivacy) + .replace(/\{\{GPP\}\}/g, gppString) + .replace(/\{\{GPP_SID\}\}/g, gppSid), + }); } - return syncs + return syncs; }, onTimeout: function(timeoutData) { const payload = { event: EVENTS.TIMEOUT, - error: timeoutData, + data: { + publisherId: timeoutData?.[0]?.params?.[0]?.publisherId, + timeoutData: timeoutData, + } }; - sendLog(payload, LOGGING_PERCENTAGE_ERROR); + sendMetrics(payload, METRICS_SAMPLE_RATE_ERROR); }, onBidWon: function(bid) { const payload = { event: EVENTS.BID_WON, - publisherId: bid.params?.[0]?.publisherId, - creativeId: bid.creativeId, - adUnitCode: bid.adUnitCode, - mediaType: bid.mediaType, - size: bid.size, + data: { + publisherId: deepAccess(bid, `ext.${BIDDER_CODE}.publisherId`), + creativeId: bid.creativeId, + adUnitCode: bid.adUnitCode, + mediaType: bid.mediaType, + size: bid.size, + cpm: bid.cpm, + currency: bid.currency, + } }; - sendLog(payload, LOGGING_PERCENTAGE_REGULAR); + sendMetrics(payload, METRICS_SAMPLE_RATE_REGULAR); }, onSetTargeting: function(bid) { const payload = { - event: EVENTS.BID_WON, - publisherId: bid.params?.[0]?.publisherId, - creativeId: bid.creativeId, - adUnitCode: bid.adUnitCode, - mediaType: bid.mediaType, - size: bid.size, + event: EVENTS.TARGETING, + data: { + publisherId: deepAccess(bid, `ext.${BIDDER_CODE}.publisherId`), + creativeId: bid.creativeId, + adUnitCode: bid.adUnitCode, + mediaType: bid.mediaType, + size: bid.size, + cpm: bid.cpm, + currency: bid.currency, + } }; - sendLog(payload, LOGGING_PERCENTAGE_REGULAR); + sendMetrics(payload, METRICS_SAMPLE_RATE_REGULAR); }, - onBidderError: function({ error }) { + onBidderError: function({ error, bidderRequest }) { + const status = error?.status ?? 0; + const type = error?.timedOut ? 'timeout' + : status === 0 ? 'network' + : status >= 500 ? 'server' + : status >= 400 ? 'client' + : 'unknown'; const payload = { event: EVENTS.ERROR, - error: error, + data: { + publisherId: bidderRequest?.bids?.[0]?.params?.publisherId, + type, + status, + } }; - sendLog(payload, LOGGING_PERCENTAGE_ERROR); + sendMetrics(payload, METRICS_SAMPLE_RATE_ERROR); }, onAdRenderSucceeded: function(bid) { const payload = { - event: EVENTS.BID_WON, - publisherId: bid.params?.[0]?.publisherId, - creativeId: bid.creativeId, - adUnitCode: bid.adUnitCode, - mediaType: bid.mediaType, - size: bid.size, + event: EVENTS.RENDER, + data: { + publisherId: deepAccess(bid, `ext.${BIDDER_CODE}.publisherId`), + creativeId: bid.creativeId, + adUnitCode: bid.adUnitCode, + mediaType: bid.mediaType, + size: bid.size, + cpm: bid.cpm, + currency: bid.currency, + } }; - sendLog(payload, LOGGING_PERCENTAGE_REGULAR); + sendMetrics(payload, METRICS_SAMPLE_RATE_REGULAR); }, } diff --git a/modules/goldbachBidAdapter.md b/modules/goldbachBidAdapter.md index 7335c95f77f..347e7b20684 100644 --- a/modules/goldbachBidAdapter.md +++ b/modules/goldbachBidAdapter.md @@ -3,87 +3,75 @@ ## Overview ```text -Module Name: Goldbach Bidder Adapter -Module Type: Bidder Adapter -Maintainer: benjamin.brachmann@goldbach.com +Module Name: Goldbach Bidder Adapter +Module Type: Bidder Adapter +Maintainer: benjamin.brachmann@goldbach.com +GVL ID: 580 ``` ## Description -Module that connects to Goldbach SSP demand sources. +Connects publishers to the Goldbach SSP. Supported media types: **banner**, **video** (instream + outstream), **native**. + +## Bid Parameters + +| Name | Scope | Type | Description | Example | +|-------------------|----------|---------|------------------------------------------------------------------------|-------------------------------| +| `publisherId` | required | string | Non-empty publisher identifier provisioned by Goldbach. | `'de-publisher.ch-ios'` | +| `slotId` | optional | string | Publisher-defined slot identifier. Falls back to `adUnit.code`. | `'/123/example.com/slot/key'` | +| `customTargeting` | optional | object | Free-form key/value targeting forwarded to the Goldbach auction. | `{ language: 'de' }` | + +## Disclosures + +For outstream video creatives, the adapter loads an external rendering script from `https://goldplayer.prod.gbadtech.io/scripts/goldplayer.js`. + +Sampled lifecycle events are sent to a Goldbach metrics endpoint for monitoring. + +## Build ```shell -gulp build --modules=goldbachBidAdapter,userId,pubProvidedIdSystem +gulp build --modules=goldbachBidAdapter,userId,pubProvidedIdSystem,consentManagementTcf ``` ## Test Parameters ```javascript - var adUnits = [ - { - code: 'au-1', - mediaTypes: { - video: { - sizes: [[640, 480]], - maxduration: 30, - } - }, - bids: [ - { - bidder: 'goldbach', - params: { - publisherId: 'goldbach_debug', - slotId: '/1235/example.com/video/video/example' - } - } - ] - }, - { - code: 'au-2', - sizes: [[1, 1]], - mediaTypes: { - native: { - title: { - required: true, - len: 50 - }, - image: { - required: true, - sizes: [300, 157] - }, - icon: { - required: true, - sizes: [30, 30] - } - } - }, - bids: [ - { - bidder: 'goldbach', - params: { - publisherId: 'goldbach_debug', - slotId: '/1235/example.com/inside-full-test-native/example' - } - } - ] - }, - { - code: 'au-3', - sizes: [[300, 250]], - mediaTypes: { - banner: { - sizes: [[300, 250]], - } - }, - bids: [ - { - bidder: 'goldbach', - params: { - publisherId: 'goldbach_debug', - slotId: '/1235/example.com/inside-full-test-banner/example' - } - } - ] - }, - ]; +var adUnits = [ + { + code: 'au-1', + mediaTypes: { banner: { sizes: [[300, 250]] } }, + bids: [{ + bidder: 'goldbach', + params: { publisherId: 'goldbach_debug', slotId: '/123/example.com/banner' } + }] + }, + { + code: 'au-2', + mediaTypes: { + video: { context: 'outstream', playerSize: [[640, 480]], mimes: ['video/mp4'] } + }, + bids: [{ + bidder: 'goldbach', + params: { publisherId: 'goldbach_debug', slotId: '/123/example.com/video' } + }] + }, + { + code: 'au-3', + mediaTypes: { + native: { + title: { required: true, len: 50 }, + image: { required: true, sizes: [300, 157] }, + icon: { required: true, sizes: [30, 30] } + } + }, + bids: [{ + bidder: 'goldbach', + params: { + publisherId: 'goldbach_debug', + slotId: '/123/example.com/native', + customTargeting: { language: 'de' } + } + }] + } +]; ``` diff --git a/test/spec/modules/goldbachBidAdapter_spec.js b/test/spec/modules/goldbachBidAdapter_spec.js index 041fb643aff..fd1d995a740 100644 --- a/test/spec/modules/goldbachBidAdapter_spec.js +++ b/test/spec/modules/goldbachBidAdapter_spec.js @@ -1,6 +1,6 @@ import { expect } from 'chai'; import sinon from 'sinon'; -import { dep, spec, storage } from 'modules/goldbachBidAdapter.js'; +import { dep, spec } from 'modules/goldbachBidAdapter.js'; import { newBidder } from 'src/adapters/bidderFactory.js'; import { deepClone } from 'src/utils.js'; import { BANNER, NATIVE, VIDEO } from 'src/mediaTypes.js'; @@ -9,7 +9,6 @@ import { addFPDToBidderRequest } from '../../helpers/fpd.js'; const BIDDER_NAME = 'goldbach' const ENDPOINT = 'https://goldlayer-api.prod.gbads.net/openrtb/2.5/auction'; -const ENDPOINT_COOKIESYNC = 'https://goldlayer-api.prod.gbads.net/cookiesync'; /* Eids */ const eids = [ @@ -314,6 +313,21 @@ describe('GoldbachBidAdapter', function () { }; expect(spec.isBidRequestValid(invalidBid)).to.equal(false); }); + + it('should return false when publisherId is an empty string', function () { + const invalidBid = Object.assign({}, bid, { params: { publisherId: '' } }); + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + it('should return false when params is missing', function () { + const invalidBid = { bidder: BIDDER_NAME }; + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); + + it('should return false when publisherId is not a string', function () { + const invalidBid = Object.assign({}, bid, { params: { publisherId: 123 } }); + expect(spec.isBidRequestValid(invalidBid)).to.equal(false); + }); }); describe('buildRequests', function () { @@ -363,6 +377,19 @@ describe('GoldbachBidAdapter', function () { expect(payload.ext.goldbach.publisherId).to.equal(bidRequests[0].params.publisherId); }); + it('should set auctionStartTime on request', function () { + const bidRequests = deepClone(validBidRequests); + const bidderRequest = deepClone(validBidderRequest); + const before = Date.now(); + const request = spec.buildRequests(bidRequests, bidderRequest); + const after = Date.now(); + const payload = request.data; + + expect(payload.ext.goldbach.auctionStartTime).to.be.a('number'); + expect(payload.ext.goldbach.auctionStartTime).to.be.at.least(before); + expect(payload.ext.goldbach.auctionStartTime).to.be.at.most(after); + }); + it('should set gdpr on request', function () { const bidRequests = deepClone(validBidRequests); const bidderRequest = deepClone(validBidderRequest); @@ -373,6 +400,17 @@ describe('GoldbachBidAdapter', function () { expect(payload.user.ext.consent).to.equal(bidderRequest.gdprConsent.consentString); }); + it('should handle missing gdprConsent gracefully', function () { + const bidRequests = deepClone(validBidRequests); + const bidderRequest = deepClone(validBidderRequest); + delete bidderRequest.gdprConsent; + const request = spec.buildRequests(bidRequests, bidderRequest); + const payload = request.data; + + expect(payload.ext.goldbach.publisherId).to.exist; + expect(payload.regs?.ext?.gdpr).to.not.exist; + }); + it('should set custom targeting on request', function () { const bidRequests = deepClone(validBidRequests); const bidderRequest = deepClone(validBidderRequest); @@ -416,14 +454,43 @@ describe('GoldbachBidAdapter', function () { validBidRequests[1].mediaTypes.video.playbackmethod = 1; const response = spec.interpretResponse(bidResponse, bidRequest); const renderer = response.find(bid => !!bid.renderer); - renderer?.renderer?.render(); expect(response).to.exist; expect(response.filter(bid => !!bid.renderer).length).to.equal(1); expect(renderer.renderer.config.documentResolver).to.exist; + expect(renderer.renderer.url).to.be.a('string'); }); } + it('should set meta fields from bid response', function () { + const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); + const bidResponse = deepClone({ body: validOrtbBidResponse }); + bidResponse.body.seatbid[0].bid[0].adomain = ['example.com']; + const response = spec.interpretResponse(bidResponse, bidRequest); + const bannerBid = response.find(bid => bid.requestId === validBidRequests[0].bidId); + + expect(bannerBid.meta).to.exist; + expect(bannerBid.meta.advertiserDomains).to.deep.equal(['example.com']); + expect(bannerBid.meta.mediaType).to.equal('banner'); + }); + + it('should use origbidcur as currency fallback', function () { + const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); + const bidResponse = deepClone({ body: validOrtbBidResponse }); + const response = spec.interpretResponse(bidResponse, bidRequest); + const bannerBid = response.find(bid => bid.requestId === validBidRequests[0].bidId); + + expect(bannerBid.currency).to.equal('USD'); + }); + + it('should return empty array for empty seatbid', function () { + const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); + const bidResponse = { body: { id: 'test', seatbid: [] } }; + const response = spec.interpretResponse(bidResponse, bidRequest); + + expect(response).to.be.an('array').that.is.empty; + }); + it('should not attach a custom video renderer when VAST url/xml is missing', function () { const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); const bidResponse = deepClone({ body: validOrtbBidResponse }); @@ -434,129 +501,464 @@ describe('GoldbachBidAdapter', function () { expect(response).to.exist; expect(response.filter(bid => !!bid.renderer).length).to.equal(0); }); + + it('should carry publisherId from the request onto every bid response under ext.goldbach', function () { + const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); + const bidResponse = deepClone({ body: validOrtbBidResponse }); + const response = spec.interpretResponse(bidResponse, bidRequest); + + expect(response).to.have.length.greaterThan(0); + response.forEach(bid => { + expect(bid.ext.goldbach.publisherId).to.equal('de-publisher.ch-ios'); + }); + }); + + it('prefers a server-echoed ext.goldbach.publisherId over the request param', function () { + const bidRequest = spec.buildRequests(validBidRequests, validBidderRequest); + const bidResponse = deepClone({ body: validOrtbBidResponse }); + // Server echoes a different publisherId on the bid (e.g. normalized / parent-resolved) + bidResponse.body.seatbid[0].bid.forEach(b => { + b.ext = b.ext || {}; + b.ext.goldbach = { publisherId: 'server-resolved-pub' }; + }); + const response = spec.interpretResponse(bidResponse, bidRequest); + + expect(response).to.have.length.greaterThan(0); + response.forEach(bid => { + expect(bid.ext.goldbach.publisherId).to.equal('server-resolved-pub'); + }); + }); }); + if (FEATURES.VIDEO) { + describe('outstream renderer', function () { + let goldPlayerSpy; + let goldPlayerOptions; + + function buildFakeDoc(elementsById = {}) { + return { + getElementById: sinon.spy((id) => + Object.prototype.hasOwnProperty.call(elementsById, id) ? elementsById[id] : null + ), + defaultView: { + GoldPlayer: function GoldPlayer(opts) { + goldPlayerOptions = opts; + goldPlayerSpy(opts); + this.play = sinon.stub(); + } + } + }; + } + + function runRenderer({ adUnitCode = 'au-2', playerSize = [[640, 480]], doc }) { + const bidRequests = deepClone(validBidRequests); + bidRequests[1].adUnitCode = adUnitCode; + bidRequests[1].mediaTypes.video.playerSize = playerSize; + const bidderRequest = deepClone(validBidderRequest); + bidderRequest.bids = bidRequests; + + const request = spec.buildRequests(bidRequests, bidderRequest); + const bidResponse = deepClone({ body: validOrtbBidResponse }); + bidResponse.body.seatbid[0].bid[1].adm = + ''; + bidResponse.body.seatbid[0].bid[1].ext = { prebid: { type: 'video', meta: { type: 'video_outstream' } } }; + const response = spec.interpretResponse(bidResponse, request); + const videoBid = response.find(b => !!b.renderer); + videoBid.adUnitCode = adUnitCode; + videoBid.renderer._render(videoBid, doc); + videoBid.renderer.process(); + return videoBid; + } + + beforeEach(function () { + goldPlayerSpy = sinon.spy(); + goldPlayerOptions = null; + }); + + it('passes the slot div as divContainerElement when adUnitCode matches a DOM id', function () { + const slotDiv = { id: 'my-slot', tagName: 'DIV' }; + const doc = buildFakeDoc({ 'my-slot': slotDiv }); + runRenderer({ adUnitCode: 'my-slot', doc }); + + expect(goldPlayerSpy.calledOnce).to.be.true; + expect(goldPlayerOptions.divContainerElement).to.equal(slotDiv); + }); + + it('passes null divContainerElement when no DOM element matches adUnitCode', function () { + const doc = buildFakeDoc({}); + runRenderer({ adUnitCode: 'missing-slot', doc }); + + expect(goldPlayerSpy.calledOnce).to.be.true; + expect(goldPlayerOptions.divContainerElement).to.equal(null); + }); + + it('reads width/height from playerSize[0] tuple', function () { + const doc = buildFakeDoc({}); + runRenderer({ playerSize: [[640, 360]], doc }); + + expect(goldPlayerOptions.publisherProvidedWidth).to.equal(640); + expect(goldPlayerOptions.publisherProvidedHeight).to.equal(360); + }); + + it('reads width/height from a flat playerSize tuple [w, h]', function () { + const doc = buildFakeDoc({}); + runRenderer({ playerSize: [640, 360], doc }); + + expect(goldPlayerOptions.publisherProvidedWidth).to.equal(640); + expect(goldPlayerOptions.publisherProvidedHeight).to.equal(360); + }); + + it('leaves width/height undefined when playerSize is missing/invalid', function () { + const doc = buildFakeDoc({}); + // null bypasses runRenderer's default-arg fallback so the renderer sees a falsy playerSize. + runRenderer({ playerSize: null, doc }); + + expect(goldPlayerOptions.publisherProvidedWidth).to.be.undefined; + expect(goldPlayerOptions.publisherProvidedHeight).to.be.undefined; + }); + + it('resolves a GAM-style adUnitCode (slashes and dots) via getElementById without throwing', function () { + const gamId = '/123/site.com/slot'; + const slotDiv = { id: gamId, tagName: 'DIV' }; + const doc = buildFakeDoc({ [gamId]: slotDiv }); + + expect(() => runRenderer({ adUnitCode: gamId, doc })).to.not.throw(); + expect(goldPlayerOptions.divContainerElement).to.equal(slotDiv); + expect(doc.getElementById.calledWith(gamId)).to.be.true; + }); + }); + } + describe('getUserSyncs', function () { - it('user-syncs with enabled pixel option', function () { - const gdprConsent = { - vendorData: { - purpose: { - consents: 1 + it('should return empty array when there is no auction response', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs(syncOptions, {}, undefined, {}); + expect(userSyncs).to.be.an('array').that.is.empty; + }); + + it('should proceed when gdprConsent is undefined (no CMP / GDPR not in scope) and substitute GDPR macros with safe defaults', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const serverResponses = [{ + body: { + ext: { + goldbach: { + syncs: [ + { type: 'image', url: 'https://partner.example/sync?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}' }, + ] + } } } - }; - const syncOptions = { pixelEnabled: true, iframeEnabled: true }; - const userSyncs = spec.getUserSyncs(syncOptions, {}, gdprConsent, {}); + }]; + const userSyncs = spec.getUserSyncs(syncOptions, serverResponses, undefined, undefined); - expect(userSyncs[0].type).to.equal('image'); - expect(userSyncs[0].url).to.contain(`https://ib.adnxs.com/getuid?${ENDPOINT_COOKIESYNC}`); - expect(userSyncs[0].url).to.contain('xandrId=$UID'); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0]).to.deep.equal({ + type: 'image', + url: 'https://partner.example/sync?gdpr=0&gdpr_consent=', + }); }); - it('user-syncs with enabled iframe option', function () { + it('should return empty array when ext.goldbach.syncs is absent from the auction response', function () { const gdprConsent = { - vendorData: { - purpose: { - consents: 1 - } - } + gdprApplies: true, + consentString: 'CONSENT', + vendorData: { purpose: { consents: { '1': true } } } }; - const syncOptions = { iframeEnabled: true }; - const userSyncs = spec.getUserSyncs(syncOptions, {}, gdprConsent, {}); + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs(syncOptions, [{ body: { /* no ext */ } }], gdprConsent, undefined); - expect(userSyncs[0].type).to.equal('iframe'); - expect(userSyncs[0].url).to.contain(`https://ib.adnxs.com/getuid?${ENDPOINT_COOKIESYNC}`); - expect(userSyncs[0].url).to.contain('xandrId=$UID'); + expect(userSyncs).to.be.an('array').that.is.empty; }); - it('user-syncs use gdpr signal', function () { + describe('server-driven syncs (ext.goldbach.syncs)', function () { const gdprConsent = { gdprApplies: true, - consentString: 'CPwk-qEPwk-qEH6AAAENCZCMAP_AAH_AAAAAI7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8Edmu_r__tr-z_f9_9P26PMav-_1793IZhwvm2feC7l_rfl4L77Cdmi79W1cFTI8SXatgkIG2jmTqBqTYtUSq15j2NSbOU5GlE_kyST2MvbOsDC-nz-yh_MFM9_8_-_v87J_-_-__b-57_-v___u3__f__Xxv_8--z_3-vq_9-flP-_______f___________-AA.II7Nd_X__bX9n-_7_6ft0eY1f9_r37uQzDhfNs-8F3L_W_LwX32E7NF36tq4KmR4ku1bBIQNtHMnUDUmxaolVrzHsak2cpyNKJ_JkknsZe2dYGF9Pn9lD-YKZ7_5_9_f52T_9_9_-39z3_9f___dv_-__-vjf_599n_v9fV_78_Kf9______-____________8A', - vendorData: { - purpose: { - consents: { '1': true } - } - } + consentString: 'CONSENT+/STR=', + vendorData: { purpose: { consents: { '1': true } } } }; - const synOptions = { pixelEnabled: true, iframeEnabled: true }; - const userSyncs = spec.getUserSyncs(synOptions, {}, gdprConsent, {}); - expect(userSyncs[0].url).to.contain(`https://ib.adnxs.com/getuid?${ENDPOINT_COOKIESYNC}`); - expect(userSyncs[0].url).to.contain('xandrId=$UID'); - expect(userSyncs[0].url).to.contain(`gdpr_consent=${gdprConsent.consentString}`); - expect(userSyncs[0].url).to.contain(`gdpr=1`); - }) - }); - describe('getUserSyncs storage', function () { - beforeEach(function () { - sandbox.stub(storage, 'setDataInLocalStorage'); - sandbox.stub(storage, 'setCookie'); - }); + function makeServerResponse(syncs) { + return [{ body: { ext: { goldbach: { syncs } } } }]; + } - afterEach(function () { - sandbox.restore(); - }); + it('uses server-driven sync URLs from the auction response when present', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image', url: 'https://partner-a.example/sync?p=1' }, + { type: 'iframe', url: 'https://partner-b.example/sync?p=2' }, + ]), + gdprConsent, + '1YYY' + ); + expect(userSyncs).to.have.length(2); + expect(userSyncs[0]).to.deep.equal({ type: 'image', url: 'https://partner-a.example/sync?p=1' }); + expect(userSyncs[1]).to.deep.equal({ type: 'iframe', url: 'https://partner-b.example/sync?p=2' }); + }); - it('should retrieve a uid in userSync call from localStorage', function () { - sandbox.stub(storage, 'localStorageIsEnabled').callsFake(() => true); - sandbox.stub(storage, 'getDataFromLocalStorage').callsFake((key) => 'goldbach_uid'); - const gdprConsent = { vendorData: { purpose: { consents: 1 } } }; - const syncOptions = { iframeEnabled: true }; - const userSyncs = spec.getUserSyncs(syncOptions, {}, gdprConsent, {}); - expect(userSyncs[0].url).to.contain('goldbach_uid'); - }); + it('substitutes {{GDPR}}, {{GDPR_CONSENT}} and {{USP}} placeholders', function () { + const syncOptions = { pixelEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { + type: 'image', + url: 'https://partner.example/sync?gdpr={{GDPR}}&gdpr_consent={{GDPR_CONSENT}}&us_privacy={{USP}}' + }, + ]), + gdprConsent, + '1YYY' + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].url).to.equal( + `https://partner.example/sync?gdpr=1&gdpr_consent=${encodeURIComponent(gdprConsent.consentString)}&us_privacy=${encodeURIComponent('1YYY')}` + ); + }); + + it('substitutes {{GPP}} and {{GPP_SID}} placeholders', function () { + const syncOptions = { pixelEnabled: true }; + const gppConsent = { gppString: 'GPP+/STR=', applicableSections: [7, 8] }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image', url: 'https://partner.example/sync?gpp={{GPP}}&gpp_sid={{GPP_SID}}' }, + ]), + gdprConsent, + undefined, + gppConsent + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].url).to.equal( + `https://partner.example/sync?gpp=${encodeURIComponent('GPP+/STR=')}&gpp_sid=${encodeURIComponent('7,8')}` + ); + }); + + it('substitutes GPP placeholders with empty values when gppConsent is missing', function () { + const syncOptions = { pixelEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image', url: 'https://partner.example/sync?gpp={{GPP}}&gpp_sid={{GPP_SID}}' }, + ]), + gdprConsent, + undefined, + undefined + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].url).to.equal('https://partner.example/sync?gpp=&gpp_sid='); + }); + + it('leaves URLs without GPP placeholders unchanged when gppConsent is provided', function () { + const syncOptions = { pixelEnabled: true }; + const gppConsent = { gppString: 'GPPSTR', applicableSections: [7] }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image', url: 'https://partner.example/sync?gdpr={{GDPR}}' }, + ]), + gdprConsent, + undefined, + gppConsent + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].url).to.equal('https://partner.example/sync?gdpr=1'); + }); + + it('filters out iframe entries when only pixel is enabled (and vice versa)', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: false }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image', url: 'https://partner.example/pixel' }, + { type: 'iframe', url: 'https://partner.example/iframe' }, + ]), + gdprConsent, + undefined + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].type).to.equal('image'); + }); - it('should retrieve a uid in userSync call from cookie', function () { - sandbox.stub(storage, 'cookiesAreEnabled').callsFake(() => true); - sandbox.stub(storage, 'getCookie').callsFake((key) => 'goldbach_uid'); - const gdprConsent = { vendorData: { purpose: { consents: 1 } } }; - const syncOptions = { iframeEnabled: true }; - const userSyncs = spec.getUserSyncs(syncOptions, {}, gdprConsent, {}); - expect(userSyncs[0].url).to.contain('goldbach_uid'); + it('treats an empty server-driven array as an authoritative no-syncs signal (no fallback)', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([]), + gdprConsent, + undefined + ); + expect(userSyncs).to.be.an('array').that.is.empty; + }); + + it('drops malformed entries (missing url or unknown type)', function () { + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([ + { type: 'image' }, + { type: 'audio', url: 'https://partner.example/audio' }, + { url: 'https://partner.example/no-type' }, + { type: 'image', url: 'https://partner.example/ok' }, + ]), + gdprConsent, + undefined + ); + expect(userSyncs).to.have.length(1); + expect(userSyncs[0].url).to.equal('https://partner.example/ok'); + }); + + it('still gates server-driven syncs on GDPR purpose 1 consent', function () { + const noConsent = { gdprApplies: true, consentString: 'CONSENT' /* no vendorData */ }; + const syncOptions = { pixelEnabled: true, iframeEnabled: true }; + const userSyncs = spec.getUserSyncs( + syncOptions, + makeServerResponse([{ type: 'image', url: 'https://partner.example/pixel' }]), + noConsent, + undefined + ); + expect(userSyncs).to.be.an('array').that.is.empty; + }); }); }); - describe('sendLogs', function () { - it('should not send logs when percentage is not met', function () { + describe('sendMetrics', function () { + it('should not send metrics when sample rate is not met', function () { Math.random.returns(1); spec.onTimeout([]); expect(ajaxStub.calledOnce).to.be.false; }); + + it('should set fetch keepalive on the metrics request so it survives navigation', function () { + spec.onTimeout([]); + expect(ajaxStub.calledOnce).to.be.true; + const options = ajaxStub.firstCall.args[3]; + expect(options.keepalive).to.equal(true); + }); }); describe('onTimeout', function () { - it('should send logs on timeout', function () { + it('should send timeout event', function () { spec.onTimeout([]); expect(ajaxStub.calledOnce).to.be.true; + const payload = JSON.parse(ajaxStub.firstCall.args[2]); + expect(payload.event).to.equal('timeout'); + expect(payload.source).to.be.a('string'); + expect(payload.projected).to.be.a('number'); + expect(payload.ts).to.be.a('number'); + expect(payload.data).to.be.an('object'); + }); + + it('should read publisherId from the rewritten params array on the timed-out bidder', function () { + // adapterManager rewrites timedOutBidder.params via getUserConfiguredParams which returns an array. + spec.onTimeout([{ params: [{ publisherId: 'pub-from-timeout' }] }]); + const payload = JSON.parse(ajaxStub.firstCall.args[2]); + expect(payload.data.publisherId).to.equal('pub-from-timeout'); }); }); describe('onBidWon', function () { - it('should send logs on won', function () { - spec.onBidWon([]); + it('should send bid_won event', function () { + spec.onBidWon({ + ext: { goldbach: { publisherId: 'pub-1' } }, + creativeId: 'crid-1', + adUnitCode: 'au-1', + mediaType: 'banner', + size: '300x250', + cpm: 1.5, + currency: 'USD' + }); expect(ajaxStub.calledOnce).to.be.true; + const payload = JSON.parse(ajaxStub.firstCall.args[2]); + expect(payload.event).to.equal('bid_won'); + expect(payload.source).to.be.a('string'); + expect(payload.projected).to.be.a('number'); + expect(payload.ts).to.be.a('number'); + expect(payload.data).to.be.an('object'); + expect(payload.data).to.include.keys('publisherId', 'creativeId', 'adUnitCode', 'mediaType', 'size', 'cpm', 'currency'); + expect(payload.data.publisherId).to.equal('pub-1'); }); }); describe('onSetTargeting', function () { - it('should send logs on targeting', function () { - spec.onSetTargeting([]); + it('should send targeting_set event', function () { + spec.onSetTargeting({ + ext: { goldbach: { publisherId: 'pub-1' } }, + creativeId: 'crid-1', + adUnitCode: 'au-1', + mediaType: 'banner', + size: '300x250', + cpm: 1.0, + currency: 'CHF' + }); expect(ajaxStub.calledOnce).to.be.true; + const payload = JSON.parse(ajaxStub.firstCall.args[2]); + expect(payload.event).to.equal('targeting_set'); + expect(payload.source).to.be.a('string'); + expect(payload.projected).to.be.a('number'); + expect(payload.ts).to.be.a('number'); + expect(payload.data).to.be.an('object'); + expect(payload.data).to.include.keys('publisherId', 'creativeId', 'adUnitCode', 'mediaType', 'size', 'cpm', 'currency'); + expect(payload.data.publisherId).to.equal('pub-1'); }); }); describe('onBidderError', function () { - it('should send logs on bidder error', function () { - spec.onBidderError([]); - expect(ajaxStub.calledOnce).to.be.true; + function payloadFor(error) { + ajaxStub.resetHistory(); + spec.onBidderError({ error }); + return JSON.parse(ajaxStub.firstCall.args[2]).data; + } + + it('should send error event with type + status, never the raw XHR object', function () { + const data = payloadFor({ status: 500, statusText: 'Internal Server Error', responseText: '' }); + expect(data).to.include.keys('type', 'status'); + expect(data).to.not.have.any.keys('errorData', 'responseText', 'responseXML', 'statusText'); + }); + + it('classifies 5xx as "server"', function () { + expect(payloadFor({ status: 503 }).type).to.equal('server'); + }); + + it('classifies 4xx as "client"', function () { + expect(payloadFor({ status: 404 }).type).to.equal('client'); + }); + + it('classifies status 0 (or missing) as "network"', function () { + expect(payloadFor({ status: 0 }).type).to.equal('network'); + expect(payloadFor({}).type).to.equal('network'); + }); + + it('classifies a timeout flag as "timeout" regardless of status', function () { + expect(payloadFor({ timedOut: true, status: 0 }).type).to.equal('timeout'); + expect(payloadFor({ timedOut: true, status: 504 }).type).to.equal('timeout'); + }); + + it('classifies a 2xx (unexpected error path) as "unknown"', function () { + expect(payloadFor({ status: 200 }).type).to.equal('unknown'); }); }); describe('onAdRenderSucceeded', function () { - it('should send logs on render succeeded', function () { - spec.onAdRenderSucceeded([]); + it('should send creative_render event', function () { + spec.onAdRenderSucceeded({ + ext: { goldbach: { publisherId: 'pub-1' } }, + creativeId: 'crid-1', + adUnitCode: 'au-1', + mediaType: 'video', + size: '640x480', + cpm: 2.0, + currency: 'EUR' + }); expect(ajaxStub.calledOnce).to.be.true; + const payload = JSON.parse(ajaxStub.firstCall.args[2]); + expect(payload.event).to.equal('creative_render'); + expect(payload.source).to.be.a('string'); + expect(payload.projected).to.be.a('number'); + expect(payload.ts).to.be.a('number'); + expect(payload.data).to.be.an('object'); + expect(payload.data).to.include.keys('publisherId', 'creativeId', 'adUnitCode', 'mediaType', 'size', 'cpm', 'currency'); + expect(payload.data.publisherId).to.equal('pub-1'); }); }); }); From 5ad41439deeead5df2063cb8e611d82673f52873 Mon Sep 17 00:00:00 2001 From: deferoper Date: Mon, 1 Jun 2026 22:14:38 +0300 Subject: [PATCH 023/124] New Adapter: ferio (#14896) * Add ferio bid adapter * fix: isolate fallback response media type, include types * refactor: convert adapter and utilities to ts * refactor: rely on ORTB converter for request signals --------- Co-authored-by: Patrick McCann --- libraries/ferioUtils/bidderUtils.ts | 498 ++++++++++ modules/ferioBidAdapter.md | 104 ++ modules/ferioBidAdapter.ts | 28 + test/spec/modules/ferioBidAdapter_spec.js | 1096 +++++++++++++++++++++ 4 files changed, 1726 insertions(+) create mode 100644 libraries/ferioUtils/bidderUtils.ts create mode 100644 modules/ferioBidAdapter.md create mode 100644 modules/ferioBidAdapter.ts create mode 100644 test/spec/modules/ferioBidAdapter_spec.js diff --git a/libraries/ferioUtils/bidderUtils.ts b/libraries/ferioUtils/bidderUtils.ts new file mode 100644 index 00000000000..3a8a0280fd2 --- /dev/null +++ b/libraries/ferioUtils/bidderUtils.ts @@ -0,0 +1,498 @@ +import { ortbConverter } from "../ortbConverter/converter.js"; +import { pbsExtensions } from "../pbsExtensions/pbsExtensions.js"; +import { BANNER, NATIVE, VIDEO, type MediaType } from "../../src/mediaTypes.js"; +import { BID_RESPONSE } from "../../src/pbjsORTB.js"; +import { + CONSENT_GDPR, + CONSENT_GPP, + CONSENT_USP, + type ConsentDataForKey, +} from "../../src/consentHandler.js"; +import { + isPlainObject, + logError, + sizesToSizeTuples, +} from "../../src/utils.js"; +import type { + AdapterRequest, + AdapterResponse, + BidderSpec, + ServerResponse, +} from "../../src/adapters/bidderFactory.js"; +import type { + BidRequest, + ClientBidderRequest, +} from "../../src/adapterManager.js"; +import type { BidResponse } from "../../src/bidfactory.js"; +import type { SyncType } from "../../src/userSync.js"; +import type { BidderCode, Currency, Size } from "../../src/types/common.d.ts"; +import type { ORTBRequest } from "../../src/types/ortb/request.d.ts"; +import type { ORTBBid, ORTBResponse } from "../../src/types/ortb/response.d.ts"; +import type { NativeResponse } from "../../src/types/ortb/native.d.ts"; + +const DEFAULT_CURRENCY: Currency = "USD"; +const DEFAULT_TTL = 300; +const DEFAULT_PARAM_BIDDER_CODE = "ferio"; +const ORTB_RESPONSE_MEDIA_TYPES = [1, 2, 4] as const; + +const supportedMediaTypes = [BANNER, VIDEO, NATIVE] as const; + +type SupportedFerioMediaType = typeof supportedMediaTypes[number]; +type FerioResponseMType = typeof ORTB_RESPONSE_MEDIA_TYPES[number]; +type RequiredParam = string; + +type FerioParamsRecord = { + publisherId?: unknown; + adUnitId?: unknown; + [key: string]: unknown; +}; + +type FerioAdapterRequest = AdapterRequest & { + method: "POST"; + url: string; + data: ORTBRequest; + options: { + contentType: "text/plain"; + withCredentials: true; + }; +}; + +export type FerioBidderSpecOptions< + Code extends BidderCode = typeof DEFAULT_PARAM_BIDDER_CODE +> = { + code?: Code; + endpoint: string; + paramBidderCode?: BidderCode; + requiredParams?: readonly RequiredParam[]; +}; + +type GdprConsent = null | undefined | ConsentDataForKey; +type UspConsent = null | undefined | ConsentDataForKey; +type GppConsent = null | undefined | ConsentDataForKey; + +type ConsentParamValue = string | number; +type ConsentParam = readonly [string, ConsentParamValue]; +type UserSyncOptions = { + iframeEnabled?: boolean; + pixelEnabled?: boolean; +}; +type FerioUserSync = { + type: SyncType; + url: string; +}; + +type NativeAdm = Partial & { + assets: NonNullable; +}; +type NativeAdmWrapper = { + native: NativeAdm; +}; +type BidWithRawAdm = Omit & { + adm?: unknown; +}; +type FerioBidResponseWithAdapterCode = Partial & { + adapterCode?: BidderCode; + bidderCode?: BidderCode; +}; + +function isRecord(value: unknown): value is Record { + return isPlainObject(value); +} + +function isNonEmptyString(value: unknown): value is string { + return typeof value === "string" && value.trim().length > 0; +} + +function getNonEmptyString(value: unknown, fallback: string): string { + return isNonEmptyString(value) ? value.trim() : fallback; +} + +function hasValidSize(sizes: unknown): boolean { + return (sizesToSizeTuples(sizes) as Size[]).some((size) => + size.every((value) => Number.isFinite(Number(value)) && Number(value) > 0) + ); +} + +function getFerioParams(params: unknown): FerioParamsRecord { + return isRecord(params) ? params : {}; +} + +function isBidRequestValid( + bid: BidRequest, + requiredParams: readonly RequiredParam[] = [] +): boolean { + const params = getFerioParams(bid.params); + if ( + !isNonEmptyString(params.publisherId) || + !isNonEmptyString(params.adUnitId) + ) { + return false; + } + + if ( + requiredParams.some((paramName) => !isNonEmptyString(params[paramName])) + ) { + return false; + } + + const mediaTypes = bid.mediaTypes || {}; + const hasBanner = !!mediaTypes[BANNER]; + const hasVideo = !!mediaTypes[VIDEO]; + const hasNative = !!mediaTypes[NATIVE]; + + if (!hasBanner && !hasVideo && !hasNative) { + return false; + } + + if (hasBanner && !hasValidSize(mediaTypes[BANNER].sizes)) { + return false; + } + + if (hasVideo && !hasValidSize(mediaTypes[VIDEO].playerSize)) { + return false; + } + + if (hasNative && !bid.nativeOrtbRequest) { + return false; + } + + return true; +} + +function isSupportedMediaType(value: unknown): value is SupportedFerioMediaType { + return supportedMediaTypes.includes(value as SupportedFerioMediaType); +} + +function isFerioResponseMType(value: unknown): value is FerioResponseMType { + return ORTB_RESPONSE_MEDIA_TYPES.includes(value as FerioResponseMType); +} + +function getBidPrebidMediaType(bid: ORTBBid): SupportedFerioMediaType | undefined { + const prebidExt = bid.ext?.prebid; + if (!isRecord(prebidExt)) { + return; + } + + return isSupportedMediaType(prebidExt.type) ? prebidExt.type : undefined; +} + +function getSingleMediaType( + bidRequest: BidRequest +): SupportedFerioMediaType | undefined { + const mediaTypes = supportedMediaTypes.filter( + (mediaType) => bidRequest.mediaTypes?.[mediaType] + ); + return mediaTypes.length === 1 ? mediaTypes[0] : undefined; +} + +function hasResponseMediaType(bid: ORTBBid): boolean { + return isFerioResponseMType(bid.mtype) || !!getBidPrebidMediaType(bid); +} + +function isNativeResponse( + bid: ORTBBid, + context: { mediaType?: MediaType } +): boolean { + return ( + bid.mtype === 4 || + getBidPrebidMediaType(bid) === NATIVE || + context.mediaType === NATIVE + ); +} + +function parseAdm(adm: unknown): unknown { + if (typeof adm !== "string") { + return adm; + } + + try { + return JSON.parse(adm); + } catch (e) { + return adm; + } +} + +function isNativeAdmWrapper(value: unknown): value is NativeAdmWrapper { + if (!isRecord(value) || Array.isArray(value.assets) || !isRecord(value.native)) { + return false; + } + + return Array.isArray(value.native.assets); +} + +function normalizeNativeAdm( + bid: ORTBBid, + context: { mediaType?: MediaType } +): ORTBBid { + if (!isNativeResponse(bid, context)) { + return bid; + } + + const adm = parseAdm((bid as BidWithRawAdm).adm); + if (isNativeAdmWrapper(adm)) { + return { ...bid, adm: JSON.stringify(adm.native) }; + } + + return bid; +} + +function getAdapterResponseBids(response: AdapterResponse): BidResponse[] { + if (isRecord(response) && Array.isArray(response.bids)) { + return response.bids as BidResponse[]; + } + + return []; +} + +function getContextAdapterCode(context: { + bidRequest?: unknown; + bidderRequest?: unknown; +}): BidderCode | undefined { + if ( + isRecord(context.bidRequest) && + typeof context.bidRequest.bidder === "string" + ) { + return context.bidRequest.bidder; + } + + const bidderRequest = context.bidderRequest; + if (isRecord(bidderRequest) && typeof bidderRequest.bidderCode === "string") { + return bidderRequest.bidderCode; + } +} + +function createFerioConverter( + paramBidderCode: BidderCode +) { + return ortbConverter({ + context: { + currency: DEFAULT_CURRENCY, + netRevenue: true, + ttl: DEFAULT_TTL, + }, + processors: pbsExtensions, + imp(buildImp, bidRequest, context) { + return buildImp( + { ...bidRequest, bidder: paramBidderCode } as BidRequest, + context + ); + }, + bidResponse(buildBidResponse, bid, context) { + let responseContext = context; + if (!hasResponseMediaType(bid)) { + const fallbackMediaType = getSingleMediaType(context.bidRequest); + if (!fallbackMediaType) { + return; + } + responseContext = { ...context, mediaType: fallbackMediaType }; + } + return buildBidResponse( + normalizeNativeAdm(bid, responseContext), + responseContext + ); + }, + overrides: { + [BID_RESPONSE]: { + bidderCode(orig, bidResponse, bid, context) { + orig(bidResponse, bid, context); + const adapterCode = getContextAdapterCode(context); + if (adapterCode) { + const response = bidResponse as FerioBidResponseWithAdapterCode; + response.bidderCode = adapterCode; + response.adapterCode = adapterCode; + } + }, + }, + }, + }); +} + +function normalizeEndpoint(endpoint?: string): string | undefined { + if (!isNonEmptyString(endpoint)) { + return; + } + + const normalizedEndpoint = endpoint.trim().replace(/\/+$/, ""); + return /\/bid$/.test(normalizedEndpoint) + ? normalizedEndpoint + : `${normalizedEndpoint}/bid`; +} + +function getEndpointBase(endpoint?: string): string | undefined { + return endpoint?.replace(/\/bid$/, ""); +} + +function appendQueryParams(url: string, params: ConsentParam[]): string { + const query = params + .map(([key, value]) => `${key}=${encodeURIComponent(value)}`) + .join("&"); + const separator = url.includes("?") + ? url.endsWith("?") || url.endsWith("&") + ? "" + : "&" + : "?"; + return `${url}${separator}${query}`; +} + +function isHttpsUrl(value: unknown): value is string { + if (!isNonEmptyString(value)) { + return false; + } + + const url = value.trim(); + if (!/^https:\/\//i.test(url)) { + return false; + } + + try { + return new URL(url).protocol === "https:"; + } catch (e) { + return false; + } +} + +function getConsentParams( + gdprConsent: GdprConsent = null, + uspConsent: UspConsent = null, + gppConsent: GppConsent = null +): ConsentParam[] { + const gdpr = isRecord(gdprConsent) && gdprConsent.gdprApplies ? 1 : 0; + const gdprConsentString = + isRecord(gdprConsent) && typeof gdprConsent.consentString === "string" + ? gdprConsent.consentString + : ""; + + const params: ConsentParam[] = [ + ["us_privacy", typeof uspConsent === "string" ? uspConsent : ""], + ["gdpr", gdpr], + ["gdpr_consent", gdprConsentString], + ]; + + if (isRecord(gppConsent)) { + if (typeof gppConsent.gppString === "string" && gppConsent.gppString) { + params.push(["gpp", gppConsent.gppString]); + } + if (Array.isArray(gppConsent.applicableSections)) { + params.push(["gpp_sid", gppConsent.applicableSections.join(",")]); + } + } + + return params; +} + +function getUserSyncs( + syncBase: string | undefined, + syncOptions: UserSyncOptions = {}, + gdprConsent: GdprConsent = null, + uspConsent: UspConsent = null, + gppConsent: GppConsent = null +): FerioUserSync[] { + if (!(syncOptions.iframeEnabled || syncOptions.pixelEnabled) || !syncBase) { + return []; + } + + const consentParams = getConsentParams(gdprConsent, uspConsent, gppConsent); + const syncCandidates: FerioUserSync[] = []; + + if (syncOptions.pixelEnabled) { + syncCandidates.push({ type: "image", url: `${syncBase}/sync` }); + } + if (syncOptions.iframeEnabled) { + syncCandidates.push({ + type: "iframe", + url: `${syncBase}/cli/iframe.html`, + }); + } + + return syncCandidates.reduce((syncs, sync) => { + if (isHttpsUrl(sync.url)) { + syncs.push({ + type: sync.type, + url: appendQueryParams(sync.url, consentParams), + }); + } + return syncs; + }, []); +} + +export function createFerioBidderSpec< + Code extends BidderCode = typeof DEFAULT_PARAM_BIDDER_CODE +>( + options: FerioBidderSpecOptions +): BidderSpec { + const code = getNonEmptyString( + options.code, + DEFAULT_PARAM_BIDDER_CODE + ) as Code; + const requiredParams = Array.isArray(options.requiredParams) + ? options.requiredParams + : []; + const endpoint = normalizeEndpoint(options.endpoint); + const syncBase = getEndpointBase(endpoint); + const converter = createFerioConverter( + getNonEmptyString(options.paramBidderCode, code) + ); + + return { + code, + supportedMediaTypes, + isBidRequestValid(bid) { + return isBidRequestValid(bid, requiredParams); + }, + buildRequests( + validBidRequests: BidRequest[] = [], + bidderRequest: ClientBidderRequest = { + bids: validBidRequests, + } as ClientBidderRequest + ): FerioAdapterRequest[] { + if (!validBidRequests.length) { + return []; + } + if (!endpoint) { + logError("ferioUtils: missing endpoint option"); + return []; + } + + return [ + { + method: "POST", + url: endpoint, + data: converter.toORTB({ bidRequests: validBidRequests, bidderRequest }), + options: { + contentType: "text/plain", + withCredentials: true, + }, + }, + ]; + }, + interpretResponse( + serverResponse: Partial, + request: Partial = {} + ): BidResponse[] { + if (!serverResponse?.body || !request?.data) { + return []; + } + + try { + return getAdapterResponseBids( + converter.fromORTB({ + response: serverResponse.body as ORTBResponse, + request: request.data as ORTBRequest, + }) + ); + } catch (e) { + logError("ferioUtils: error while interpreting OpenRTB response", e); + return []; + } + }, + getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { + return getUserSyncs( + syncBase, + syncOptions, + gdprConsent, + uspConsent, + gppConsent + ); + }, + }; +} diff --git a/modules/ferioBidAdapter.md b/modules/ferioBidAdapter.md new file mode 100644 index 00000000000..9d051d0db0a --- /dev/null +++ b/modules/ferioBidAdapter.md @@ -0,0 +1,104 @@ +# Overview + +``` +Module Name: Ferio Bid Adapter +Module Type: Bidder Adapter +Maintainer: prebid@ferio.cloud +``` + +# Description + +Connects to Ferio demand sources for bids. +Ferio bid adapter supports banner, video, and native ads. + +# Bid Params + +| Name | Scope | Type | Description | +| ------------- | -------- | ------ | ----------------------------------- | +| `publisherId` | required | String | Publisher ID on the Ferio platform. | +| `adUnitId` | required | String | Ad unit ID on the Ferio platform. | +| `tenantId` | required | String | Tenant ID on the Ferio platform. | + +# Test Parameters + +```javascript +var adUnits = [ + { + code: "banner-div", + mediaTypes: { + banner: { + sizes: [[300, 250]], + }, + }, + bids: [ + { + bidder: "ferio", + params: { + tenantId: "anyclip-pbjs", + publisherId: "pub22yCUTGq6An3d", + adUnitId: "59a8d685-ed01-4b10-9f50-fe9ad0c9c0c1", + }, + }, + ], + }, + { + code: "video-div", + mediaTypes: { + video: { + context: "instream", + playerSize: [640, 480], + mimes: ["video/mp4"], + protocols: [2, 3, 5, 6], + }, + }, + bids: [ + { + bidder: "ferio", + params: { + tenantId: "anyclip-pbjs", + publisherId: "pub22yCUTGq6An3d", + adUnitId: "59a8d685-ed01-4b10-9f50-fe9ad0c9c0c1", + }, + }, + ], + }, + { + code: "native-div", + mediaTypes: { + native: { + ortb: { + ver: "1.2", + assets: [ + { + id: 1, + required: 1, + title: { + len: 90, + }, + }, + { + id: 2, + required: 1, + img: { + type: 3, + w: 300, + h: 250, + }, + }, + ], + }, + }, + }, + bids: [ + { + bidder: "ferio", + params: { + tenantId: "anyclip-pbjs", + publisherId: "pub22yCUTGq6An3d", + adUnitId: "59a8d685-ed01-4b10-9f50-fe9ad0c9c0c1", + }, + }, + ], + }, +]; +``` diff --git a/modules/ferioBidAdapter.ts b/modules/ferioBidAdapter.ts new file mode 100644 index 00000000000..99383f034f4 --- /dev/null +++ b/modules/ferioBidAdapter.ts @@ -0,0 +1,28 @@ +import { + type BidderSpec, + registerBidder, +} from "../src/adapters/bidderFactory.js"; +import { createFerioBidderSpec } from "../libraries/ferioUtils/bidderUtils.js"; + +const BIDDER_CODE = "ferio"; +const FERIO_ENDPOINT = "https://ferio.bid/pbjs/bid"; + +export interface FerioBidParams { + publisherId: string; + adUnitId: string; + tenantId: string; +} + +declare module "../src/adUnits" { + interface BidderParams { + [BIDDER_CODE]: FerioBidParams; + } +} + +export const spec: BidderSpec = createFerioBidderSpec({ + code: BIDDER_CODE, + endpoint: FERIO_ENDPOINT, + requiredParams: ["tenantId"], +}); + +registerBidder(spec); diff --git a/test/spec/modules/ferioBidAdapter_spec.js b/test/spec/modules/ferioBidAdapter_spec.js new file mode 100644 index 00000000000..a5943d98227 --- /dev/null +++ b/test/spec/modules/ferioBidAdapter_spec.js @@ -0,0 +1,1096 @@ +import { expect } from "chai"; +import { spec } from "../../../modules/ferioBidAdapter.js"; +import { createFerioBidderSpec } from "../../../libraries/ferioUtils/bidderUtils.js"; +import { config } from "../../../src/config.js"; +import { BANNER, NATIVE, VIDEO } from "../../../src/mediaTypes.js"; +import { isValid } from "../../../src/adapters/bidderFactory.js"; +import { stubAuctionIndex } from "../../helpers/indexStub.js"; + +const BIDDER_CODE = "ferio"; +const ALIAS_CODE = "clientABidder"; +const ALIAS_PARAM_BIDDER_CODE = "ferioflow"; +const FERIO_BID_URL = "https://ferio.bid/pbjs/bid"; +const ALIAS_BID_URL = "https://bidder.ferio.cloud/prebid/bid"; + +function bidRequest(overrides = {}) { + return { + bidder: BIDDER_CODE, + bidId: "bid-1", + adUnitCode: "adunit-1", + transactionId: "tx-1", + bidRequestsCount: 1, + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]], + }, + }, + params: { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + tenantId: "tenant-123", + }, + ...overrides, + }; +} + +function bidderRequest(overrides = {}) { + return { + bidderCode: BIDDER_CODE, + auctionId: "auction-1", + timeout: 800, + refererInfo: { + page: "https://example.com/article", + location: "https://example.com/article", + domain: "example.com", + ref: "https://referrer.example.com", + isAmp: false, + }, + ortb2: { + site: { + page: "https://example.com/article", + }, + device: { + ua: "Mozilla/5.0 test", + language: "en-US", + w: 1366, + h: 768, + }, + }, + ...overrides, + }; +} + +function getImp(request, impId) { + return request.data.imp.find((imp) => imp.id === impId); +} + +function buildRequest(bidRequests, requestOverrides = {}, adapterSpec = spec) { + return adapterSpec.buildRequests( + bidRequests, + bidderRequest({ bids: bidRequests, ...requestOverrides }) + )[0]; +} + +function serverResponse(bids, overrides = {}) { + return { + body: { + id: "response-1", + seatbid: [ + { + seat: BIDDER_CODE, + bid: bids, + }, + ], + cur: "USD", + ...overrides, + }, + }; +} + +describe("ferioBidAdapter", function () { + beforeEach(function () { + config.resetConfig(); + }); + + it("registers the ferio bidder code", function () { + expect(spec.code).to.equal(BIDDER_CODE); + }); + + describe("createFerioBidderSpec", function () { + it("creates alias specs with configurable endpoint and bidder params key", function () { + const aliasSpec = createFerioBidderSpec({ + code: ALIAS_CODE, + endpoint: "https://bidder.ferio.cloud/prebid", + paramBidderCode: ALIAS_PARAM_BIDDER_CODE, + }); + const aliasBid = bidRequest({ + bidder: ALIAS_CODE, + params: { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + }, + }); + + expect(aliasSpec.code).to.equal(ALIAS_CODE); + expect(aliasSpec.isBidRequestValid(aliasBid)).to.equal(true); + + const request = buildRequest( + [aliasBid], + { bidderCode: ALIAS_CODE, bids: [aliasBid] }, + aliasSpec + ); + const imp = getImp(request, "bid-1"); + + expect(request.url).to.equal(ALIAS_BID_URL); + expect(imp.ext.prebid.bidder[ALIAS_PARAM_BIDDER_CODE]).to.deep.equal({ + publisherId: "pub-123", + adUnitId: "ad-unit-456", + }); + expect(imp.ext.prebid.bidder).to.not.have.property(ALIAS_CODE); + + const bids = aliasSpec.interpretResponse( + serverResponse([], { + seatbid: [ + { + seat: "router-seat", + bid: [ + { + id: "seat-banner", + impid: "bid-1", + price: 1.1, + adm: "
ad
", + crid: "creative-banner", + w: 300, + h: 250, + mtype: 1, + }, + ], + }, + ], + }), + request + ); + + expect(bids).to.have.lengthOf(1); + expect(bids[0]).to.deep.include({ + requestId: "bid-1", + bidderCode: ALIAS_CODE, + adapterCode: ALIAS_CODE, + mediaType: BANNER, + }); + }); + + it("lets alias specs opt into extra required params", function () { + const aliasSpec = createFerioBidderSpec({ + code: ALIAS_CODE, + endpoint: "https://bidder.ferio.cloud/prebid/bid", + paramBidderCode: ALIAS_PARAM_BIDDER_CODE, + requiredParams: ["tenantId"], + }); + + expect( + aliasSpec.isBidRequestValid( + bidRequest({ + bidder: ALIAS_CODE, + params: { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + }, + }) + ) + ).to.equal(false); + expect( + aliasSpec.isBidRequestValid( + bidRequest({ + bidder: ALIAS_CODE, + }) + ) + ).to.equal(true); + }); + }); + + describe("isBidRequestValid", function () { + it("returns true for valid banner, video, and native requests", function () { + expect(spec.isBidRequestValid(bidRequest())).to.equal(true); + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: { + [VIDEO]: { + playerSize: [640, 480], + context: "instream", + }, + }, + }) + ) + ).to.equal(true); + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: { + [NATIVE]: {}, + }, + nativeOrtbRequest: { + ver: "1.2", + assets: [{ id: 1, title: { len: 90 } }], + }, + }) + ) + ).to.equal(true); + }); + + it("requires publisherId, adUnitId, and tenantId", function () { + [ + { + adUnitId: "ad-unit-456", + tenantId: "tenant-123", + }, + { + publisherId: "pub-123", + tenantId: "tenant-123", + }, + { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + }, + { + publisherId: "", + adUnitId: "ad-unit-456", + tenantId: "tenant-123", + }, + { + publisherId: "pub-123", + adUnitId: "", + tenantId: "tenant-123", + }, + { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + tenantId: "", + }, + ].forEach((params) => { + expect(spec.isBidRequestValid(bidRequest({ params }))).to.equal(false); + }); + }); + + it("does not accept alternate param names for adUnitId or tenantId", function () { + expect( + spec.isBidRequestValid( + bidRequest({ + params: { + publisherId: "pub-123", + tenantId: "tenant-123", + supplyTagId: "supply-tag-456", + }, + }) + ) + ).to.equal(false); + expect( + spec.isBidRequestValid( + bidRequest({ + params: { + publisherId: "pub-123", + tenantId: "tenant-123", + placementId: "placement-456", + }, + }) + ) + ).to.equal(false); + expect( + spec.isBidRequestValid( + bidRequest({ + params: { + publisherId: "pub-123", + adUnitId: "ad-unit-456", + tid: "tenant-123", + }, + }) + ) + ).to.equal(false); + }); + + it("requires valid media declarations", function () { + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: {}, + }) + ) + ).to.equal(false); + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: { + [BANNER]: {}, + }, + }) + ) + ).to.equal(false); + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: { + [VIDEO]: { + context: "instream", + }, + }, + }) + ) + ).to.equal(false); + expect( + spec.isBidRequestValid( + bidRequest({ + mediaTypes: { + [NATIVE]: {}, + }, + }) + ) + ).to.equal(false); + }); + }); + + describe("buildRequests", function () { + it("uses the Ferio OpenRTB endpoint and request options", function () { + config.setConfig({ + [BIDDER_CODE]: { + endpoint: "https://ignored.ferio.cloud", + }, + }); + + const requests = spec.buildRequests([bidRequest()], bidderRequest()); + + expect(requests).to.be.an("array").with.lengthOf(1); + expect(requests[0].url).to.equal(FERIO_BID_URL); + expect(requests[0].method).to.equal("POST"); + expect(requests[0].options).to.deep.equal({ + contentType: "text/plain", + withCredentials: true, + }); + expect(requests[0].data).to.be.an("object"); + expect(requests[0].data.imp).to.be.an("array").with.lengthOf(1); + expect(requests[0].data.tmax).to.equal(800); + expect(requests[0].data.site.page).to.equal( + "https://example.com/article" + ); + }); + + it("emits one OpenRTB request for all bids even when params.host is present", function () { + const balancerBid = bidRequest({ bidId: "bid-balancer" }); + const tenantABid = bidRequest({ + bidId: "bid-tenant-a", + params: { + publisherId: "pub-456", + adUnitId: "ad-unit-456", + tenantId: "tenant-456", + host: "https://tenant-a.ferio.cloud", + }, + }); + const tenantASecondBid = bidRequest({ + bidId: "bid-tenant-a-2", + params: { + publisherId: "pub-789", + adUnitId: "ad-unit-789", + tenantId: "tenant-789", + host: "https://tenant-a.ferio.cloud", + }, + }); + + const requests = spec.buildRequests( + [balancerBid, tenantABid, tenantASecondBid], + bidderRequest() + ); + + expect(requests).to.be.an("array").with.lengthOf(1); + expect(requests[0].url).to.equal(FERIO_BID_URL); + expect(requests[0].data.imp.map((imp) => imp.id)).to.deep.equal([ + "bid-balancer", + "bid-tenant-a", + "bid-tenant-a-2", + ]); + }); + + it("places bidder params under imp.ext.prebid.bidder.ferio", function () { + const request = buildRequest([ + bidRequest({ + bidder: ALIAS_CODE, + }), + ]); + const imp = getImp(request, "bid-1"); + + expect(imp.ext.prebid.bidder.ferio).to.deep.equal({ + publisherId: "pub-123", + adUnitId: "ad-unit-456", + tenantId: "tenant-123", + }); + expect(imp.ext.prebid.bidder).to.not.have.property(ALIAS_CODE); + }); + + it("builds banner, video, and native impressions", function () { + const userEids = [ + { + source: "pubcid.org", + uids: [{ id: "pubcid", atype: 1 }], + }, + ]; + const bannerBid = bidRequest({ + bidId: "banner-bid", + }); + const videoBid = bidRequest({ + bidId: "video-bid", + mediaTypes: { + [VIDEO]: { + playerSize: [[640, 480]], + context: "instream", + protocols: [2, 3, 5, 6], + mimes: ["video/mp4"], + }, + }, + ortb2Imp: { + ext: { + tid: "imp-tid", + }, + }, + }); + const nativeBid = bidRequest({ + bidId: "native-bid", + mediaTypes: { + [NATIVE]: {}, + }, + nativeOrtbRequest: { + ver: "1.2", + assets: [{ id: 1, title: { len: 90 } }], + }, + }); + + const request = buildRequest( + [bannerBid, videoBid, nativeBid], + { + ortb2: { + user: { + ext: { + eids: userEids, + }, + }, + }, + } + ); + + const bannerImp = getImp(request, "banner-bid"); + expect(bannerImp.banner.format).to.deep.equal([{ w: 300, h: 250 }]); + + const videoImp = getImp(request, "video-bid"); + expect(videoImp.ext.tid).to.equal("imp-tid"); + if (FEATURES.VIDEO) { + expect(videoImp.video).to.deep.include({ + w: 640, + h: 480, + }); + expect(videoImp.video.protocols).to.deep.equal([2, 3, 5, 6]); + expect(videoImp.video.mimes).to.deep.equal(["video/mp4"]); + } + + const nativeImp = getImp(request, "native-bid"); + if (FEATURES.NATIVE) { + expect(JSON.parse(nativeImp.native.request)).to.deep.equal({ + ver: "1.2", + assets: [{ id: 1, title: { len: 90 } }], + }); + expect(nativeImp.native.ver).to.equal("1.2"); + } + + expect(request.data.user.ext.eids).to.deep.equal(userEids); + }); + + it("passes privacy fields from ortb2 to the OpenRTB request", function () { + const request = buildRequest( + [bidRequest()], + { + ortb2: { + regs: { + ext: { + gdpr: 1, + us_privacy: "1YNN", + }, + gpp: "gpp-string", + gpp_sid: [8], + }, + user: { + ext: { + consent: "consent-string", + }, + }, + }, + } + ); + + expect(request.data.regs.ext.gdpr).to.equal(1); + expect(request.data.user.ext.consent).to.equal("consent-string"); + expect(request.data.regs.ext.us_privacy).to.equal("1YNN"); + expect(request.data.regs.gpp).to.equal("gpp-string"); + expect(request.data.regs.gpp_sid).to.deep.equal([8]); + }); + + it("passes schain from ortb2 to the OpenRTB request", function () { + const schain = { + ver: "1.0", + complete: 1, + nodes: [{ asi: "exchange.example", sid: "seller-123", hp: 1 }], + }; + const request = buildRequest( + [bidRequest()], + { + ortb2: { + source: { + ext: { + schain, + }, + }, + }, + } + ); + + expect(request.data.source.ext.schain).to.deep.equal(schain); + }); + + it("returns an empty request list when there are no valid bid requests", function () { + expect(spec.buildRequests([], bidderRequest())).to.deep.equal([]); + }); + }); + + describe("interpretResponse", function () { + it("normalizes router response seats to the requested adapter bidder code", function () { + const requestBid = bidRequest(); + const request = buildRequest([requestBid]); + const bids = spec.interpretResponse( + serverResponse([], { + seatbid: [ + { + seat: "4OkkP5Kru1ICV7pVr5sTkA", + bid: [ + { + id: "seat-banner", + impid: "bid-1", + price: 1.1, + adm: "
ad
", + crid: "creative-banner", + w: 300, + h: 250, + mtype: 1, + }, + ], + }, + ], + }), + request + ); + const bid = bids[0]; + + expect(bids).to.have.lengthOf(1); + expect(bid).to.deep.include({ + requestId: "bid-1", + bidderCode: BIDDER_CODE, + adapterCode: BIDDER_CODE, + currency: "USD", + creativeId: "creative-banner", + ttl: 300, + netRevenue: true, + mediaType: BANNER, + width: 300, + height: 250, + ad: "
ad
", + }); + expect( + isValid( + requestBid.adUnitCode, + { ...bid }, + { + index: stubAuctionIndex({ bidRequests: [requestBid] }), + } + ) + ).to.equal(true); + }); + + it("parses standard OpenRTB banner, video, and native responses", function () { + const nativeAd = { + ver: "1.2", + assets: [{ id: 1, title: { text: "Native title" } }], + link: { url: "https://example.com/click" }, + }; + const request = buildRequest([ + bidRequest({ + bidId: "banner-bid", + }), + bidRequest({ + bidId: "video-bid", + mediaTypes: { + [VIDEO]: { + playerSize: [[640, 480]], + context: "instream", + mimes: ["video/mp4"], + }, + }, + }), + bidRequest({ + bidId: "native-bid", + mediaTypes: { + [NATIVE]: {}, + }, + nativeOrtbRequest: { + ver: "1.2", + assets: [{ id: 1, title: { len: 90 } }], + }, + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-banner", + impid: "banner-bid", + price: 1.1, + adm: "
ad
", + adomain: ["example.com"], + crid: "creative-banner", + w: 300, + h: 250, + mtype: 1, + }, + { + id: "seat-video", + impid: "video-bid", + price: 2.1, + adm: "", + nurl: "https://example.com/vast", + crid: "creative-video", + mtype: 2, + }, + { + id: "seat-native", + impid: "native-bid", + price: 3.1, + adm: JSON.stringify(nativeAd), + crid: "creative-native", + mtype: 4, + }, + ]), + request + ); + + expect(bids).to.be.an("array").with.lengthOf(3); + + const bannerBid = bids.find((bid) => bid.requestId === "banner-bid"); + expect(bannerBid).to.deep.include({ + requestId: "banner-bid", + seatBidId: "seat-banner", + cpm: 1.1, + currency: "USD", + creativeId: "creative-banner", + ttl: 300, + netRevenue: true, + mediaType: BANNER, + width: 300, + height: 250, + ad: "
ad
", + bidderCode: BIDDER_CODE, + adapterCode: BIDDER_CODE, + }); + expect(bannerBid.meta.advertiserDomains).to.deep.equal(["example.com"]); + + const videoBid = bids.find((bid) => bid.requestId === "video-bid"); + expect(videoBid).to.deep.include({ + requestId: "video-bid", + cpm: 2.1, + currency: "USD", + creativeId: "creative-video", + ttl: 300, + netRevenue: true, + mediaType: VIDEO, + }); + if (FEATURES.VIDEO) { + expect(videoBid).to.deep.include({ + vastXml: "", + vastUrl: "https://example.com/vast", + playerWidth: 640, + playerHeight: 480, + }); + } + + const nativeBid = bids.find((bid) => bid.requestId === "native-bid"); + expect(nativeBid).to.deep.include({ + requestId: "native-bid", + cpm: 3.1, + currency: "USD", + creativeId: "creative-native", + ttl: 300, + netRevenue: true, + mediaType: NATIVE, + }); + if (FEATURES.NATIVE) { + expect(nativeBid.native.ortb).to.deep.equal(nativeAd); + } + }); + + it("unwraps IAB native ADM wrapper responses", function () { + if (!FEATURES.NATIVE) { + this.skip(); + } + + const nativeAd = { + ver: "1.2", + assets: [ + { id: 1, title: { text: "Simple Native Test Ad" } }, + { + id: 2, + img: { + url: "data:image/svg+xml,%3Csvg%3E%3C/svg%3E", + w: 300, + h: 250, + }, + }, + ], + link: { url: "https://example.com/click" }, + imptrackers: ["https://example.com/imp"], + }; + const request = buildRequest([ + bidRequest({ + bidId: "native-bid", + mediaTypes: { + [NATIVE]: {}, + }, + nativeOrtbRequest: { + ver: "1.2", + assets: [ + { id: 1, title: { len: 90 } }, + { id: 2, img: { type: 3, w: 300, h: 250 } }, + ], + }, + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-native", + impid: "native-bid", + price: 1.1622, + adm: JSON.stringify({ native: nativeAd }), + crid: "creative-native", + mtype: 4, + ext: { + prebid: { + type: NATIVE, + }, + }, + }, + ]), + request + ); + + expect(bids).to.be.an("array").with.lengthOf(1); + expect(bids[0]).to.deep.include({ + requestId: "native-bid", + cpm: 1.1622, + creativeId: "creative-native", + mediaType: NATIVE, + }); + expect(bids[0].native.ortb).to.deep.equal(nativeAd); + }); + + it("uses bid.ext.prebid.type when mtype is absent", function () { + const request = buildRequest([ + bidRequest({ + bidId: "video-bid", + mediaTypes: { + [VIDEO]: { + playerSize: [[640, 480]], + context: "instream", + }, + }, + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-video", + impid: "video-bid", + price: 2.1, + adm: "", + crid: "creative-video", + ext: { + prebid: { + type: VIDEO, + }, + }, + }, + ]), + request + ); + + expect(bids).to.have.lengthOf(1); + expect(bids[0].mediaType).to.equal(VIDEO); + if (FEATURES.VIDEO) { + expect(bids[0].vastXml).to.equal(""); + } + }); + + it("falls back to the original request media type for single-format bids", function () { + const request = buildRequest([ + bidRequest({ + bidId: "video-bid", + mediaTypes: { + [VIDEO]: { + playerSize: [[640, 480]], + context: "instream", + }, + }, + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-video", + impid: "video-bid", + price: 2.1, + adm: "", + crid: "creative-video", + }, + ]), + request + ); + + expect(bids).to.have.lengthOf(1); + expect(bids[0].mediaType).to.equal(VIDEO); + if (FEATURES.VIDEO) { + expect(bids[0].vastXml).to.equal(""); + } + }); + + it("does not leak fallback media type across bids with the same impid", function () { + const request = buildRequest([ + bidRequest({ + bidId: "banner-bid", + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-banner", + impid: "banner-bid", + price: 1.1, + adm: "
ad
", + crid: "creative-banner", + }, + { + id: "seat-video", + impid: "banner-bid", + price: 2.1, + adm: "", + crid: "creative-video", + ext: { + prebid: { + type: VIDEO, + }, + }, + }, + ]), + request + ); + + expect(bids).to.have.lengthOf(2); + expect(bids[0].mediaType).to.equal(BANNER); + expect(bids[1].mediaType).to.equal(VIDEO); + if (FEATURES.VIDEO) { + expect(bids[1].vastXml).to.equal(""); + } + }); + + it("skips multi-format responses without an ORTB media type", function () { + const request = buildRequest([ + bidRequest({ + bidId: "multi-format-bid", + mediaTypes: { + [BANNER]: { + sizes: [[300, 250]], + }, + [VIDEO]: { + playerSize: [[640, 480]], + context: "instream", + }, + }, + }), + ]); + + const bids = spec.interpretResponse( + serverResponse([ + { + id: "seat-unknown", + impid: "multi-format-bid", + price: 1.1, + adm: "
ad
", + crid: "creative-unknown", + }, + ]), + request + ); + + expect(bids).to.deep.equal([]); + }); + + it("returns an empty array for missing or malformed response bodies", function () { + const request = buildRequest([bidRequest()]); + + expect(spec.interpretResponse({}, request)).to.deep.equal([]); + expect(spec.interpretResponse({ body: null }, request)).to.deep.equal([]); + expect(spec.interpretResponse({ body: {} }, request)).to.deep.equal([]); + expect( + spec.interpretResponse( + { + body: { + seatbid: [], + }, + }, + request + ) + ).to.deep.equal([]); + expect( + spec.interpretResponse({ + body: { + seatbid: [], + }, + }) + ).to.deep.equal([]); + }); + }); + + describe("getUserSyncs", function () { + it("returns an empty array when syncs are disabled", function () { + expect( + spec.getUserSyncs( + { + iframeEnabled: false, + pixelEnabled: false, + }, + [ + { + body: { + ext: { + ferio: { + pixels: [["image", "https://ignored.example.com/sync"]], + }, + }, + }, + }, + ] + ) + ).to.deep.equal([]); + }); + + it("returns image syncs derived from the auction endpoint when pixel sync is enabled", function () { + const syncs = spec.getUserSyncs( + { + iframeEnabled: false, + pixelEnabled: true, + }, + [ + { + body: { + ext: { + ferio: { + pixels: [["image", "https://ignored.example.com/sync"]], + }, + }, + }, + }, + ] + ); + + expect(syncs).to.deep.equal([ + { + type: "image", + url: "https://ferio.bid/pbjs/sync?us_privacy=&gdpr=0&gdpr_consent=", + }, + ]); + }); + + it("returns iframe syncs derived from the auction endpoint when iframe sync is enabled", function () { + const syncs = spec.getUserSyncs( + { + iframeEnabled: true, + pixelEnabled: false, + }, + [] + ); + + expect(syncs).to.deep.equal([ + { + type: "iframe", + url: "https://ferio.bid/pbjs/cli/iframe.html?us_privacy=&gdpr=0&gdpr_consent=", + }, + ]); + }); + + it("returns both sync types with encoded privacy parameters when both are enabled", function () { + const syncs = spec.getUserSyncs( + { + iframeEnabled: true, + pixelEnabled: true, + }, + [], + { + gdprApplies: true, + consentString: "gdpr consent", + }, + "1YA-", + { + gppString: "gpp consent", + applicableSections: [8, 9], + } + ); + + expect(syncs).to.deep.equal([ + { + type: "image", + url: "https://ferio.bid/pbjs/sync?us_privacy=1YA-&gdpr=1&gdpr_consent=gdpr%20consent&gpp=gpp%20consent&gpp_sid=8%2C9", + }, + { + type: "iframe", + url: "https://ferio.bid/pbjs/cli/iframe.html?us_privacy=1YA-&gdpr=1&gdpr_consent=gdpr%20consent&gpp=gpp%20consent&gpp_sid=8%2C9", + }, + ]); + }); + + it("derives alias sync URLs from the alias auction endpoint", function () { + const aliasSpec = createFerioBidderSpec({ + code: ALIAS_CODE, + endpoint: "https://bidder.ferio.cloud/prebid", + paramBidderCode: ALIAS_PARAM_BIDDER_CODE, + }); + + expect( + aliasSpec.getUserSyncs({ + iframeEnabled: true, + pixelEnabled: true, + }) + ).to.deep.equal([ + { + type: "image", + url: "https://bidder.ferio.cloud/prebid/sync?us_privacy=&gdpr=0&gdpr_consent=", + }, + { + type: "iframe", + url: "https://bidder.ferio.cloud/prebid/cli/iframe.html?us_privacy=&gdpr=0&gdpr_consent=", + }, + ]); + }); + + it("filters user syncs to HTTPS URLs", function () { + const insecureSpec = createFerioBidderSpec({ + code: ALIAS_CODE, + endpoint: "http://bidder.ferio.cloud/prebid", + paramBidderCode: ALIAS_PARAM_BIDDER_CODE, + }); + + const syncs = insecureSpec.getUserSyncs( + { + iframeEnabled: true, + pixelEnabled: true, + }, + [], + { + gdprApplies: true, + consentString: "gdpr consent", + }, + "1YA-", + { + gppString: "gpp consent", + applicableSections: [8, 9], + } + ); + + expect(syncs).to.deep.equal([]); + }); + }); +}); From d13c6a835062bd575679120e3b6135f764014c9c Mon Sep 17 00:00:00 2001 From: tososhi Date: Tue, 2 Jun 2026 19:39:34 +0900 Subject: [PATCH 024/124] fluct Bid Adapter: add device.ext.vpw/vph viewport size signals (#14957) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add instl support * falseの場合も明示的に送信するようにした * fluct Bid Adapter: allow wrapper to inject its name via x-fluct-prebid-wrapper header Read `fluct.wrapperName` from Prebid config and, when set, attach it as the `x-fluct-prebid-wrapper` HTTP header on every bid request so the fluct bidder can identify which wrapper the request originates from. Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: move customHeaders construction outside _each loop Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: add device.ext.vpw/vph viewport size signals Pass viewport dimensions (vpw, vph) from ortb2.device.ext to the fluct server. Viewability prediction by DSPs uses viewport size to differentiate between screen size (w/h) and actual visible area, which directly affects bid prices. Co-Authored-By: Claude Sonnet 4.6 --------- Co-authored-by: yosei-ito Co-authored-by: himu62 Co-authored-by: himu Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Patrick McCann --- modules/fluctBidAdapter.js | 24 ++++++--- test/spec/modules/fluctBidAdapter_spec.js | 63 +++++++++++++++++++++++ 2 files changed, 81 insertions(+), 6 deletions(-) diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index 0281e47c95c..77f8d43b311 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -10,7 +10,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fluct'; const END_POINT = 'https://hb.adingo.jp/prebid/'; -const VERSION = '1.5'; +const VERSION = '1.6'; const NET_REVENUE = true; const TTL = 300; const DEFAULT_CURRENCY = 'JPY'; @@ -112,6 +112,15 @@ export const spec = { buildRequests: (validBidRequests, bidderRequest) => { const serverRequests = []; const page = bidderRequest.refererInfo.page; + const wrapperName = config.getConfig('fluct')?.wrapperName; + const customHeaders = { + 'x-fluct-app': 'prebid/fluctBidAdapter', + 'x-fluct-version': VERSION, + 'x-openrtb-version': 2.5, + }; + if (wrapperName) { + customHeaders['x-fluct-prebid-wrapper'] = wrapperName; + } _each(validBidRequests, (request) => { const impExt = request.ortb2Imp?.ext; @@ -218,6 +227,13 @@ export const spec = { if (ortb2Device.h) data.device.h = ortb2Device.h; if (ortb2Device.language) data.device.language = ortb2Device.language; if (ortb2Device.devicetype) data.device.devicetype = ortb2Device.devicetype; + const vpw = ortb2Device.ext?.vpw; + const vph = ortb2Device.ext?.vph; + if (vpw != null || vph != null) { + data.device.ext = {}; + if (vpw != null) data.device.ext.vpw = vpw; + if (vph != null) data.device.ext.vph = vph; + } } // Set top-level bidfloor to the highest floor across all sizes @@ -239,11 +255,7 @@ export const spec = { options: { contentType: 'application/json', withCredentials: true, - customHeaders: { - 'x-fluct-app': 'prebid/fluctBidAdapter', - 'x-fluct-version': VERSION, - 'x-openrtb-version': 2.5 - } + customHeaders, }, data: data }); diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index 99d7d1c78a4..312c58e9690 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -192,6 +192,18 @@ describe('fluctAdapter', function () { expect(request.data.regs).to.eql(undefined); }); + it('does not include x-fluct-prebid-wrapper header by default', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.options.customHeaders['x-fluct-prebid-wrapper']).to.be.undefined; + }); + + it('includes x-fluct-prebid-wrapper header when fluct.wrapperName is configured', function () { + sb.stub(config, 'getConfig').withArgs('fluct').returns({ wrapperName: 'boost' }); + + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.options.customHeaders['x-fluct-prebid-wrapper']).to.equal('boost'); + }); + it('includes filtered user.eids if any exists', function () { const bidRequests2 = bidRequests.map( (bidReq) => Object.assign({}, bidReq, { @@ -555,6 +567,57 @@ describe('fluctAdapter', function () { expect(request.data.device).to.eql({ sua }); }); + it('includes device.ext.vpw and device.ext.vph from ortb2.device.ext', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { + w: 1920, + h: 1080, + ext: { vpw: 1280, vph: 720 }, + }, + }, + }))[0]; + expect(request.data.device).to.eql({ + w: 1920, + h: 1080, + ext: { vpw: 1280, vph: 720 }, + }); + }); + + it('includes device.ext.vpw only when vph is absent', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { + ext: { vpw: 375 }, + }, + }, + }))[0]; + expect(request.data.device).to.eql({ ext: { vpw: 375 } }); + }); + + it('includes device.ext.vph only when vpw is absent', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { + ext: { vph: 667 }, + }, + }, + }))[0]; + expect(request.data.device).to.eql({ ext: { vph: 667 } }); + }); + + it('does not set device.ext when neither vpw nor vph is present', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + device: { + w: 1920, + h: 1080, + }, + }, + }))[0]; + expect(request.data.device.ext).to.eql(undefined); + }); + it('includes no data.imp by default', function () { const request = spec.buildRequests(bidRequests, bidderRequest)[0]; expect(request.data.imp).to.eql(undefined); From 2a0e6c891ff6b05e9a76a94cfbd48066f00fda11 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 2 Jun 2026 10:37:47 -0400 Subject: [PATCH 025/124] Core: Avoid keepalive for >64KiB request bodies and log warning (#14916) * Core: warn when keepalive is skipped for oversized payload * Potential fix for pull request finding 'Unused variable, import, function or class' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * use blob() to calculate size * Potential fix for pull request finding 'Semicolon insertion' Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> * lint * Fix firefox losing keepalive, not supporting body * Safari fix * update comment --------- Co-authored-by: Copilot Autofix powered by AI <223894421+github-code-quality[bot]@users.noreply.github.com> Co-authored-by: Demetrio Girardi --- src/ajax.ts | 40 +++++++++-- test/mocks/xhr.js | 4 ++ test/spec/unit/core/ajax_spec.js | 118 +++++++++++++++++++++++++------ 3 files changed, 134 insertions(+), 28 deletions(-) diff --git a/src/ajax.ts b/src/ajax.ts index 91c3f92a0cf..a082e0972d3 100644 --- a/src/ajax.ts +++ b/src/ajax.ts @@ -2,12 +2,12 @@ import { ACTIVITY_ACCESS_REQUEST_CREDENTIALS } from './activities/activities.js' import { activityParams } from './activities/activityParams.js'; import { isActivityAllowed } from './activities/rules.js'; import { config } from './config.js'; -import { buildUrl, logError, parseUrl } from './utils.js'; +import { buildUrl, logError, logWarn, parseUrl } from './utils.js'; import type { ModuleType } from "./activities/modules.ts"; export const dep = { fetch: window.fetch.bind(window), - makeRequest: (r, o) => new Request(r, o), + makeRequest: (r, o?) => new Request(r, o), timeout(timeout, resource) { const ctl = new AbortController(); let cancelTimer = setTimeout(() => { @@ -27,6 +27,7 @@ export const dep = { const GET = 'GET'; const POST = 'POST'; const CTYPE = 'Content-Type'; +const KEEPALIVE_MAX_BODY_SIZE = 64 * 1024; export interface AjaxOptions { /** * HTTP method. @@ -94,10 +95,12 @@ export function toFetchRequest(url, data, options: AjaxOptions = {}) { rqOpts.suppressTopicsEnrollmentWarning = options.suppressTopicsEnrollmentWarning; } } + const request = dep.makeRequest(url, rqOpts); if (options.keepalive) { - rqOpts.keepalive = true; + // do not set the "real" keepalive flag as Safari won't allow us to change it + (request as any)._keepalive = true; } - return dep.makeRequest(url, rqOpts); + return request; } function callerContext(callers = []) { @@ -147,12 +150,21 @@ function fetcherFactoryImpl(context, timeout = 3000, { request, done }: any = {} context = fixedCallerContext(moduleType, moduleName); } let fetcher = (resource, options) => { + // special treatment for keepalive - because of inconsistent browser behavior, + // we must start with keepalive: false and flip it as a last step + // Updating request options with new Request(oldRequest, newOptions): + // on Firefox, will default newOptions.keepalive = false + // on Safari, will not allow keepalive = true to become = false + const keepalive = resource?._keepalive ?? options?.keepalive ?? resource?.keepalive; let to; if (timeout != null && options?.signal == null && !config.getConfig('disableAjaxTimeout')) { to = dep.timeout(timeout, resource); options = Object.assign({ signal: to.signal }, options); } - let request = dep.makeRequest(resource, options); + let request = dep.makeRequest(resource, { + ...options, + keepalive: false + }); if ( request.credentials === 'include' && ( @@ -161,11 +173,25 @@ function fetcherFactoryImpl(context, timeout = 3000, { request, done }: any = {} ) ) { request = dep.makeRequest(request, { - keepalive: request.keepalive, // According to MDN this should be unnecessary, but Firefox will lose `keepalive` without itt credentials: 'same-origin' }); } - let pm = dep.fetch(request); + let pm; + if (keepalive) { + // requests can be "used" only once - and blob() counts as usage, so clone the request + pm = request.clone().blob().then(blob => { + if (blob.size > KEEPALIVE_MAX_BODY_SIZE) { + logWarn(`Ignoring keepalive: request body exceeds ${KEEPALIVE_MAX_BODY_SIZE} bytes`, request); + } else { + request = dep.makeRequest(request, { + keepalive: true + }); + } + return dep.fetch(request); + }); + } else { + pm = dep.fetch(request); + } if (to?.done != null) pm = pm.finally(to.done); return pm; }; diff --git a/test/mocks/xhr.js b/test/mocks/xhr.js index 7c526cbeb9c..435e048f045 100644 --- a/test/mocks/xhr.js +++ b/test/mocks/xhr.js @@ -21,6 +21,10 @@ function mockFetchServer() { // firefox will lose keepalive otherwise keepalive: resource?.keepalive }, options)); + request.clone = () => ({ + ...request, + blob: () => GreedyPromise.resolve(new Blob([requestBody])) + }) bodies.set(request, requestBody); return request; } diff --git a/test/spec/unit/core/ajax_spec.js b/test/spec/unit/core/ajax_spec.js index c3fc9ae2683..6ea5883d9e2 100644 --- a/test/spec/unit/core/ajax_spec.js +++ b/test/spec/unit/core/ajax_spec.js @@ -1,10 +1,18 @@ -import { ajaxBuilder, attachCallbacks, dep, fetch, ajax, fetcherFactory, toFetchRequest } from '../../../../src/ajax.js'; +import { + ajax, + ajaxBuilder, + attachCallbacks, + dep, + fetch, + fetcherFactory, + toFetchRequest +} from '../../../../src/ajax.js'; import { config } from 'src/config.js'; import { server } from '../../../mocks/xhr.js'; import * as utils from 'src/utils.js'; -import { logError } from 'src/utils.js'; import { registerActivityControl } from '../../../../src/activities/rules.js'; import { ACTIVITY_ACCESS_REQUEST_CREDENTIALS } from '../../../../src/activities/activities.js'; +import { defer } from 'src/utils/promise.js'; const EXAMPLE_URL = 'https://www.example.com'; @@ -46,13 +54,13 @@ describe('ajax', () => { if (denyCreds) { return { allow: false }; } - }) - resetRule = registerActivityControl(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, 'test', arqRule) - }) + }); + resetRule = registerActivityControl(ACTIVITY_ACCESS_REQUEST_CREDENTIALS, 'test', arqRule); + }); afterEach(() => { resetRule(); config.resetConfig(); - }) + }); Object.entries({ 'URL': [EXAMPLE_URL, { credentials: 'include' }], 'request object': [new Request(EXAMPLE_URL, { credentials: 'include' })], @@ -70,9 +78,9 @@ describe('ajax', () => { componentName: 'test' })); expect(server.requests[0].fetch.request.credentials).to.eql('same-origin'); - }) - }) - }) + }); + }); + }); it('does not timeout after it completes', () => { const fetch = fetcherFactory(1000); @@ -247,10 +255,10 @@ describe('ajax', () => { toFetchRequest(EXAMPLE_URL, null, opts); sinon.assert.calledWithMatch(dep.makeRequest, sinon.match.any, { [option]: undefined }); }); - }) - }) - }) - }) + }); + }); + }); + }); }); describe('credentials', () => { @@ -330,12 +338,80 @@ describe('ajax', () => { component: 'prebid.test' })); sinon.assert.calledOnce(arqRule); - }) + }); }); - }) + }); }); }); + describe('keepalive', () => { + let sandbox, request; + before(() => { + server.restore(); + }) + after(() => { + server.enable(); + }) + beforeEach(() => { + request = defer(); + sandbox = sinon.createSandbox(); + sandbox.stub(dep, 'makeRequest').callsFake((r, o) => { + const req = new Request(r, o); + sandbox.spy(req, 'clone'); + return req; + }); + sandbox.stub(dep, 'fetch').callsFake(req => { + request.resolve(req); + return new Promise((resolve) => {}); + }); + }); + afterEach(() => { + sandbox.restore(); + }) + Object.entries({ + 'small payload': { + body: 'x'.repeat(1024), + keepalive: true + }, + 'large payload': { + body: 'x'.repeat(65537), + keepalive: false + }, + }).forEach(([t, { body, keepalive }]) => { + describe(`POST with ${t}`, () => { + Object.entries({ + ajax() { + ajax(EXAMPLE_URL, () => {}, body, { method: 'POST', keepalive: true }) + }, + fetch() { + fetch(EXAMPLE_URL, { method: 'POST', body, keepalive: true }) + } + }).forEach(([name, fn]) => { + describe(name, () => { + it(`should set keepalive = ${keepalive}`, () => { + fn(); + return request.promise.then(req => { + expect(req.keepalive).to.eql(keepalive); + }) + }); + it('should not use the body', () => { + fn(); + return request.promise.then(req => { + expect(req.bodyUsed).to.be.false; + }) + }) + }) + }) + }) + }); + it('should not try to get body size for requests that do not ask for keepalive', () => { + fetch(EXAMPLE_URL, { body: 'test', method: 'POST' }); + return request.promise.then(req => { + sinon.assert.notCalled(req.clone); + }) + }) + }) + describe('attachCallbacks', () => { const sampleHeaders = new Headers({ 'x-1': 'v1', @@ -394,7 +470,7 @@ describe('ajax', () => { done(); } }); - }) + }); Object.entries({ '2xx response': { @@ -459,11 +535,11 @@ describe('ajax', () => { afterEach(() => { sandbox.restore(); - }) + }); function checkXHR(xhr) { utils.logError.resetHistory(); - const serialized = JSON.parse(JSON.stringify(xhr)) + const serialized = JSON.parse(JSON.stringify(xhr)); // serialization of `responseXML` should not generate console messages sinon.assert.notCalled(utils.logError); @@ -516,8 +592,8 @@ describe('ajax', () => { expect(payload).to.eql(body); checkXHR(xhr); done(); - }) - }) + }); + }); } }); }); @@ -549,4 +625,4 @@ describe('ajax', () => { }); }); }); -}) +}); From 8bd1727df05f2c3b9b46d5d49c1bea120cdbdccc Mon Sep 17 00:00:00 2001 From: Valentino <57947465+Valentino3@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:54:39 -0300 Subject: [PATCH 026/124] ResetDigital Bid Adapter: Forward user EIDs (#14975) * ResetDigital: Forward user EIDs * ResetDigital: Aggregate user EIDs * ResetDigital: Simplify EID forwarding --- modules/resetdigitalBidAdapter.js | 9 +++- modules/resetdigitalBidAdapter.md | 5 +++ .../modules/resetdigitalBidAdapter_spec.js | 42 +++++++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/modules/resetdigitalBidAdapter.js b/modules/resetdigitalBidAdapter.js index d34ca4b7c9b..c96aa2776ab 100644 --- a/modules/resetdigitalBidAdapter.js +++ b/modules/resetdigitalBidAdapter.js @@ -58,7 +58,8 @@ export const spec = { return result; } - const userIds = extractUserIdsFromEids(bidderRequest.userIdAsEids); + const userEids = validBidRequests[0]?.userIdAsEids || []; + const userIds = extractUserIdsFromEids(userEids); const payload = { start_time: timestamp(), @@ -75,6 +76,12 @@ export const spec = { sync_limit: spb, }; + if (userEids.length) { + payload.user = { + eids: deepClone(userEids), + }; + } + if (bidderRequest && bidderRequest.gdprConsent) { payload.gdpr = { applies: bidderRequest.gdprConsent.gdprApplies, diff --git a/modules/resetdigitalBidAdapter.md b/modules/resetdigitalBidAdapter.md index 64b600a7cc0..339d85abbf4 100644 --- a/modules/resetdigitalBidAdapter.md +++ b/modules/resetdigitalBidAdapter.md @@ -11,6 +11,11 @@ Maintainer: BidderSupport@resetdigital.co Prebid adapter for Reset Digital. Requires approval and account setup. Video is supported but requires a publisher supplied renderer at this time. +# User IDs + +The adapter forwards Prebid User ID module EIDs from `bidRequest.userIdAsEids` in OpenRTB format under `user.eids`. +Publishers should include and configure the Prebid User ID module and any desired ID submodules to make IDs available. + # Test Parameters ## Web diff --git a/test/spec/modules/resetdigitalBidAdapter_spec.js b/test/spec/modules/resetdigitalBidAdapter_spec.js index 80ae8caea7d..cb24d4d3ef5 100644 --- a/test/spec/modules/resetdigitalBidAdapter_spec.js +++ b/test/spec/modules/resetdigitalBidAdapter_spec.js @@ -105,6 +105,48 @@ describe('resetdigitalBidAdapter', function () { it('should include media types', function () { expect(rdata.imps[0].media_types !== null).to.be.true }) + + it('should pass user id eids in OpenRTB format', function () { + const liverampEid = { + source: 'liveramp.com', + uids: [{ + id: 'XiR-liveRamp-envelope', + atype: 1, + ext: { + rtiPartner: 'idl', + stype: 'ppuid' + } + }] + } + const sharedIdEid = { + source: 'sharedid.org', + uids: [{ + id: 'shared-id', + atype: 1 + }] + } + const eids = [liverampEid, sharedIdEid] + + const request = spec.buildRequests([{ + ...bannerRequest, + userIdAsEids: eids + }], { refererInfo: {} }) + const payload = JSON.parse(request.data) + + expect(payload.user.eids).to.deep.equal(eids) + expect(payload.user_ids).to.deep.equal({ + 'liveramp.com': { + id: 'XiR-liveRamp-envelope', + ext: { + rtiPartner: 'idl', + stype: 'ppuid' + } + }, + 'sharedid.org': { + id: 'shared-id' + } + }) + }) }) describe('interpretResponse', function () { From 2e1aed9973a20f99e5e38d3a6907c94164abeb22 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Tue, 2 Jun 2026 07:55:15 -0700 Subject: [PATCH 027/124] acxiomRtd: fix tests (#14974) --- modules/acxiomRealIdSystem.ts | 5 +++- plugins/callerContext.js | 2 +- test/spec/modules/acxiomRealIdSystem_spec.js | 25 ++++++++++---------- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/modules/acxiomRealIdSystem.ts b/modules/acxiomRealIdSystem.ts index 7776ce61e2a..d37327363c9 100644 --- a/modules/acxiomRealIdSystem.ts +++ b/modules/acxiomRealIdSystem.ts @@ -19,6 +19,9 @@ const MODULE_NAME = 'acxiomRealId' as const; const DEFAULT_API_URL = 'https://ids.api.gcprivacy.id/v1/eid/l'; const DEFAULT_SOURCE_ID = 'acxiom.id'; export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME }); +export const dep = { + ajaxBuilder +} export type AcxiomRealIdParams = { /** Partner ID issued by GrowthCode on behalf of Acxiom */ @@ -197,7 +200,7 @@ export const acxiomRealIdSubmodule: IdProviderSpec = { return { callback: (cb) => { - const ajax = ajaxBuilder(); + const ajax = dep.ajaxBuilder(); ajax( url, { diff --git a/plugins/callerContext.js b/plugins/callerContext.js index 73dc5a99358..4df6de5b9ca 100644 --- a/plugins/callerContext.js +++ b/plugins/callerContext.js @@ -32,7 +32,7 @@ const getCallers = (() => { cache[filename] = callers.callers; } else { console.warn(`WARNING: cannot determine moduleType/moduleName to associate with '${filename}'. If this is a new adapter it may need metadata to be updated. ${message}`) - cache[filename] = null; + cache[filename] = []; } } return cache[filename]; diff --git a/test/spec/modules/acxiomRealIdSystem_spec.js b/test/spec/modules/acxiomRealIdSystem_spec.js index b534a2bbc03..fccd5ed0ba8 100644 --- a/test/spec/modules/acxiomRealIdSystem_spec.js +++ b/test/spec/modules/acxiomRealIdSystem_spec.js @@ -1,5 +1,4 @@ -import { acxiomRealIdSubmodule, storage } from 'modules/acxiomRealIdSystem.ts'; -import * as ajaxLib from 'src/ajax.js'; +import { acxiomRealIdSubmodule, dep, storage } from 'modules/acxiomRealIdSystem.ts'; import { gdprDataHandler, uspDataHandler, gppDataHandler } from 'src/adapterManager.js'; import { expect } from 'chai'; @@ -349,7 +348,7 @@ describe('acxiomRealIdSystem', () => { it('should POST to the default API URL with partnerId and default sourceId in body', (done) => { let capturedUrl, capturedBody, capturedOptions; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks, body, options) => { capturedUrl = url; capturedBody = body; @@ -380,7 +379,7 @@ describe('acxiomRealIdSystem', () => { it('should include HEM in POST body when provided', (done) => { let capturedBody; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks, body) => { capturedBody = body; callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); @@ -402,7 +401,7 @@ describe('acxiomRealIdSystem', () => { it('should not include HEM in POST body when not provided', (done) => { let capturedBody; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks, body) => { capturedBody = body; callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); @@ -424,7 +423,7 @@ describe('acxiomRealIdSystem', () => { it('should use custom sourceId in POST body when provided', (done) => { let capturedBody; const customSourceId = 'custom.source'; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks, body) => { capturedBody = body; callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); @@ -447,7 +446,7 @@ describe('acxiomRealIdSystem', () => { it('should use custom API URL when provided', (done) => { let capturedUrl; const customUrl = 'https://custom.example.com/v1/eid/l'; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { capturedUrl = url; callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); @@ -468,7 +467,7 @@ describe('acxiomRealIdSystem', () => { it('should strip trailing slashes from custom API URL', (done) => { let capturedUrl; - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { capturedUrl = url; callbacks.success(makeEidResponse(REAL_ID_TOKEN, 1)); @@ -487,7 +486,7 @@ describe('acxiomRealIdSystem', () => { }); it('should preserve atype from API response', (done) => { - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { callbacks.success(makeEidResponse(REAL_ID_TOKEN, 3)); } @@ -505,7 +504,7 @@ describe('acxiomRealIdSystem', () => { }); it('should call callback with undefined on no-match response', (done) => { - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { callbacks.success(JSON.stringify({ requestId: 'test', user: {} })); } @@ -523,7 +522,7 @@ describe('acxiomRealIdSystem', () => { }); it('should call callback with undefined when eids array is empty', (done) => { - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { callbacks.success(makeEmptyResponse()); } @@ -541,7 +540,7 @@ describe('acxiomRealIdSystem', () => { }); it('should call callback with undefined on API error', (done) => { - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { callbacks.error('server error'); } @@ -559,7 +558,7 @@ describe('acxiomRealIdSystem', () => { }); it('should call callback with undefined on malformed JSON response', (done) => { - ajaxBuilderStub = sinon.stub(ajaxLib, 'ajaxBuilder').returns( + ajaxBuilderStub = sinon.stub(dep, 'ajaxBuilder').returns( (url, callbacks) => { callbacks.success('not json'); } From 74c9b4f75ba38be8a6d3989e2a722c155bc5f726 Mon Sep 17 00:00:00 2001 From: Maxime Lequain Date: Tue, 2 Jun 2026 18:27:27 +0200 Subject: [PATCH 028/124] feat: add hubvisor analytics adapter (#14976) --- modules/hubvisorAnalyticsAdapter.md | 11 +++++++++++ modules/hubvisorAnalyticsAdapter.ts | 15 +++++++++++++++ .../modules/hubvisorAnalyticsAdapter_spec.js | 18 ++++++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 modules/hubvisorAnalyticsAdapter.md create mode 100644 modules/hubvisorAnalyticsAdapter.ts create mode 100644 test/spec/modules/hubvisorAnalyticsAdapter_spec.js diff --git a/modules/hubvisorAnalyticsAdapter.md b/modules/hubvisorAnalyticsAdapter.md new file mode 100644 index 00000000000..93d33e2f408 --- /dev/null +++ b/modules/hubvisorAnalyticsAdapter.md @@ -0,0 +1,11 @@ +# Overview + +``` +Module Name: Hubvisor Analytics Adapter +Module Type: Analytics Adapter +Maintainer: support@hubvisor.io +``` + +# Description + +Analytics adapter for Hubvisor. \ No newline at end of file diff --git a/modules/hubvisorAnalyticsAdapter.ts b/modules/hubvisorAnalyticsAdapter.ts new file mode 100644 index 00000000000..69b0643bdec --- /dev/null +++ b/modules/hubvisorAnalyticsAdapter.ts @@ -0,0 +1,15 @@ +import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; +import adapterManager from '../src/adapterManager.js'; + +const hubvisorAnalytics = adapter({ + global: 'hubvisorAnalytics', + handler: 'on', + analyticsType: 'bundle' +}); + +adapterManager.registerAnalyticsAdapter({ + adapter: hubvisorAnalytics, + code: 'hubvisor' +}); + +export default hubvisorAnalytics; diff --git a/test/spec/modules/hubvisorAnalyticsAdapter_spec.js b/test/spec/modules/hubvisorAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..3ca7ca856ef --- /dev/null +++ b/test/spec/modules/hubvisorAnalyticsAdapter_spec.js @@ -0,0 +1,18 @@ +import * as utils from 'src/utils.js'; +import hubvisorAnalytics from '../../../modules/hubvisorAnalyticsAdapter.js'; +import adapterManager from 'src/adapterManager'; +import { expectEvents } from '../../helpers/analytics.js'; + +describe('Hubvisor Analytics Adapter', () => { + it('Events should be bundled to hubvisor analytics', () => { + const hubvisorAnalyticsStub = utils.getWindowSelf().hubvisorAnalytics = sinon.stub(); + + adapterManager.enableAnalytics({ + provider: 'hubvisor' + }); + + expectEvents().to.beBundledTo(hubvisorAnalyticsStub); + + hubvisorAnalytics.disableAnalytics(); + }); +}); From 7d672e1be6ba974d68128bf022a123ce221e50b8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Jun 2026 15:38:31 -0400 Subject: [PATCH 029/124] Bump actions/github-script from 8 to 9 (#14980) Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/PR-assignment.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/PR-assignment.yml b/.github/workflows/PR-assignment.yml index 6c4c5d7f537..4748ba4c677 100644 --- a/.github/workflows/PR-assignment.yml +++ b/.github/workflows/PR-assignment.yml @@ -67,7 +67,7 @@ jobs: console.log('Assigned reviewers:', JSON.stringify(reviewers, null, 2)); - name: Auto-label core PR if: ${{ fromJSON(steps.get-props.outputs.result).isCoreChange }} - uses: actions/github-script@v8 + uses: actions/github-script@v9 with: github-token: ${{ steps.token.outputs.token }} script: | From 642893075bc0c68c4228d77ee01918d4708e06b4 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Tue, 2 Jun 2026 16:48:58 -0400 Subject: [PATCH 030/124] Aps Bid Adapter: map bidder metadata (#14977) --- modules/apsBidAdapter.js | 7 +++++++ test/spec/modules/apsBidAdapter_spec.js | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/modules/apsBidAdapter.js b/modules/apsBidAdapter.js index 918c32247f5..eda5f879d2b 100644 --- a/modules/apsBidAdapter.js +++ b/modules/apsBidAdapter.js @@ -199,6 +199,13 @@ export const converter = ortbConverter({ } const bidResponse = buildBidResponse(bid, context); + bidResponse.meta = bidResponse.meta || {}; + if (bid.ext?.bidder) { + bidResponse.meta.networkId = bid.ext.bidder; + } + if (context.seatbid?.seat) { + bidResponse.meta.seat = context.seatbid.seat; + } if (bidResponse.mediaType === VIDEO) { bidResponse.vastUrl = vastUrl; } diff --git a/test/spec/modules/apsBidAdapter_spec.js b/test/spec/modules/apsBidAdapter_spec.js index 8bf37db5be8..eaa28c1081d 100644 --- a/test/spec/modules/apsBidAdapter_spec.js +++ b/test/spec/modules/apsBidAdapter_spec.js @@ -465,8 +465,12 @@ describe('apsBidAdapter', () => { w: 300, h: 250, exp: 3600, + ext: { + bidder: '911', + }, }, ], + seat: '10432', }, ], }, @@ -494,6 +498,13 @@ describe('apsBidAdapter', () => { expect(result.length).to.equal(1); }); + it('should fill networkId and seat metadata from APS response fields', () => { + const result = spec.interpretResponse(response, request); + + expect(result[0].meta.networkId).to.equal('911'); + expect(result[0].meta.seat).to.equal('10432'); + }); + it('should include accountID in creative script', () => { updateAPSConfig({ accountID: accountID }); From 96284b4b9e94b09e28f4478425a75aab8a581153 Mon Sep 17 00:00:00 2001 From: mkomorski Date: Tue, 2 Jun 2026 22:53:04 +0200 Subject: [PATCH 031/124] Core: bidDesirabilityAdjustment (#14860) * adding bidderDesirabilityAdjusments to bidderSettings * adding bid desirability sort to bidLimit path * adding bid desirability to reducers * sharing bidRequest between cpm and desirability adjustments * sortByDealAndPriceBucketOrDesirability * fixing multibid & removing bidRequest fallback --------- Co-authored-by: Patrick McCann --- libraries/ortbConverter/processors/default.js | 1 + modules/multibid/index.ts | 5 +- src/auction.ts | 8 +- src/bidderSettings.ts | 7 +- src/bidfactory.ts | 2 + src/targeting.ts | 27 +-- src/utils/cpm.js | 17 +- src/utils/desirability.ts | 47 +++++ src/utils/reducers.js | 8 + test/spec/unit/core/targeting_spec.js | 12 +- test/spec/unit/utils/desirability_spec.js | 166 ++++++++++++++++++ test/spec/unit/utils/reducers_spec.js | 56 ++++++ 12 files changed, 330 insertions(+), 26 deletions(-) create mode 100644 src/utils/desirability.ts create mode 100644 test/spec/unit/utils/desirability_spec.js diff --git a/libraries/ortbConverter/processors/default.js b/libraries/ortbConverter/processors/default.js index 3b6b1156063..8b07fe1d333 100644 --- a/libraries/ortbConverter/processors/default.js +++ b/libraries/ortbConverter/processors/default.js @@ -88,6 +88,7 @@ export const DEFAULT_PROCESSORS = { burl: bid.burl, ttl: bid.exp || context.ttl, netRevenue: context.netRevenue, + duration: bid.dur, }).filter(([k, v]) => typeof v !== 'undefined') .forEach(([k, v]) => { bidResponse[k] = v; diff --git a/modules/multibid/index.ts b/modules/multibid/index.ts index 5776bac32d4..02492704a3b 100644 --- a/modules/multibid/index.ts +++ b/modules/multibid/index.ts @@ -11,10 +11,11 @@ import { import * as events from '../../src/events.js'; import { EVENTS } from '../../src/constants.js'; import { addBidderRequests } from '../../src/auction.js'; -import { getHighestCpmBidsFromBidPool, sortByDealAndPriceBucketOrCpm } from '../../src/targeting.js'; +import { getHighestCpmBidsFromBidPool, sortByDealAndPriceBucketOrDesirability } from '../../src/targeting.js'; import { PBS, registerOrtbProcessor, REQUEST } from '../../src/pbjsORTB.js'; import { timedBidResponseHook } from '../../src/utils/perfMetrics.js'; import type { BidderCode } from "../../src/types/common.d.ts"; +import { sortByHighestDesirability } from '../../src/utils/desirability.ts'; const MODULE_NAME = 'multibid'; let hasMultibid = false; @@ -238,7 +239,7 @@ export function targetBidPoolHook(fn, bidsReceived, highestCpmCallback, adUnitBi Object.keys(bidsByBidderCode).forEach(key => bucketBids.push(bidsByBidderCode[key].reduce(highestCpmCallback))); // if adUnitBidLimit is set, pass top N number bids if (adUnitBidLimit > 0) { - bucketBids = dealPrioritization ? bucketBids.sort(sortByDealAndPriceBucketOrCpm(true)) : bucketBids.sort((a, b) => b.cpm - a.cpm); + bucketBids = dealPrioritization ? bucketBids.sort(sortByDealAndPriceBucketOrDesirability(true)) : bucketBids.sort(sortByHighestDesirability); bucketBids.sort(sortByMultibid); modifiedBids.push(...bucketBids.slice(0, adUnitBidLimit)); } else { diff --git a/src/auction.ts b/src/auction.ts index 1b53fa42601..324ce9e35c1 100644 --- a/src/auction.ts +++ b/src/auction.ts @@ -39,6 +39,7 @@ import { isActivityAllowed } from './activities/rules.js'; import { ACTIVITY_ADD_BID_RESPONSE } from './activities/activities.js'; import { MODULE_TYPE_BIDDER } from './activities/modules.ts'; import { wrapInBids } from "./utils/wrapsInBids.ts"; +import { adjustDesirability } from './utils/desirability.ts'; const { syncUsers } = userSync; @@ -1127,11 +1128,16 @@ function setKeys(keyValues, bidderSettings, custBidObj, bidReq) { } export function adjustBids(bid) { - const bidPriceAdjusted = adjustCpm(bid.cpm, bid); + const bidRequest = auctionManager.index.getBidRequest(bid); + const bidPriceAdjusted = adjustCpm(bid.cpm, bid, bidRequest); if (bidPriceAdjusted >= 0) { bid.cpm = bidPriceAdjusted; } + + // defaults to cpm + const bidDesirabilityAdjusted = adjustDesirability(bid, bidRequest); + bid.desirability = bidDesirabilityAdjusted; } /** diff --git a/src/bidderSettings.ts b/src/bidderSettings.ts index c9d68cdddf7..23979a7d34a 100644 --- a/src/bidderSettings.ts +++ b/src/bidderSettings.ts @@ -50,6 +50,11 @@ export interface BidderScopedSettings extends BidderSettin * Custom CPM adjustment function. Could, for example, adjust a bidder’s gross-price bid to net price. */ bidCpmAdjustment?: (cpm: number, bid: Bid, bidRequest: BidRequest) => number; + /** + * Optional score used when sorting bids for targeting / winners. + * Should return a comparable number; higher is preferred. Defaults to `cpm`. + */ + bidDesirabilityAdjustment?: (cpm: number, bid: Bid, bidRequest: BidRequest) => number; /** * Define which key/value pairs are sent to the ad server. */ @@ -71,7 +76,7 @@ export class ScopedSettings, SCOPED extends * Get setting value at `path` under the given scope, falling back to the default scope if needed. * If `scope` is `null`, get the setting's default value. */ - get

(scope, path: P): SETTINGS[P] { + get

(scope, path: P): SCOPED[P] { let value = this.getOwn(scope, path); if (typeof value === 'undefined') { value = this.getOwn(null, path); diff --git a/src/bidfactory.ts b/src/bidfactory.ts index c8e3a7b6b6c..f19552a1314 100644 --- a/src/bidfactory.ts +++ b/src/bidfactory.ts @@ -100,6 +100,8 @@ export interface BaseBidResponse { * Billing tracker URL. */ burl?: string; + + desirability: number; } // BidResponesProperties - adapter interpretResponse properties specific to the format. diff --git a/src/targeting.ts b/src/targeting.ts index 83b2b421091..4e04d0bfbe3 100644 --- a/src/targeting.ts +++ b/src/targeting.ts @@ -16,15 +16,15 @@ import { logInfo, logMessage, logWarn, - sortByHighestCpm, uniques, } from './utils.js'; -import { getHighestCpm, getOldestHighestCpmBid } from './utils/reducers.js'; +import { getHighestCpm, getHighestDesirability, getOldestHighestCpmBid } from './utils/reducers.js'; import type { Bid } from './bidfactory.ts'; import type { AdUnitCode, ByAdUnit, Identifier } from './types/common.d.ts'; import type { DefaultTargeting } from './auction.ts'; import { lock } from "./targeting/lock.ts"; import { isBidUsable } from './targeting/filters.ts'; +import { sortByHighestDesirability } from './utils/desirability.ts' import { updateSlotTargetingFromMap } from "./utils/gptTargeting.ts"; var pbTargetingKeys = []; @@ -42,7 +42,7 @@ export const TARGETING_KEYS_ARR = Object.keys(TARGETING_KEYS).map( // If two bids are found for same adUnitCode, we will use the highest one to take part in auction // This can happen in case of concurrent auctions // If adUnitBidLimit is set above 0 return top N number of bids -export const getHighestCpmBidsFromBidPool = hook('sync', function(bidsReceived, winReducer, adUnitBidLimit = 0, hasModified = false, winSorter = sortByHighestCpm) { +export const getHighestCpmBidsFromBidPool = hook('sync', function(bidsReceived, winReducer, adUnitBidLimit = 0, hasModified = false, winSorter = sortByHighestDesirability) { if (!hasModified) { const bids = []; const dealPrioritization = config.getConfig('sendBidsControl.dealPrioritization'); @@ -56,7 +56,7 @@ export const getHighestCpmBidsFromBidPool = hook('sync', function(bidsReceived, // if adUnitBidLimit is set, pass top N number bids const bidLimit = typeof adUnitBidLimit === 'object' ? adUnitBidLimit[bucketKey] : adUnitBidLimit; if (bidLimit) { - bucketBids = dealPrioritization ? bucketBids.sort(sortByDealAndPriceBucketOrCpm(true)) : bucketBids.sort((a, b) => b.cpm - a.cpm); + bucketBids = dealPrioritization ? bucketBids.sort(sortByDealAndPriceBucketOrDesirability(true)) : bucketBids.sort(winSorter); bids.push(...bucketBids.slice(0, bidLimit)); } else { bucketBids = bucketBids.sort(winSorter) @@ -91,7 +91,7 @@ export const getHighestCpmBidsFromBidPool = hook('sync', function(bidsReceived, * "hb_pb": "2" * }] */ -export function sortByDealAndPriceBucketOrCpm(useCpm = false) { +export function sortByDealAndPriceBucketOrDesirability(useDesirability = false) { return function(a, b) { if (a.adserverTargeting.hb_deal !== undefined && b.adserverTargeting.hb_deal === undefined) { return -1; @@ -102,7 +102,10 @@ export function sortByDealAndPriceBucketOrCpm(useCpm = false) { } // assuming both values either have a deal or don't have a deal - sort by the hb_pb param - if (useCpm) { + if (useDesirability) { + if (b.desirability && a.desirability) { + return b.desirability - a.desirability; + } return b.cpm - a.cpm; } @@ -242,11 +245,11 @@ export function newTargeting(auctionManager) { * @param adUnitCode * @param bidLimit * @param bidsReceived - The received bids, defaulting to the result of getBidsReceived(). - * @param [winReducer = getHighestCpm] - reducer method - * @param [winSorter = sortByHighestCpm] - sorter method + * @param [winReducer = getHighestDesirability] - reducer method + * @param [winSorter = sortByHighestDesirability] - sorter method * @return targeting */ - getAllTargeting(adUnitCode?: AdUnitCode | AdUnitCode[], bidLimit?: number, bidsReceived?: Bid[], winReducer = getHighestCpm, winSorter = sortByHighestCpm): ByAdUnit { + getAllTargeting(adUnitCode?: AdUnitCode | AdUnitCode[], bidLimit?: number, bidsReceived?: Bid[], winReducer = getHighestDesirability, winSorter = sortByHighestDesirability): ByAdUnit { bidsReceived ||= getBidsReceived(winReducer, winSorter); const adUnitCodes = getAdUnitCodes(adUnitCode); const adUnitBidLimit = getAdUnitBidLimitMap(adUnitCodes, bidLimit); @@ -346,10 +349,10 @@ export function newTargeting(auctionManager) { * @param adUnitCode adUnitCode or array of adUnitCodes * @param bids - The received bids, defaulting to the result of getBidsReceived(). * @param [winReducer = getHighestCpm] - reducer method - * @param [winSorter = sortByHighestCpm] - sorter method + * @param [winSorter = sortByHighestDesirability] - sorter method * @return An array of winning bids. */ - getWinningBids(adUnitCode: AdUnitCode | AdUnitCode[], bids?: Bid[], winReducer = getHighestCpm, winSorter = sortByHighestCpm): Bid[] { + getWinningBids(adUnitCode: AdUnitCode | AdUnitCode[], bids?: Bid[], winReducer = getHighestCpm, winSorter = sortByHighestDesirability): Bid[] { const bidsReceived = bids || getBidsReceived(winReducer, winSorter); const adUnitCodes = getAdUnitCodes(adUnitCode); @@ -580,7 +583,7 @@ export function newTargeting(auctionManager) { adUnitCode, adserverTargeting: targetingCopy[adUnitCode] }; - }).sort(sortByDealAndPriceBucketOrCpm()); + }).sort(sortByDealAndPriceBucketOrDesirability()); // iterate through the targeting based on above list and transform the keys into the query-equivalent and count characters return targetingMap.reduce(function (accMap, currMap, index, arr) { diff --git a/src/utils/cpm.js b/src/utils/cpm.js index f0206486186..a52cdc45a97 100644 --- a/src/utils/cpm.js +++ b/src/utils/cpm.js @@ -2,12 +2,21 @@ import { auctionManager } from '../auctionManager.js'; import { bidderSettings } from '../bidderSettings.js'; import { logError } from '../utils.js'; +/** + * Resolve a bidder-scoped hook (`bidCpmAdjustment`, `bidDesirabilityAdjustment`, …) using the same + * precedence as publisher settings: `getOwn(bidderCode)` wins, otherwise adapter vs bidder depending on + * `adjustAlternateBids` on the adapter scope. + */ +export function getBidAdjustmentFn(bid, bs, key, bidRequest) { + const adapterCode = bid?.adapterCode; + const bidderCode = bid?.bidderCode || bidRequest?.bidder; + const adjustAlternateBids = bs.get(bid?.adapterCode, 'adjustAlternateBids'); + return bs.getOwn(bidderCode, key) || bs.get(adjustAlternateBids ? adapterCode : bidderCode, key); +} + export function adjustCpm(cpm, bidResponse, bidRequest, { index = auctionManager.index, bs = bidderSettings } = {}) { bidRequest = bidRequest || index.getBidRequest(bidResponse); - const adapterCode = bidResponse?.adapterCode; - const bidderCode = bidResponse?.bidderCode || bidRequest?.bidder; - const adjustAlternateBids = bs.get(bidResponse?.adapterCode, 'adjustAlternateBids'); - const bidCpmAdjustment = bs.getOwn(bidderCode, 'bidCpmAdjustment') || bs.get(adjustAlternateBids ? adapterCode : bidderCode, 'bidCpmAdjustment'); + const bidCpmAdjustment = getBidAdjustmentFn(bidResponse, bs, 'bidCpmAdjustment', bidRequest); if (bidCpmAdjustment && typeof bidCpmAdjustment === 'function') { try { return bidCpmAdjustment(cpm, Object.assign({}, bidResponse), bidRequest); diff --git a/src/utils/desirability.ts b/src/utils/desirability.ts new file mode 100644 index 00000000000..adfb06225a5 --- /dev/null +++ b/src/utils/desirability.ts @@ -0,0 +1,47 @@ +import type { BidRequest } from '../adapterManager.ts'; +import { bidderSettings } from '../bidderSettings.js'; +import type { Bid } from '../bidfactory.ts'; +import type { BidderCode } from '../types/common'; +import { logError } from '../utils.js'; +import { getBidAdjustmentFn } from './cpm.js'; + +export type SortByHighestDesirabilityDeps = { + bs?: typeof bidderSettings; +}; + +type BidAdjustmentFn = ( + cpm: number, + bid: Bid, + bidRequest: BidRequest | undefined | null +) => number; + +export function adjustDesirability( + bid: Bid, + bidRequest: BidRequest | undefined | null, + deps: SortByHighestDesirabilityDeps = {}, +): number { + const bs = deps.bs ?? bidderSettings; + const bidCopy = Object.assign({}, bid) as Bid; + + const adjustedCpm = bid.cpm; + + const bidDesirabilityAdjustment = getBidAdjustmentFn(bid, bs, 'bidDesirabilityAdjustment', bidRequest) as BidAdjustmentFn | undefined; + if (typeof bidDesirabilityAdjustment !== 'function') { + return adjustedCpm; + } + + try { + return bidDesirabilityAdjustment(adjustedCpm, bidCopy, bidRequest); + } catch (e) { + logError('Error during bid desirability adjustment', e); + return adjustedCpm; + } +} + +/** Compare bids that already carry `.desirability` (e.g. after `adjustBids` in the auction). Higher wins. */ +export function sortByHighestDesirability(a: Bid, b: Bid): number { + if (b.desirability && a.desirability) { + return b.desirability - a.desirability; + } + return b.cpm - a.cpm; +} diff --git a/src/utils/reducers.js b/src/utils/reducers.js index 0814ac0ec49..bb585638611 100644 --- a/src/utils/reducers.js +++ b/src/utils/reducers.js @@ -35,6 +35,14 @@ const timestampCompare = keyCompare((bid) => bid.responseTimestamp); // This function will get highest cpm value bid, in case of tie it will return the bid with lowest timeToRespond export const getHighestCpm = maximum(tiebreakCompare(cpmCompare, reverseCompare(keyCompare((bid) => bid.timeToRespond)))) +const bidDesirabilityCompare = keyCompare((bid) => bid.desirability); + +// This function will get highest bid by `.desirability` (publisher `bidDesirabilityAdjustment` when set, else mirrors cpm via `adjustBids`); +// ties use lowest `timeToRespond`, matching {@link getHighestCpm}. +export const getHighestDesirability = maximum( + tiebreakCompare(bidDesirabilityCompare, reverseCompare(keyCompare((bid) => bid.timeToRespond))) +); + // This function will get the oldest highest cpm value bid, in case of tie it will return the bid which came in first // Use case for tie: https://github.com/prebid/Prebid.js/issues/2448 export const getOldestHighestCpmBid = maximum(tiebreakCompare(cpmCompare, reverseCompare(timestampCompare))) diff --git a/test/spec/unit/core/targeting_spec.js b/test/spec/unit/core/targeting_spec.js index fc636d73599..0420385833c 100644 --- a/test/spec/unit/core/targeting_spec.js +++ b/test/spec/unit/core/targeting_spec.js @@ -2,7 +2,7 @@ import { expect } from 'chai'; import { getGPTSlotsForAdUnits, getHighestCpmBidsFromBidPool, - sortByDealAndPriceBucketOrCpm, + sortByDealAndPriceBucketOrDesirability, targeting as targetingInstance , getAdUnitBidLimitMap } from 'src/targeting.js'; @@ -1481,7 +1481,7 @@ describe('targeting tests', function () { }); }); - describe('sortByDealAndPriceBucketOrCpm', function() { + describe('sortByDealAndPriceBucketOrDesirability', function() { it('will properly sort bids when some bids have deals and some do not', function () { const bids = [{ adserverTargeting: { @@ -1517,7 +1517,7 @@ describe('targeting tests', function () { hb_pb: '100.00', } }]; - bids.sort(sortByDealAndPriceBucketOrCpm()); + bids.sort(sortByDealAndPriceBucketOrDesirability()); expect(bids[0].adserverTargeting.hb_adid).to.equal('ghi'); expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); expect(bids[2].adserverTargeting.hb_adid).to.equal('abc'); @@ -1552,7 +1552,7 @@ describe('targeting tests', function () { hb_deal: '9864' } }]; - bids.sort(sortByDealAndPriceBucketOrCpm()); + bids.sort(sortByDealAndPriceBucketOrDesirability()); expect(bids[0].adserverTargeting.hb_adid).to.equal('ghi'); expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); expect(bids[2].adserverTargeting.hb_adid).to.equal('abc'); @@ -1591,7 +1591,7 @@ describe('targeting tests', function () { hb_pb: '100.00' } }]; - bids.sort(sortByDealAndPriceBucketOrCpm()); + bids.sort(sortByDealAndPriceBucketOrDesirability()); expect(bids[0].adserverTargeting.hb_adid).to.equal('pqr'); expect(bids[1].adserverTargeting.hb_adid).to.equal('jkl'); expect(bids[2].adserverTargeting.hb_adid).to.equal('ghi'); @@ -1642,7 +1642,7 @@ describe('targeting tests', function () { hb_pb: '100.00', } }]; - bids.sort(sortByDealAndPriceBucketOrCpm(true)); + bids.sort(sortByDealAndPriceBucketOrDesirability(true)); expect(bids[0].adserverTargeting.hb_adid).to.equal('jkl'); expect(bids[1].adserverTargeting.hb_adid).to.equal('abc'); expect(bids[2].adserverTargeting.hb_adid).to.equal('ghi'); diff --git a/test/spec/unit/utils/desirability_spec.js b/test/spec/unit/utils/desirability_spec.js new file mode 100644 index 00000000000..2600fe2e92b --- /dev/null +++ b/test/spec/unit/utils/desirability_spec.js @@ -0,0 +1,166 @@ +import { expect } from 'chai'; +import { auctionManager } from 'src/auctionManager.js'; +import * as utils from 'src/utils.js'; +import { adjustDesirability, sortByHighestDesirability } from '../../../../src/utils/desirability.js'; + +describe('desirability utils', function () { + let sandbox; + + const testDeps = function (bs) { + return { index: auctionManager.index, bs }; + }; + + const bidderSettingsNoAdjustment = { + get() { + return undefined; + }, + getOwn() { + return undefined; + } + }; + + /** + * Each bidder registers its own `bidDesirabilityAdjustment` via getOwn. + */ + const bidderSettingsPerBidderAdjustment = { + get() { + return undefined; + }, + getOwn(bidder, path) { + if (path !== 'bidDesirabilityAdjustment') return undefined; + if (bidder === 'bidder-a') { + return (cpm, bid) => 100 * (bid.duration || 0) + cpm; + } + if (bidder === 'bidder-b') { + return (cpm, bid) => cpm - 5 * (bid.duration || 0); + } + if (bidder === 'bidder-c') { + return (cpm, bid) => cpm + (bid.duration || 0); + } + return undefined; + } + }; + + const bidderSettingsMixedAdjustment = { + get() { + return undefined; + }, + getOwn(bidder, path) { + if (path !== 'bidDesirabilityAdjustment') return undefined; + if (bidder === 'bad-adjust') return (cpm, b) => b.will.throw.on.purpose.for.test; + if (bidder === 'ok-adjust') return (cpm) => cpm * 2; + return undefined; + } + }; + + /** Mirrors auction `adjustBids`: desirability from `adjustDesirability` on current bid `.cpm`. */ + function hydrateBidScores(bid, bs) { + const desirability = adjustDesirability(bid, null, testDeps(bs)); + return Object.assign({}, bid, { desirability }); + } + + beforeEach(function () { + sandbox = sinon.createSandbox(); + sandbox.stub(auctionManager.index, 'getBidRequest').returns(null); + }); + + afterEach(function () { + sandbox.restore(); + }); + + describe('adjustDesirability', function () { + it('returns raw cpm when no desirability hook applies', function () { + const bid = { cpm: 4.25, bidderCode: 'nobody', bidder: 'nobody' }; + expect(adjustDesirability(bid, null, testDeps(bidderSettingsNoAdjustment))).to.equal(4.25); + }); + + it('falls back to raw cpm when bidDesirabilityAdjustment throws', function () { + const logStub = sinon.stub(utils, 'logError'); + const badBid = { + cpm: 11, + bidderCode: 'bad-adjust', + bidder: 'bad-adjust' + }; + expect( + adjustDesirability(badBid, null, testDeps(bidderSettingsMixedAdjustment)) + ).to.equal(11); + sinon.assert.calledWithMatch(logStub, 'Error during bid desirability adjustment'); + logStub.restore(); + }); + + it('runs bidDesirabilityAdjustment on bid.cpm after CPM was adjusted elsewhere', function () { + const bs = { + get() { + return undefined; + }, + getOwn(bidder, path) { + if (bidder !== 'combo') return undefined; + if (path === 'bidDesirabilityAdjustment') { + return (cpm) => cpm + 7; + } + return undefined; + } + }; + const bid = { cpm: 20, bidderCode: 'combo', bidder: 'combo' }; + expect(adjustDesirability(bid, null, testDeps(bs))).to.equal(27); + }); + }); + + describe('sortByHighestDesirability', function () { + it('orders by hydrated .desirability when bidDesirabilityAdjustment throws on one bidder', function () { + const logStub = sinon.stub(utils, 'logError'); + const okBid = { + cpm: 90, + bidderCode: 'ok-adjust', + bidder: 'ok-adjust' + }; + const badBid = { + cpm: 11, + bidderCode: 'bad-adjust', + bidder: 'bad-adjust' + }; + + expect( + [okBid, badBid].map((b) => + hydrateBidScores(b, bidderSettingsMixedAdjustment) + ).sort(sortByHighestDesirability).map((b) => b.bidderCode) + ).to.eql(['ok-adjust', 'bad-adjust']); + sinon.assert.called(logStub); + logStub.restore(); + }); + + it('orders by hydrated desirability equal to raw cpm when no bidDesirabilityAdjustment', function () { + const bids = [ + { cpm: 1, bidderCode: 'bidder-a', bidder: 'bidder-a' }, + { cpm: 5, bidderCode: 'bidder-b', bidder: 'bidder-b' }, + { cpm: 3, bidderCode: 'bidder-c', bidder: 'bidder-c' }, + ].map((b) => hydrateBidScores(b, bidderSettingsNoAdjustment)); + const sorted = bids.slice().sort(sortByHighestDesirability); + expect(sorted.map((x) => x.cpm)).to.eql([5, 3, 1]); + }); + + it('uses bidder-specific bidDesirabilityAdjustment after hydration', function () { + // Rankings: a 210, c 48, b 35 + const bids = [ + { cpm: 50, duration: 3, bidderCode: 'bidder-b', bidder: 'bidder-b' }, + { cpm: 40, duration: 8, bidderCode: 'bidder-c', bidder: 'bidder-c' }, + { cpm: 10, duration: 2, bidderCode: 'bidder-a', bidder: 'bidder-a' }, + ].map((b) => hydrateBidScores(b, bidderSettingsPerBidderAdjustment)); + const sorted = bids.slice().sort(sortByHighestDesirability); + expect(sorted.map((b) => b.bidderCode)).to.eql([ + 'bidder-a', + 'bidder-c', + 'bidder-b', + ]); + }); + + it('compares `.desirability` only — raw cpm ties need explicit scores', function () { + expect( + sortByHighestDesirability( + { cpm: 5, desirability: 1 }, + { cpm: 5, desirability: 2 }, + ), + ).to.equal(1); + }); + }); +}); diff --git a/test/spec/unit/utils/reducers_spec.js b/test/spec/unit/utils/reducers_spec.js index d5723f25955..93dbd2e63fb 100644 --- a/test/spec/unit/utils/reducers_spec.js +++ b/test/spec/unit/utils/reducers_spec.js @@ -5,8 +5,10 @@ import { minimum, maximum, getHighestCpm, + getHighestDesirability, getOldestHighestCpmBid, getLatestHighestCpmBid, reverseCompare } from '../../../../src/utils/reducers.js'; + import assert from 'assert'; describe('reducers', () => { @@ -93,6 +95,60 @@ describe('reducers', () => { }); }); + describe('getHighestDesirability', function () { + it('matches getHighestCpm when `.desirability` mirrors cpm ranking', function () { + const hi = { + cpm: 2, + desirability: 2, + timeToRespond: 100, + bidderCode: 'x' + }; + const lo = { + cpm: 1, + desirability: 1, + timeToRespond: 100, + bidderCode: 'y' + }; + expect(getHighestDesirability(hi, lo)).to.eql(hi); + expect(getHighestDesirability(lo, hi)).to.eql(hi); + + const slow = { + cpm: 1, + desirability: 1, + timeToRespond: 100, + bidderCode: 'x' + }; + const fast = { + cpm: 1, + desirability: 1, + timeToRespond: 50, + bidderCode: 'y' + }; + expect(getHighestDesirability(slow, fast)).to.eql(fast); + expect(getHighestDesirability(fast, slow)).to.eql(fast); + }); + + it('prefers higher `.desirability` over raw cpm tie-break ranking', function () { + const boosted = { + cpm: 2, + bonus: 20, + desirability: 22, + timeToRespond: 100, + bidderCode: 'boosted', + bidder: 'boosted' + }; + const plain = { + cpm: 10, + desirability: 10, + timeToRespond: 100, + bidderCode: 'plain', + bidder: 'plain' + }; + expect(getHighestDesirability(boosted, plain)).to.eql(boosted); + expect(getHighestDesirability(plain, boosted)).to.eql(boosted); + }); + }); + describe('getOldestHighestCpmBid', () => { it('should pick the oldest in case of tie using responseTimeStamp', function () { const a = { From 6733412d8146c729252dc0d0fc4d2646980a5745 Mon Sep 17 00:00:00 2001 From: tososhi Date: Wed, 3 Jun 2026 19:53:00 +0900 Subject: [PATCH 032/124] fluct Bid Adapter: add remaining missing bid request signals (#14958) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add instl support * falseの場合も明示的に送信するようにした * fluct Bid Adapter: allow wrapper to inject its name via x-fluct-prebid-wrapper header Read `fluct.wrapperName` from Prebid config and, when set, attach it as the `x-fluct-prebid-wrapper` HTTP header on every bid request so the fluct bidder can identify which wrapper the request originates from. Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: move customHeaders construction outside _each loop Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: add remaining missing bid request signals Forward all outstanding signals from Prebid.js to the fluct server: Regulation/privacy: - regs.ext.dsa (Digital Services Act) — EU DSPs skip bids without it - regs.ext.gpc (Global Privacy Control) User attributes: - user.yob, user.gender, user.keywords — demographic/interest targeting - user.ext.data (all fields, not just im_segments) Site metadata: - site.name, site.search, site.publisher.domain Auction context: - refererInfo.canonicalUrl — more reliable than raw page URL - refererInfo.isAmp, reachedTop, numIframes — page environment signals - timeout — lets fluct server optimize response time - source.tid — auction-level transaction ID Floor model metadata: - floorData.modelVersion, location, floorProvider Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: fix guard inconsistencies found in code review - yob: use != null guard (consistent with gender) - numIframes: use != null guard so top-level pages (numIframes=0) are forwarded - site.publisher: gate on publisher object existence instead of domain, and forward id in addition to domain Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: remove floorData metadata fields Floor model metadata (modelVersion, location, floorProvider) has unclear server-side use. Removing to keep the PR focused; floor price itself (bidfloor/bidfloorcur) is already forwarded by existing code. Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: fix duplicate instl assignment after rebase Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: remove extra blank line (lint fix) Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: fix padded-blocks lint error in spec Co-Authored-By: Claude Sonnet 4.6 * fluct Bid Adapter: remove CORS preflight by switching to text/plain Replace custom request headers with body fields to eliminate the ~400ms OPTIONS preflight on every bid request: - Remove Content-Type: application/json and custom headers (x-fluct-app, x-fluct-version, x-openrtb-version, x-fluct-prebid-wrapper) - Move adapter metadata to request body: - adapterVersion (was x-fluct-version) - wrapperName (was x-fluct-prebid-wrapper, set only when configured) - Default content type becomes text/plain (Prebid ajax default), which is a CORS simple request and requires no preflight Co-Authored-By: Claude Sonnet 4.6 * Revert "fluct Bid Adapter: remove CORS preflight by switching to text/plain" This reverts commit 5c129058b1dfab4ab9fcb69aa376b474f96420df. --------- Co-authored-by: yosei-ito Co-authored-by: Claude Sonnet 4.6 --- modules/fluctBidAdapter.js | 30 ++++- test/spec/modules/fluctBidAdapter_spec.js | 155 ++++++++++++++++++++++ 2 files changed, 182 insertions(+), 3 deletions(-) diff --git a/modules/fluctBidAdapter.js b/modules/fluctBidAdapter.js index 77f8d43b311..5e370b6da02 100644 --- a/modules/fluctBidAdapter.js +++ b/modules/fluctBidAdapter.js @@ -10,7 +10,7 @@ import { registerBidder } from '../src/adapters/bidderFactory.js'; const BIDDER_CODE = 'fluct'; const END_POINT = 'https://hb.adingo.jp/prebid/'; -const VERSION = '1.6'; +const VERSION = '1.7'; const NET_REVENUE = true; const TTL = 300; const DEFAULT_CURRENCY = 'JPY'; @@ -131,6 +131,7 @@ export const spec = { const ortb2Site = bidderRequest.ortb2?.site; if (ortb2Site) { data.site = {}; + if (ortb2Site.name) data.site.name = ortb2Site.name; if (ortb2Site.cat) data.site.cat = ortb2Site.cat; if (ortb2Site.sectioncat) data.site.sectioncat = ortb2Site.sectioncat; if (ortb2Site.pagecat) data.site.pagecat = ortb2Site.pagecat; @@ -138,18 +139,29 @@ export const spec = { if (ortb2Site.content) data.site.content = ortb2Site.content; if (ortb2Site.domain) data.site.domain = ortb2Site.domain; if (ortb2Site.ref) data.site.ref = ortb2Site.ref; + if (ortb2Site.search) data.site.search = ortb2Site.search; + if (ortb2Site.publisher) { + data.site.publisher = {}; + if (ortb2Site.publisher.id) data.site.publisher.id = ortb2Site.publisher.id; + if (ortb2Site.publisher.domain) data.site.publisher.domain = ortb2Site.publisher.domain; + } if (ortb2Site.ext?.data) data.site.ext = { data: ortb2Site.ext.data }; } data.adUnitCode = request.adUnitCode; data.bidId = request.bidId; + const ortb2User = bidderRequest.ortb2?.user; data.user = { - data: bidderRequest.ortb2?.user?.data ?? [], + data: ortb2User?.data ?? [], eids: [ ...(request.userIdAsEids ?? []), - ...(bidderRequest.ortb2?.user?.ext?.eids ?? []), + ...(ortb2User?.ext?.eids ?? []), ], }; + if (ortb2User?.yob != null) data.user.yob = ortb2User.yob; + if (ortb2User?.gender != null) data.user.gender = ortb2User.gender; + if (ortb2User?.keywords) data.user.keywords = ortb2User.keywords; + if (ortb2User?.ext?.data) data.user.ext = { data: ortb2User.ext.data }; if (impExt) { data.transactionId = impExt.tid; @@ -183,6 +195,18 @@ export const spec = { sid: bidderRequest.ortb2.regs.gpp_sid }); } + if (bidderRequest.ortb2?.regs?.ext?.dsa) { + deepSetValue(data, 'regs.ext.dsa', bidderRequest.ortb2.regs.ext.dsa); + } + if (bidderRequest.ortb2?.regs?.ext?.gpc != null) { + deepSetValue(data, 'regs.ext.gpc', bidderRequest.ortb2.regs.ext.gpc); + } + if (bidderRequest.refererInfo?.canonicalUrl) data.canonicalUrl = bidderRequest.refererInfo.canonicalUrl; + if (bidderRequest.refererInfo?.isAmp) data.isAmp = true; + if (bidderRequest.refererInfo?.reachedTop != null) data.reachedTop = bidderRequest.refererInfo.reachedTop; + if (bidderRequest.refererInfo?.numIframes != null) data.numIframes = bidderRequest.refererInfo.numIframes; + if (bidderRequest.timeout != null) data.timeout = bidderRequest.timeout; + if (bidderRequest.ortb2?.source?.tid) deepSetValue(data, 'source.tid', bidderRequest.ortb2.source.tid); if (bidderRequest.ortb2?.user?.ext?.data?.im_segments) { deepSetValue(data, 'params.kv.imsids', bidderRequest.ortb2.user.ext.data.im_segments); } diff --git a/test/spec/modules/fluctBidAdapter_spec.js b/test/spec/modules/fluctBidAdapter_spec.js index 312c58e9690..685f70faca5 100644 --- a/test/spec/modules/fluctBidAdapter_spec.js +++ b/test/spec/modules/fluctBidAdapter_spec.js @@ -451,6 +451,27 @@ describe('fluctAdapter', function () { expect(request.data.regs.gpp.sid).to.eql([1, 2, 3]); }); + it('includes data.regs.ext.dsa if bidderRequest.ortb2.regs.ext.dsa exists', function () { + const dsa = { + dsarequired: 1, + pubrender: 0, + datatopub: 2, + transparency: [{ domain: 'example.com', dsaparams: [1, 2] }], + }; + const request = spec.buildRequests( + bidRequests, + Object.assign({}, bidderRequest, { + ortb2: { regs: { ext: { dsa } } }, + }), + )[0]; + expect(request.data.regs.ext.dsa).to.eql(dsa); + }); + + it('does not include data.regs.ext.dsa when absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.regs?.ext?.dsa).to.eql(undefined); + }); + it('includes no data.site by default', function () { const request = spec.buildRequests(bidRequests, bidderRequest)[0]; expect(request.data.site).to.eql(undefined); @@ -796,6 +817,140 @@ describe('fluctAdapter', function () { expect(request.data.bidfloor).to.eql(undefined); expect(request.data.bidfloorcur).to.eql(undefined); }); + + it('includes data.regs.ext.gpc from ortb2.regs.ext.gpc', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { regs: { ext: { gpc: '1' } } }, + }))[0]; + expect(request.data.regs.ext.gpc).to.eql('1'); + }); + + it('does not include data.regs.ext.gpc when absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.regs?.ext?.gpc).to.eql(undefined); + }); + + it('includes data.canonicalUrl from refererInfo.canonicalUrl', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', canonicalUrl: 'https://example.com/canonical' }, + }))[0]; + expect(request.data.canonicalUrl).to.eql('https://example.com/canonical'); + }); + + it('does not include data.canonicalUrl when absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.canonicalUrl).to.eql(undefined); + }); + + it('includes data.isAmp when refererInfo.isAmp is true', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', isAmp: true }, + }))[0]; + expect(request.data.isAmp).to.eql(true); + }); + + it('does not include data.isAmp when refererInfo.isAmp is false', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', isAmp: false }, + }))[0]; + expect(request.data.isAmp).to.eql(undefined); + }); + + it('includes data.reachedTop from refererInfo.reachedTop', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', reachedTop: false }, + }))[0]; + expect(request.data.reachedTop).to.eql(false); + }); + + it('includes data.numIframes from refererInfo.numIframes', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', numIframes: 2 }, + }))[0]; + expect(request.data.numIframes).to.eql(2); + }); + + it('includes data.numIframes = 0 when page is at top level', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + refererInfo: { page: 'http://example.com', numIframes: 0 }, + }))[0]; + expect(request.data.numIframes).to.eql(0); + }); + + it('includes data.timeout from bidderRequest.timeout', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + timeout: 3000, + }))[0]; + expect(request.data.timeout).to.eql(3000); + }); + + it('does not include data.timeout when absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.timeout).to.eql(undefined); + }); + + it('includes data.source.tid from ortb2.source.tid', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { source: { tid: 'auction-tid-123' } }, + }))[0]; + expect(request.data.source.tid).to.eql('auction-tid-123'); + }); + + it('does not include data.source.tid when absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.source?.tid).to.eql(undefined); + }); + + it('includes data.site.name and data.site.search and data.site.publisher.domain', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { + site: { + name: 'My Site', + search: 'prebid', + publisher: { domain: 'publisher.example.com' }, + }, + }, + }))[0]; + expect(request.data.site.name).to.eql('My Site'); + expect(request.data.site.search).to.eql('prebid'); + expect(request.data.site.publisher).to.eql({ domain: 'publisher.example.com' }); + }); + + it('includes data.site.publisher.id even when domain is absent', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { site: { publisher: { id: 'pub-123' } } }, + }))[0]; + expect(request.data.site.publisher).to.eql({ id: 'pub-123' }); + }); + + it('includes both id and domain in data.site.publisher when both present', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { site: { publisher: { id: 'pub-123', domain: 'example.com' } } }, + }))[0]; + expect(request.data.site.publisher).to.eql({ id: 'pub-123', domain: 'example.com' }); + }); + + it('includes data.user.yob, data.user.gender, data.user.keywords', function () { + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { user: { yob: 1990, gender: 'M', keywords: 'sports,tech' } }, + }))[0]; + expect(request.data.user.yob).to.eql(1990); + expect(request.data.user.gender).to.eql('M'); + expect(request.data.user.keywords).to.eql('sports,tech'); + }); + + it('includes data.user.ext.data from ortb2.user.ext.data', function () { + const extData = { segment: ['A', 'B'], customAttr: 'value' }; + const request = spec.buildRequests(bidRequests, Object.assign({}, bidderRequest, { + ortb2: { user: { ext: { data: extData } } }, + }))[0]; + expect(request.data.user.ext.data).to.eql(extData); + }); + + it('does not include data.user.ext when ortb2.user.ext.data is absent', function () { + const request = spec.buildRequests(bidRequests, bidderRequest)[0]; + expect(request.data.user.ext).to.eql(undefined); + }); }); describe('should interpretResponse', function() { From 7bf65e7a388815bfd5c2c6256f4cb02cddb6221b Mon Sep 17 00:00:00 2001 From: mihanikw2g <92710748+mihanikw2g@users.noreply.github.com> Date: Wed, 3 Jun 2026 20:29:53 +0700 Subject: [PATCH 033/124] Asterio Bid Adapter: Add native support (#14929) --- modules/asterioBidAdapter.md | 2 +- modules/asterioBidAdapter.ts | 115 +++++++++++++++++++- test/spec/modules/asterioBidAdapter_spec.js | 77 +++++++++++++ 3 files changed, 188 insertions(+), 6 deletions(-) diff --git a/modules/asterioBidAdapter.md b/modules/asterioBidAdapter.md index f18b7156bd7..07a056caf09 100644 --- a/modules/asterioBidAdapter.md +++ b/modules/asterioBidAdapter.md @@ -9,7 +9,7 @@ Maintainer: mnikulin@asteriosoft.com # Description Connects to Asterio Bidder for bids. -Asterio bid adapter supports Banner and Video ads. +Asterio bid adapter supports Banner, Video and Native ads. # Bid Params diff --git a/modules/asterioBidAdapter.ts b/modules/asterioBidAdapter.ts index 4c6441367d6..3c2ffe13915 100644 --- a/modules/asterioBidAdapter.ts +++ b/modules/asterioBidAdapter.ts @@ -1,7 +1,7 @@ import { type AdapterRequest, type BidderSpec, type ServerResponse, registerBidder } from '../src/adapters/bidderFactory.js'; import { deepAccess, deepClone } from '../src/utils.js'; import { ajax } from '../src/ajax.js'; -import { BANNER, VIDEO } from '../src/mediaTypes.js'; +import { BANNER, NATIVE, VIDEO } from '../src/mediaTypes.js'; import type { BidRequest } from '../src/adapterManager.js'; import type { Size } from '../src/types/common.d.ts'; @@ -45,9 +45,54 @@ type AsterioServerBid = { adomain?: string[]; }; +type AsterioNativeImage = { + url: string; + width?: number; + height?: number; +}; + +type AsterioNativeResponse = { + link?: { + url?: string; + clicktrackers?: string[]; + }; + imptrackers?: string[]; + eventtrackers?: Array<{ + event?: number; + method?: number; + url?: string; + }>; + assets?: Array<{ + title?: { + text?: string; + }; + img?: { + url?: string; + w?: number; + h?: number; + type?: number; + }; + data?: { + value?: string; + type?: number; + }; + }>; +}; + +type AsterioNativeBid = { + clickUrl?: string; + clickTrackers: string[]; + impressionTrackers: string[]; + ortb: AsterioNativeResponse; + title?: string; + image?: AsterioNativeImage; + icon?: AsterioNativeImage; + body?: string; +}; + export const spec: BidderSpec = { code: BIDDER_CODE, - supportedMediaTypes: [BANNER, VIDEO], + supportedMediaTypes: [BANNER, VIDEO, NATIVE], isBidRequestValid: function (bid) { return !!(bid.params && bid.params.adUnitToken); @@ -58,7 +103,7 @@ export const spec: BidderSpec = { bidId: bidRequest.bidId, adUnitToken: bidRequest.params.adUnitToken, pos: getPosition(bidRequest), - sizes: prepareSizes(bidRequest.sizes) + sizes: prepareSizes(getSizes(bidRequest)) })); const payload: { @@ -121,6 +166,14 @@ export const spec: BidderSpec = { bid.vastXml = bidResponse.ad; } + if (NATIVE === bid.mediaType && bidResponse.ad) { + const native = parseNativeAd(bidResponse.ad); + if (native) { + bid.native = native; + delete bid.ad; + } + } + bid.meta = {}; bid.meta.advertiserDomains = bid.adomain || []; @@ -138,16 +191,68 @@ export const spec: BidderSpec = { } }; -function prepareSizes(sizes: Size | Size[]) { +function prepareSizes(sizes: Size | Size[] | undefined): AsterioBidPayload['sizes'] { if (!Array.isArray(sizes) || sizes.length === 0) { return []; } - const normalizedSizes = typeof sizes[0] === 'number' ? [sizes] : sizes; + const normalizedSizes: Size[] = typeof sizes[0] === 'number' ? [sizes as Size] : sizes as Size[]; return normalizedSizes.map(size => ({ width: size[0], height: size[1] })); } +function getSizes(bidRequest: BidRequest): Size | Size[] | undefined { + return bidRequest.mediaTypes?.banner?.sizes ?? deepAccess(bidRequest, 'sizes'); +} + function getPosition(bidRequest: BidRequest): number | undefined { return bidRequest.params.pos ?? deepAccess(bidRequest, 'mediaTypes.banner.pos') ?? deepAccess(bidRequest, 'mediaTypes.video.pos'); } +function parseNativeAd(ad: string): AsterioNativeBid | undefined { + let parsedResponse: { native?: AsterioNativeResponse }; + try { + parsedResponse = JSON.parse(ad); + } catch (e) { + return; + } + + const nativeResponse = parsedResponse.native; + if (!nativeResponse) { + return; + } + + const native: AsterioNativeBid = { + clickUrl: nativeResponse.link?.url, + clickTrackers: [...(nativeResponse.link?.clicktrackers || [])], + impressionTrackers: [...(nativeResponse.imptrackers || [])], + ortb: nativeResponse + }; + + nativeResponse.eventtrackers?.forEach(tracker => { + if (tracker.event === 1 && tracker.method === 1 && tracker.url) { + native.impressionTrackers.push(tracker.url); + } + }); + + nativeResponse.assets?.forEach(asset => { + if (asset.title?.text) { + native.title = asset.title.text; + } else if (asset.img?.url) { + const image: AsterioNativeImage = { + url: asset.img.url, + width: asset.img.w, + height: asset.img.h + }; + if (asset.img.type === 1) { + native.icon = image; + } else if (asset.img.type === 3 || !native.image) { + native.image = image; + } + } else if (asset.data?.value && (asset.data.type === 2 || !native.body)) { + native.body = asset.data.value; + } + }); + + return native; +} + registerBidder(spec); diff --git a/test/spec/modules/asterioBidAdapter_spec.js b/test/spec/modules/asterioBidAdapter_spec.js index 6df402b31d6..90642cffc7d 100644 --- a/test/spec/modules/asterioBidAdapter_spec.js +++ b/test/spec/modules/asterioBidAdapter_spec.js @@ -64,6 +64,59 @@ const BIDDER_VIDEO_RESPONSE = { }] }; +const BIDDER_NATIVE_RESPONSE = { + bids: [{ + ad: JSON.stringify({ + native: { + assets: [{ + title: { + text: 'Native title' + } + }, { + img: { + type: 3, + url: 'https://cdn.example.com/image.jpg', + w: 300, + h: 250 + } + }, { + img: { + type: 1, + url: 'https://cdn.example.com/icon.jpg', + w: 64, + h: 64 + } + }, { + data: { + type: 2, + value: 'Native body' + } + }], + link: { + url: 'https://advertiser.example.com', + clicktrackers: ['https://tracker.example.com/click'] + }, + eventtrackers: [{ + event: 1, + method: 1, + url: 'https://tracker.example.com/impression' + }] + } + }), + requestId: 'request-3', + cpm: 3.45, + currency: 'USD', + width: 1, + height: 1, + ttl: 300, + creativeId: 'creative-3', + netRevenue: true, + format: 'native', + mediaType: 'native', + adomain: ['native.example.com'] + }] +}; + describe('asterioBidAdapter', function () { const adapter = newBidder(spec); @@ -218,6 +271,30 @@ describe('asterioBidAdapter', function () { expect(result[0].meta.advertiserDomains).to.deep.equal(['video.example.com']); }); + it('should map native bids from direct response', function () { + const result = spec.interpretResponse({ body: BIDDER_NATIVE_RESPONSE }, {}); + + expect(result).to.have.lengthOf(1); + expect(result[0].mediaType).to.equal('native'); + expect(result[0].ad).to.equal(undefined); + expect(result[0].native.title).to.equal('Native title'); + expect(result[0].native.body).to.equal('Native body'); + expect(result[0].native.clickUrl).to.equal('https://advertiser.example.com'); + expect(result[0].native.image).to.deep.equal({ + url: 'https://cdn.example.com/image.jpg', + width: 300, + height: 250 + }); + expect(result[0].native.icon).to.deep.equal({ + url: 'https://cdn.example.com/icon.jpg', + width: 64, + height: 64 + }); + expect(result[0].native.clickTrackers).to.deep.equal(['https://tracker.example.com/click']); + expect(result[0].native.impressionTrackers).to.deep.equal(['https://tracker.example.com/impression']); + expect(result[0].meta.advertiserDomains).to.deep.equal(['native.example.com']); + }); + it('should return empty array for invalid response body', function () { expect(spec.interpretResponse({ body: undefined }, {})).to.deep.equal([]); expect(spec.interpretResponse({ body: '' }, {})).to.deep.equal([]); From b69cd8d64fa97103ce264736eba7fd82e20f20f7 Mon Sep 17 00:00:00 2001 From: abermanov-zeta <95416296+abermanov-zeta@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:38:00 +0200 Subject: [PATCH 034/124] Zeta Global Analytics Adapter: extra events (#14964) * Zeta Global SSP Analytics Adapter: track extra events * Zeta Global SSP Analytics Adapter: harden payload helpers and fallbacks Extract shared site-context, floor, mediaType, and device helpers so analytics events send complete fields (including auctionId on bidsReceived) with robust page/domain fallbacks and bounded bidder error payloads. Co-authored-by: Cursor * Zeta SSP Analytics Adapter: code style fixes. --------- Co-authored-by: Cursor --- modules/zeta_global_sspAnalyticsAdapter.js | 293 ++++++++++++------ modules/zeta_global_sspAnalyticsAdapter.md | 11 +- .../zeta_global_sspAnalyticsAdapter_spec.js | 264 ++++++++++++++++ 3 files changed, 468 insertions(+), 100 deletions(-) diff --git a/modules/zeta_global_sspAnalyticsAdapter.js b/modules/zeta_global_sspAnalyticsAdapter.js index 01d6a4a5a77..6e0964e9954 100644 --- a/modules/zeta_global_sspAnalyticsAdapter.js +++ b/modules/zeta_global_sspAnalyticsAdapter.js @@ -5,13 +5,14 @@ import { EVENTS } from '../src/constants.js'; import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js'; import { config } from '../src/config.js'; -import { parseDomain } from '../src/refererDetection.js'; +import { getRefererInfo, parseDomain } from '../src/refererDetection.js'; import { BANNER, VIDEO } from "../src/mediaTypes.js"; const ZETA_GVL_ID = 833; const ADAPTER_CODE = 'zeta_global_ssp'; const BASE_URL = 'https://ssp.disqus.com/prebid/event'; const LOG_PREFIX = 'ZetaGlobalSsp-Analytics: '; +const MAX_ERROR_RESPONSE_TEXT_LENGTH = 500; /// /////////// VARIABLES //////////////////////////////////// @@ -27,128 +28,213 @@ function sendEvent(eventType, event) { ); } +function getMediaTypeFromBidRequest(b) { + return b?.mediaTypes?.video ? VIDEO : (b?.mediaTypes?.banner ? BANNER : undefined); +} + +function resolveFloorFromBidRequest(b) { + const mediaType = getMediaTypeFromBidRequest(b); + if (typeof b?.getFloor !== 'function') { + return undefined; + } + try { + const floorInfo = b.getFloor({ + currency: 'USD', + mediaType: mediaType, + size: '*' + }); + const floor = parseFloat(floorInfo?.floor); + return !isNaN(floor) ? floor : undefined; + } catch (e) { + return undefined; + } +} + +function buildBidRequestBid(b) { + return { + bidId: b?.bidId, + auctionId: b?.auctionId, + bidder: b?.bidder, + mediaType: getMediaTypeFromBidRequest(b), + sizes: b?.sizes, + device: b?.ortb2?.device, + adUnitCode: b?.adUnitCode, + floor: resolveFloorFromBidRequest(b) + }; +} + +function resolveRenderSiteContext(args = {}) { + const pageUrl = config.getConfig('pageUrl'); + const docLocation = args.doc?.location; + const docPage = docLocation?.host && docLocation?.pathname + ? docLocation.host + docLocation.pathname + : undefined; + const page = pageUrl || docPage || args.bid?.refererInfo?.page || getRefererInfo().page; + const domain = parseDomain(page, { noLeadingWww: true }) || + args.bid?.refererInfo?.domain || + getRefererInfo().domain; + return { page, domain }; +} + +function resolveBidderRequestSiteContext(bidderRequest) { + const refererInfo = getRefererInfo(); + return { + page: bidderRequest?.refererInfo?.page || refererInfo.page, + domain: bidderRequest?.refererInfo?.domain || refererInfo.domain + }; +} + +function resolveTimeoutSiteContext(timeouts = []) { + const siteBid = timeouts.find(t => t?.ortb2?.site?.page || t?.ortb2?.site?.domain); + const refererInfo = getRefererInfo(); + return { + page: siteBid?.ortb2?.site?.page || refererInfo.page, + domain: siteBid?.ortb2?.site?.domain || refererInfo.domain + }; +} + +function buildReceivedBid(bid) { + return { + adId: bid?.adId, + requestId: bid?.requestId, + auctionId: bid?.auctionId, + creativeId: bid?.creativeId, + bidder: bid?.bidderCode || bid?.bidder, + dspId: bid?.dspId, + mediaType: bid?.mediaType, + size: bid?.size, + adomain: bid?.adserverTargeting?.hb_adomain, + timeToRespond: bid?.timeToRespond, + cpm: bid?.cpm, + adUnitCode: bid?.adUnitCode, + floorData: bid?.floorData + }; +} + +function buildDevice(bid) { + const device = bid?.ortb2?.device; + if (device) { + return { ...device, ua: device.ua || navigator.userAgent }; + } + return { ua: navigator.userAgent }; +} + +function normalizeError(error) { + if (error == null) { + return undefined; + } + if (typeof error === 'string') { + return { message: error }; + } + const normalized = {}; + if (error.message != null) { + normalized.message = error.message; + } + if (error.status != null) { + normalized.status = error.status; + } + if (error.statusText != null) { + normalized.statusText = error.statusText; + } + if (error.responseText != null) { + normalized.responseText = String(error.responseText).slice(0, MAX_ERROR_RESPONSE_TEXT_LENGTH); + } + if (Object.keys(normalized).length === 0) { + return { message: String(error) }; + } + return normalized; +} + /// /////////// ADAPTER EVENT HANDLER FUNCTIONS ////////////// function adRenderSucceededHandler(args) { - const page = config.getConfig('pageUrl') || args.doc?.location?.host + args.doc?.location?.pathname; + const { page, domain } = resolveRenderSiteContext(args); const event = { zetaParams: zetaParams, - domain: parseDomain(page, { noLeadingWww: true }), + domain: domain, page: page, - bid: { - adId: args.bid?.adId, - requestId: args.bid?.requestId, - auctionId: args.bid?.auctionId, - creativeId: args.bid?.creativeId, - bidder: args.bid?.bidderCode, - dspId: args.bid?.dspId, - mediaType: args.bid?.mediaType, - size: args.bid?.size, - adomain: args.bid?.adserverTargeting?.hb_adomain, - timeToRespond: args.bid?.timeToRespond, - cpm: args.bid?.cpm, - adUnitCode: args.bid?.adUnitCode, - floorData: args.bid?.floorData - }, - device: { - ua: navigator.userAgent - } + bid: buildReceivedBid(args.bid), + device: buildDevice(args.bid) } sendEvent(EVENTS.AD_RENDER_SUCCEEDED, event); } +function adRenderFailedHandler(args) { + const { page, domain } = resolveRenderSiteContext(args); + const event = { + zetaParams: zetaParams, + domain: domain, + page: page, + adId: args.adId, + reason: args.reason, + message: args.message, + bid: buildReceivedBid(args.bid), + device: buildDevice(args.bid) + } + sendEvent(EVENTS.AD_RENDER_FAILED, event); +} + function auctionEndHandler(args) { const event = { zetaParams: zetaParams, - bidderRequests: args.bidderRequests?.map(br => ({ - bidderCode: br?.bidderCode, - domain: br?.refererInfo?.domain, - page: br?.refererInfo?.page, - bids: br?.bids?.map(b => { - const mediaType = b?.mediaTypes?.video ? VIDEO : (b?.mediaTypes?.banner ? BANNER : undefined); - let floor; - if (typeof b?.getFloor === 'function') { - try { - const floorInfo = b.getFloor({ - currency: 'USD', - mediaType: mediaType, - size: '*' - }); - if (floorInfo && !isNaN(parseFloat(floorInfo.floor))) { - floor = parseFloat(floorInfo.floor); - } - } catch (e) { - // ignore floor lookup errors - } - } - - return { - bidId: b?.bidId, - auctionId: b?.auctionId, - bidder: b?.bidder, - mediaType: mediaType, - sizes: b?.sizes, - device: b?.ortb2?.device, - adUnitCode: b?.adUnitCode, - floor: floor - }; - }) - })), - bidsReceived: args.bidsReceived?.map(br => ({ - adId: br?.adId, - requestId: br?.requestId, - creativeId: br?.creativeId, - bidder: br?.bidder, - mediaType: br?.mediaType, - size: br?.size, - adomain: br?.adserverTargeting?.hb_adomain, - timeToRespond: br?.timeToRespond, - cpm: br?.cpm, - adUnitCode: br?.adUnitCode, - dspId: br?.dspId - })) + bidderRequests: args.bidderRequests?.map(br => { + const siteContext = resolveBidderRequestSiteContext(br); + return { + bidderCode: br?.bidderCode, + domain: siteContext.domain, + page: siteContext.page, + bids: br?.bids?.map(buildBidRequestBid) + }; + }), + bidsReceived: args.bidsReceived?.map(buildReceivedBid) } sendEvent(EVENTS.AUCTION_END, event); } function bidTimeoutHandler(args) { + const siteContext = resolveTimeoutSiteContext(args); const event = { zetaParams: zetaParams, - domain: args.find(t => t?.ortb2?.site?.domain)?.ortb2?.site?.domain, - page: args.find(t => t?.ortb2?.site?.page)?.ortb2?.site?.page, - timeouts: args.map(t => { - const mediaType = t?.mediaTypes?.video ? VIDEO : (t?.mediaTypes?.banner ? BANNER : undefined); - let floor; - if (typeof t?.getFloor === 'function') { - try { - const floorInfo = t.getFloor({ - currency: 'USD', - mediaType: mediaType, - size: '*' - }); - if (floorInfo && !isNaN(parseFloat(floorInfo.floor))) { - floor = parseFloat(floorInfo.floor); - } - } catch (e) { - // ignore floor lookup errors - } - } - return { - bidId: t?.bidId, - auctionId: t?.auctionId, - bidder: t?.bidder, - mediaType: mediaType, - sizes: t?.sizes, - timeout: t?.timeout, - device: t?.ortb2?.device, - adUnitCode: t?.adUnitCode, - floor: floor - } - }) + domain: siteContext.domain, + page: siteContext.page, + timeouts: args.map(t => ({ + ...buildBidRequestBid(t), + timeout: t?.timeout + })) } sendEvent(EVENTS.BID_TIMEOUT, event); } +function bidderErrorHandler(args) { + const bidderRequest = args.bidderRequest; + const siteContext = resolveBidderRequestSiteContext(bidderRequest); + const event = { + zetaParams: zetaParams, + error: normalizeError(args.error), + bidderRequest: { + bidderCode: bidderRequest?.bidderCode, + domain: siteContext.domain, + page: siteContext.page, + bids: bidderRequest?.bids?.map(buildBidRequestBid) + } + } + sendEvent(EVENTS.BIDDER_ERROR, event); +} + +function browserInterventionHandler(args) { + const { page, domain } = resolveRenderSiteContext(args); + const event = { + zetaParams: zetaParams, + domain: domain, + page: page, + adId: args.adId, + intervention: args.intervention, + bid: buildReceivedBid(args.bid), + device: buildDevice(args.bid) + } + sendEvent(EVENTS.BROWSER_INTERVENTION, event); +} + /// /////////// ADAPTER DEFINITION /////////////////////////// const baseAdapter = adapter({ analyticsType: 'endpoint' }); @@ -174,12 +260,21 @@ const zetaAdapter = Object.assign({}, baseAdapter, { case EVENTS.AD_RENDER_SUCCEEDED: adRenderSucceededHandler(args); break; + case EVENTS.AD_RENDER_FAILED: + adRenderFailedHandler(args); + break; case EVENTS.AUCTION_END: auctionEndHandler(args); break; case EVENTS.BID_TIMEOUT: bidTimeoutHandler(args); break; + case EVENTS.BIDDER_ERROR: + bidderErrorHandler(args); + break; + case EVENTS.BROWSER_INTERVENTION: + browserInterventionHandler(args); + break; } } }); diff --git a/modules/zeta_global_sspAnalyticsAdapter.md b/modules/zeta_global_sspAnalyticsAdapter.md index d586d0069b1..2d8cfeeeb04 100644 --- a/modules/zeta_global_sspAnalyticsAdapter.md +++ b/modules/zeta_global_sspAnalyticsAdapter.md @@ -8,7 +8,16 @@ Maintainer: abermanov@zetaglobal.com ## Description -Analytics Adapter which sends auctionEnd and adRenderSucceeded events to Zeta Global SSP analytics endpoints +Analytics Adapter which sends Prebid analytics events to Zeta Global SSP analytics endpoints. + +Tracked events: + +- `auctionEnd` +- `adRenderSucceeded` +- `adRenderFailed` +- `bidTimeout` +- `bidderError` +- `browserIntervention` ## How to configure ``` diff --git a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js index e3e37ff967e..4e50dcdbff0 100644 --- a/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js +++ b/test/spec/modules/zeta_global_sspAnalyticsAdapter_spec.js @@ -2,6 +2,7 @@ import zetaAnalyticsAdapter from 'modules/zeta_global_sspAnalyticsAdapter.js'; import { config } from 'src/config'; import { EVENTS } from 'src/constants.js'; import { server } from '../../mocks/xhr.js'; +import * as refererDetection from 'src/refererDetection.js'; const utils = require('src/utils'); const events = require('src/events'); @@ -365,6 +366,103 @@ const SAMPLE_EVENTS = { }, 'adId': '5759bb3ef7be1e8' }, + AD_RENDER_FAILED: { + 'reason': 'exception', + 'message': 'Render failed', + 'bid': { + 'bidderCode': 'zeta_global_ssp', + 'adId': '5759bb3ef7be1e8', + 'requestId': '206be9a13236af', + 'mediaType': 'banner', + 'cpm': 2.258302852806723, + 'creativeId': '456456456', + 'auctionId': '75e394d9', + 'bidder': 'zeta_global_ssp', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 123, + 'size': '480x320', + 'dspId': 'test-dsp-id-123', + 'adserverTargeting': { + 'hb_adomain': 'example.adomain' + }, + 'floorData': { + 'floorValue': 1.5, + 'floorCurrency': 'USD', + 'floorRule': 'test-rule' + } + }, + 'adId': '5759bb3ef7be1e8' + }, + BIDDER_ERROR: { + 'error': { + 'status': 503, + 'statusText': 'Service Unavailable', + 'responseText': 'upstream unavailable' + }, + 'bidderRequest': { + 'bidderCode': 'zeta_global_ssp', + 'refererInfo': { + 'domain': 'test-zeta-ssp.net:63342', + 'page': 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html' + }, + 'bids': [{ + 'adUnitCode': '/19968336/header-bid-tag-0', + 'bidId': '206be9a13236af', + 'auctionId': '75e394d9', + 'bidder': 'zeta_global_ssp', + 'mediaTypes': { + 'banner': { + 'sizes': [ + [300, 250], + [300, 600] + ] + } + }, + 'sizes': [ + [300, 250], + [300, 600] + ], + 'ortb2': { + 'device': { + 'mobile': 1 + } + }, + 'getFloor': function() { + return { floor: 1.5, currency: 'USD' }; + } + }] + } + }, + BROWSER_INTERVENTION: { + 'bid': { + 'bidderCode': 'zeta_global_ssp', + 'adId': '5759bb3ef7be1e8', + 'requestId': '206be9a13236af', + 'mediaType': 'banner', + 'cpm': 2.258302852806723, + 'creativeId': '456456456', + 'auctionId': '75e394d9', + 'bidder': 'zeta_global_ssp', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 123, + 'size': '480x320', + 'dspId': 'test-dsp-id-123', + 'adserverTargeting': { + 'hb_adomain': 'example.adomain' + }, + 'floorData': { + 'floorValue': 1.5, + 'floorCurrency': 'USD', + 'floorRule': 'test-rule' + } + }, + 'adId': '5759bb3ef7be1e8', + 'intervention': { + 'type': 'intervention', + 'id': 'HeavyAdIntervention', + 'message': 'Heavy ad unloaded' + } + }, BID_TIMEOUT: [ { 'bidder': 'zeta_global_ssp', @@ -628,6 +726,7 @@ describe('Zeta Global SSP Analytics Adapter', function () { adUnitCode: '/19968336/header-bid-tag-0', adId: '5759bb3ef7be1e8', requestId: '206be9a13236af', + auctionId: '75e394d9', creativeId: '456456456', bidder: 'zeta_global_ssp', mediaType: 'banner', @@ -676,6 +775,171 @@ describe('Zeta Global SSP Analytics Adapter', function () { expect(auctionSucceeded.device.ua).to.not.be.empty; }); + it('should handle AD_RENDER_FAILED event', function () { + events.emit(EVENTS.AD_RENDER_FAILED, SAMPLE_EVENTS.AD_RENDER_FAILED); + + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal('https://ssp.disqus.com/prebid/event/adRenderFailed'); + const adRenderFailed = JSON.parse(requests[0].requestBody); + expect(adRenderFailed.zetaParams).to.be.deep.equal({ + sid: 111, + tags: { + position: 'top', + shortname: 'name' + } + }); + expect(adRenderFailed.domain).to.eql('config.domain.com'); + expect(adRenderFailed.page).to.eql('https://www.config.domain.com/index.html'); + expect(adRenderFailed.adId).to.eql('5759bb3ef7be1e8'); + expect(adRenderFailed.reason).to.eql('exception'); + expect(adRenderFailed.message).to.eql('Render failed'); + expect(adRenderFailed.bid.bidder).to.eql('zeta_global_ssp'); + expect(adRenderFailed.bid.floorData).to.be.deep.equal({ + floorValue: 1.5, + floorCurrency: 'USD', + floorRule: 'test-rule' + }); + expect(adRenderFailed.device.ua).to.not.be.empty; + }); + + it('should handle AD_RENDER_FAILED event without pageUrl config using bid refererInfo', function () { + config.resetConfig(); + events.emit(EVENTS.AD_RENDER_FAILED, { + ...SAMPLE_EVENTS.AD_RENDER_FAILED, + bid: { + ...SAMPLE_EVENTS.AD_RENDER_FAILED.bid, + refererInfo: { + domain: 'fallback.example.com', + page: 'https://fallback.example.com/article' + }, + ortb2: { + device: { + w: 1024, + h: 768, + ua: 'test-ua-string' + } + } + } + }); + + expect(requests.length).to.equal(1); + const adRenderFailed = JSON.parse(requests[0].requestBody); + expect(adRenderFailed.page).to.eql('https://fallback.example.com/article'); + expect(adRenderFailed.domain).to.eql('fallback.example.com'); + expect(adRenderFailed.device).to.be.deep.equal({ + w: 1024, + h: 768, + ua: 'test-ua-string' + }); + }); + + it('should handle AD_RENDER_FAILED event without pageUrl config using getRefererInfo fallback', function () { + config.resetConfig(); + sandbox.stub(refererDetection, 'getRefererInfo').returns({ + domain: 'referer.example.com', + page: 'https://referer.example.com/page' + }); + events.emit(EVENTS.AD_RENDER_FAILED, SAMPLE_EVENTS.AD_RENDER_FAILED); + + expect(requests.length).to.equal(1); + const adRenderFailed = JSON.parse(requests[0].requestBody); + expect(adRenderFailed.page).to.eql('https://referer.example.com/page'); + expect(adRenderFailed.domain).to.eql('referer.example.com'); + }); + + it('should handle BIDDER_ERROR event', function () { + events.emit(EVENTS.BIDDER_ERROR, SAMPLE_EVENTS.BIDDER_ERROR); + + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal('https://ssp.disqus.com/prebid/event/bidderError'); + const bidderError = JSON.parse(requests[0].requestBody); + expect(bidderError.zetaParams).to.be.deep.equal({ + sid: 111, + tags: { + position: 'top', + shortname: 'name' + } + }); + expect(bidderError.error).to.be.deep.equal({ + status: 503, + statusText: 'Service Unavailable', + responseText: 'upstream unavailable' + }); + expect(bidderError.bidderRequest).to.be.deep.equal({ + bidderCode: 'zeta_global_ssp', + domain: 'test-zeta-ssp.net:63342', + page: 'http://test-zeta-ssp.net:63342/zeta-ssp/ssp/_dev/examples/page_banner.html', + bids: [{ + adUnitCode: '/19968336/header-bid-tag-0', + bidId: '206be9a13236af', + auctionId: '75e394d9', + bidder: 'zeta_global_ssp', + mediaType: 'banner', + sizes: [ + [300, 250], + [300, 600] + ], + device: { + mobile: 1 + }, + floor: 1.5 + }] + }); + }); + + it('should truncate long bidder error responseText', function () { + const longResponse = 'x'.repeat(600); + events.emit(EVENTS.BIDDER_ERROR, { + ...SAMPLE_EVENTS.BIDDER_ERROR, + error: { + message: 'Server error', + status: 500, + responseText: longResponse + } + }); + + expect(requests.length).to.equal(1); + const bidderError = JSON.parse(requests[0].requestBody); + expect(bidderError.error.responseText).to.have.lengthOf(500); + expect(bidderError.error.message).to.eql('Server error'); + }); + + it('should stringify empty bidder error objects', function () { + events.emit(EVENTS.BIDDER_ERROR, { + ...SAMPLE_EVENTS.BIDDER_ERROR, + error: {} + }); + + expect(requests.length).to.equal(1); + const bidderError = JSON.parse(requests[0].requestBody); + expect(bidderError.error).to.be.deep.equal({ message: '[object Object]' }); + }); + + it('should handle BROWSER_INTERVENTION event', function () { + events.emit(EVENTS.BROWSER_INTERVENTION, SAMPLE_EVENTS.BROWSER_INTERVENTION); + + expect(requests.length).to.equal(1); + expect(requests[0].url).to.equal('https://ssp.disqus.com/prebid/event/browserIntervention'); + const browserIntervention = JSON.parse(requests[0].requestBody); + expect(browserIntervention.zetaParams).to.be.deep.equal({ + sid: 111, + tags: { + position: 'top', + shortname: 'name' + } + }); + expect(browserIntervention.domain).to.eql('config.domain.com'); + expect(browserIntervention.page).to.eql('https://www.config.domain.com/index.html'); + expect(browserIntervention.adId).to.eql('5759bb3ef7be1e8'); + expect(browserIntervention.intervention).to.be.deep.equal({ + type: 'intervention', + id: 'HeavyAdIntervention', + message: 'Heavy ad unloaded' + }); + expect(browserIntervention.bid.bidder).to.eql('zeta_global_ssp'); + expect(browserIntervention.device.ua).to.not.be.empty; + }); + it('should handle BID_TIMEOUT event', function () { events.emit(EVENTS.BID_TIMEOUT, SAMPLE_EVENTS.BID_TIMEOUT); From 454e8a1f01775a93469a03d3d00754188e965573 Mon Sep 17 00:00:00 2001 From: Demetrio Girardi Date: Wed, 3 Jun 2026 06:50:09 -0700 Subject: [PATCH 035/124] tcfControl: use the GVL to determine legal basis (#14979) * fetch purposes during build * Update metadata * include purpose metadata in adapters * add warning on bidders without p2 LI * add --no-fetch option to compile-metadata * add warning on undeclared flexible purposes * getPublicUrl * Update metadata * cleanup * Better purpose declaration warnings * do not double include purpose metadata * update metadata including specialFeatures * add build time validation * update tcfControl to check purpose declarations * lint * do not use intersection/difference --- babelConfig.js | 1 + gulp.precompilation.js | 1 + gulpfile.js | 2 +- libraries/purposeDeclarations/validate.mjs | 13 + metadata/compileMetadata.mjs | 81 ++++- metadata/gvl.mjs | 9 + metadata/modules.json | 25 +- metadata/modules/1plusXRtdProvider.json | 1 + .../modules/33acrossAnalyticsAdapter.json | 1 + metadata/modules/33acrossBidAdapter.json | 19 +- metadata/modules/33acrossIdSystem.json | 19 +- metadata/modules/360playvidBidAdapter.json | 1 + metadata/modules/51DegreesRtdProvider.json | 1 + .../AsteriobidPbmAnalyticsAdapter.json | 1 + metadata/modules/a1MediaBidAdapter.json | 1 + metadata/modules/a1MediaRtdProvider.json | 1 + metadata/modules/a4gBidAdapter.json | 1 + .../modules/aaxBlockmeterRtdProvider.json | 1 + metadata/modules/ablidaBidAdapter.json | 1 + metadata/modules/abtshieldIdSystem.json | 30 +- metadata/modules/aceexBidAdapter.json | 16 +- metadata/modules/acuityadsBidAdapter.json | 24 +- metadata/modules/acxiomRealIdSystem.json | 14 + metadata/modules/ad2ictionBidAdapter.json | 1 + metadata/modules/adWMGAnalyticsAdapter.json | 1 + metadata/modules/adWMGBidAdapter.json | 1 + metadata/modules/adagioAnalyticsAdapter.json | 1 + metadata/modules/adagioBidAdapter.json | 26 +- metadata/modules/adagioRtdProvider.json | 26 +- metadata/modules/adbroBidAdapter.json | 25 +- metadata/modules/adbutlerBidAdapter.json | 1 + metadata/modules/adclusterBidAdapter.json | 1 + metadata/modules/addefendBidAdapter.json | 16 +- metadata/modules/adelerateBidAdapter.json | 1 + metadata/modules/adfBidAdapter.json | 22 +- metadata/modules/adfusionBidAdapter.json | 18 +- metadata/modules/adgenerationBidAdapter.json | 1 + metadata/modules/adgridBidAdapter.json | 1 + metadata/modules/adhashBidAdapter.json | 1 + metadata/modules/adheseBidAdapter.json | 19 +- metadata/modules/adipoloBidAdapter.json | 22 +- .../modules/adkernelAdnAnalyticsAdapter.json | 1 + metadata/modules/adkernelAdnBidAdapter.json | 22 +- metadata/modules/adkernelBidAdapter.json | 71 +++- metadata/modules/adlaneRtdProvider.json | 1 + metadata/modules/adlooxAnalyticsAdapter.json | 1 + metadata/modules/adlooxRtdProvider.json | 1 + metadata/modules/admaruBidAdapter.json | 1 + metadata/modules/admaticBidAdapter.json | 31 +- metadata/modules/admediaBidAdapter.json | 1 + metadata/modules/admixerBidAdapter.json | 22 +- metadata/modules/admixerIdSystem.json | 22 +- metadata/modules/adnimationBidAdapter.json | 1 + metadata/modules/adnowBidAdapter.json | 72 +--- .../modules/adnuntiusAnalyticsAdapter.json | 1 + metadata/modules/adnuntiusBidAdapter.json | 22 +- metadata/modules/adnuntiusRtdProvider.json | 22 +- metadata/modules/adoceanBidAdapter.json | 19 +- metadata/modules/adotBidAdapter.json | 21 +- metadata/modules/adpartnerBidAdapter.json | 1 + metadata/modules/adplusAnalyticsAdapter.json | 1 + metadata/modules/adplusBidAdapter.json | 1 + metadata/modules/adplusIdSystem.json | 1 + metadata/modules/adponeBidAdapter.json | 18 +- metadata/modules/adprimeBidAdapter.json | 1 + metadata/modules/adqueryBidAdapter.json | 23 +- metadata/modules/adqueryIdSystem.json | 23 +- metadata/modules/adrelevantisBidAdapter.json | 1 + metadata/modules/adrinoBidAdapter.json | 19 +- metadata/modules/adriverBidAdapter.json | 1 + metadata/modules/adriverIdSystem.json | 1 + .../modules/ads_interactiveBidAdapter.json | 15 +- metadata/modules/adsmartxBidAdapter.json | 1 + metadata/modules/adsmovilBidAdapter.json | 1 + metadata/modules/adspiritBidAdapter.json | 1 + metadata/modules/adstirBidAdapter.json | 1 + metadata/modules/adtargetBidAdapter.json | 18 +- metadata/modules/adtelligentBidAdapter.json | 35 +- metadata/modules/adtelligentIdSystem.json | 14 +- metadata/modules/adtrgtmeBidAdapter.json | 1 + metadata/modules/adtrueBidAdapter.json | 1 + metadata/modules/aduptechBidAdapter.json | 24 +- metadata/modules/advRedAnalyticsAdapter.json | 1 + metadata/modules/advangelistsBidAdapter.json | 1 + metadata/modules/advertisingBidAdapter.json | 1 + metadata/modules/adverxoBidAdapter.json | 1 + metadata/modules/adxcgAnalyticsAdapter.json | 1 + metadata/modules/adxcgBidAdapter.json | 1 + .../modules/adxpremiumAnalyticsAdapter.json | 1 + metadata/modules/adyoulikeBidAdapter.json | 16 +- metadata/modules/afpBidAdapter.json | 1 + .../modules/agenticAudienceRtdProvider.json | 1 + metadata/modules/agmaAnalyticsAdapter.json | 1 + metadata/modules/aidemBidAdapter.json | 1 + metadata/modules/airgridRtdProvider.json | 20 +- metadata/modules/ajaBidAdapter.json | 1 + metadata/modules/akceloBidAdapter.json | 1 + metadata/modules/alkimiBidAdapter.json | 22 +- metadata/modules/allegroBidAdapter.json | 21 +- .../modules/alliance_gravityBidAdapter.json | 15 + metadata/modules/alvadsBidAdapter.json | 1 + metadata/modules/ampliffyBidAdapter.json | 1 + metadata/modules/amxBidAdapter.json | 15 +- metadata/modules/amxIdSystem.json | 15 +- metadata/modules/aniviewBidAdapter.json | 20 +- metadata/modules/anonymisedRtdProvider.json | 18 +- metadata/modules/anyclipBidAdapter.json | 1 + metadata/modules/anzuDSPBidAdapter.json | 1 + metadata/modules/anzuSSPBidAdapter.json | 1 + metadata/modules/apacdexBidAdapter.json | 1 + metadata/modules/apesterBidAdapter.json | 21 +- .../modules/appMonstaMediaBidAdapter.json | 1 + metadata/modules/appStockSSPBidAdapter.json | 18 +- metadata/modules/appierAnalyticsAdapter.json | 1 + metadata/modules/appierBidAdapter.json | 29 +- metadata/modules/appnexusBidAdapter.json | 77 ++++- metadata/modules/appushBidAdapter.json | 25 +- metadata/modules/apsBidAdapter.json | 23 +- metadata/modules/apstreamBidAdapter.json | 26 +- metadata/modules/arcspanRtdProvider.json | 1 + metadata/modules/asealBidAdapter.json | 1 + metadata/modules/asoBidAdapter.json | 1 + metadata/modules/asterioBidAdapter.json | 1 + .../modules/asteriobidAnalyticsAdapter.json | 1 + metadata/modules/astraoneBidAdapter.json | 1 + metadata/modules/atsAnalyticsAdapter.json | 1 + metadata/modules/audiencerunBidAdapter.json | 19 +- .../modules/automatadAnalyticsAdapter.json | 1 + metadata/modules/automatadBidAdapter.json | 1 + metadata/modules/axisBidAdapter.json | 22 +- metadata/modules/axonixBidAdapter.json | 1 + metadata/modules/azerionedgeRtdProvider.json | 25 +- metadata/modules/beachfrontBidAdapter.json | 20 +- metadata/modules/bedigitechBidAdapter.json | 1 + metadata/modules/beopBidAdapter.json | 30 +- metadata/modules/betweenBidAdapter.json | 16 +- metadata/modules/beyondmediaBidAdapter.json | 1 + metadata/modules/biddoBidAdapter.json | 1 + metadata/modules/bidfuseBidAdapter.json | 18 +- metadata/modules/bidglassBidAdapter.json | 1 + metadata/modules/bidmaticBidAdapter.json | 14 +- metadata/modules/bidscubeBidAdapter.json | 1 + metadata/modules/bidtheatreBidAdapter.json | 20 +- metadata/modules/big-richmediaBidAdapter.json | 1 + metadata/modules/billow_rtb25BidAdapter.json | 1 + metadata/modules/bitmediaBidAdapter.json | 1 + metadata/modules/blastoBidAdapter.json | 1 + metadata/modules/bliinkBidAdapter.json | 1 + metadata/modules/blockthroughBidAdapter.json | 23 +- metadata/modules/blueBidAdapter.json | 23 +- metadata/modules/blueconicRtdProvider.json | 1 + metadata/modules/bmsBidAdapter.json | 22 +- metadata/modules/bmtmBidAdapter.json | 1 + metadata/modules/boldwinBidAdapter.json | 22 +- metadata/modules/brainxBidAdapter.json | 1 + metadata/modules/brandmetricsRtdProvider.json | 1 + metadata/modules/braveBidAdapter.json | 1 + metadata/modules/bridBidAdapter.json | 17 +- metadata/modules/bridgewellBidAdapter.json | 1 + metadata/modules/browsiAnalyticsAdapter.json | 1 + metadata/modules/browsiBidAdapter.json | 14 +- metadata/modules/browsiRtdProvider.json | 1 + metadata/modules/bucksenseBidAdapter.json | 21 +- metadata/modules/buzzoolaBidAdapter.json | 1 + metadata/modules/byDataAnalyticsAdapter.json | 1 + metadata/modules/c1xBidAdapter.json | 1 + .../modules/cadent_aperture_mxBidAdapter.json | 1 + metadata/modules/carodaBidAdapter.json | 14 +- metadata/modules/ccxBidAdapter.json | 1 + metadata/modules/ceeIdSystem.json | 28 +- metadata/modules/chromeAiRtdProvider.json | 3 +- metadata/modules/chtnwBidAdapter.json | 1 + metadata/modules/cleanioRtdProvider.json | 1 + metadata/modules/clickforceBidAdapter.json | 1 + metadata/modules/clickioBidAdapter.json | 15 +- metadata/modules/clydoBidAdapter.json | 1 + metadata/modules/codefuelBidAdapter.json | 1 + metadata/modules/cointrafficBidAdapter.json | 1 + metadata/modules/coinzillaBidAdapter.json | 1 + metadata/modules/colombiaBidAdapter.json | 1 + metadata/modules/colossussspBidAdapter.json | 1 + metadata/modules/compassBidAdapter.json | 16 +- metadata/modules/conceptxBidAdapter.json | 24 +- metadata/modules/concertAnalyticsAdapter.json | 1 + metadata/modules/concertBidAdapter.json | 1 + metadata/modules/condorxBidAdapter.json | 1 + metadata/modules/confiantRtdProvider.json | 1 + metadata/modules/connatixBidAdapter.json | 19 +- metadata/modules/connectIdSystem.json | 24 +- metadata/modules/connectadBidAdapter.json | 23 +- metadata/modules/consumableBidAdapter.json | 1 + .../modules/contentexchangeBidAdapter.json | 22 +- metadata/modules/contxtfulBidAdapter.json | 1 + metadata/modules/contxtfulRtdProvider.json | 1 + metadata/modules/conversantBidAdapter.json | 22 +- metadata/modules/copper6sspBidAdapter.json | 22 +- metadata/modules/cortexBidAdapter.json | 1 + metadata/modules/cpmstarBidAdapter.json | 26 +- metadata/modules/craftBidAdapter.json | 1 + metadata/modules/criteoBidAdapter.json | 20 +- metadata/modules/criteoIdSystem.json | 20 +- metadata/modules/cwireBidAdapter.json | 18 +- metadata/modules/czechAdIdSystem.json | 17 +- metadata/modules/dacIdSystem.json | 1 + metadata/modules/dailyhuntBidAdapter.json | 1 + metadata/modules/dailymotionBidAdapter.json | 29 +- metadata/modules/dasBidAdapter.json | 1 + .../modules/datablocksAnalyticsAdapter.json | 1 + metadata/modules/datablocksBidAdapter.json | 1 + metadata/modules/datamageRtdProvider.json | 1 + .../modules/datawrkzAnalyticsAdapter.json | 1 + metadata/modules/datawrkzBidAdapter.json | 1 + metadata/modules/debugging.json | 3 +- metadata/modules/deepintentBidAdapter.json | 26 +- metadata/modules/deepintentDpesIdSystem.json | 1 + metadata/modules/defineMediaBidAdapter.json | 52 ++- metadata/modules/deltaprojectsBidAdapter.json | 24 +- metadata/modules/dexertoBidAdapter.json | 1 + metadata/modules/dgkeywordRtdProvider.json | 1 + metadata/modules/dianomiBidAdapter.json | 26 +- metadata/modules/digitalMatterBidAdapter.json | 20 +- .../modules/digitalcaramelBidAdapter.json | 1 + metadata/modules/discoveryBidAdapter.json | 1 + metadata/modules/displayioBidAdapter.json | 1 + metadata/modules/distroscaleBidAdapter.json | 12 +- metadata/modules/djaxBidAdapter.json | 1 + .../modules/docereeAdManagerBidAdapter.json | 19 +- metadata/modules/docereeBidAdapter.json | 19 +- metadata/modules/dochaseBidAdapter.json | 1 + metadata/modules/dpaiBidAdapter.json | 1 + metadata/modules/driftpixelBidAdapter.json | 1 + metadata/modules/dsp_genieeBidAdapter.json | 1 + metadata/modules/dspxBidAdapter.json | 26 +- metadata/modules/dvgroupBidAdapter.json | 1 + metadata/modules/dxkultureBidAdapter.json | 1 + metadata/modules/dxtechBidAdapter.json | 1 + .../modules/dynamicAdBoostRtdProvider.json | 1 + metadata/modules/e_volutionBidAdapter.json | 23 +- metadata/modules/eclickBidAdapter.json | 1 + metadata/modules/edge226BidAdapter.json | 17 +- .../ehealthcaresolutionsBidAdapter.json | 1 + .../modules/eightPodAnalyticsAdapter.json | 1 + metadata/modules/eightPodBidAdapter.json | 1 + metadata/modules/empowerBidAdapter.json | 18 +- metadata/modules/emtvBidAdapter.json | 1 + metadata/modules/encypherRtdProvider.json | 1 + metadata/modules/engageyaBidAdapter.json | 1 + metadata/modules/eplanningBidAdapter.json | 1 + metadata/modules/epom_dspBidAdapter.json | 1 + metadata/modules/equativBidAdapter.json | 19 +- metadata/modules/escalaxBidAdapter.json | 1 + metadata/modules/eskimiBidAdapter.json | 22 +- metadata/modules/etargetBidAdapter.json | 16 +- metadata/modules/euidIdSystem.json | 24 +- metadata/modules/exadsBidAdapter.json | 18 +- metadata/modules/excoBidAdapter.json | 1 + metadata/modules/experianRtdProvider.json | 1 + metadata/modules/fabrickIdSystem.json | 1 + metadata/modules/fanBidAdapter.json | 1 + metadata/modules/feedadBidAdapter.json | 29 +- metadata/modules/finativeBidAdapter.json | 1 + metadata/modules/fintezaAnalyticsAdapter.json | 1 + metadata/modules/flippBidAdapter.json | 1 + metadata/modules/floxisBidAdapter.json | 1 + metadata/modules/fluctBidAdapter.json | 1 + metadata/modules/freepassBidAdapter.json | 1 + metadata/modules/freepassIdSystem.json | 1 + metadata/modules/ftrackIdSystem.json | 1 + metadata/modules/fwsspBidAdapter.json | 21 +- metadata/modules/gameraRtdProvider.json | 1 + metadata/modules/gammaBidAdapter.json | 1 + metadata/modules/gamoshiBidAdapter.json | 25 +- metadata/modules/gemiusIdSystem.json | 19 +- metadata/modules/genericAnalyticsAdapter.json | 1 + metadata/modules/geoedgeRtdProvider.json | 1 + metadata/modules/geolocationRtdProvider.json | 1 + metadata/modules/getintentBidAdapter.json | 1 + metadata/modules/gjirafaBidAdapter.json | 1 + metadata/modules/glomexBidAdapter.json | 28 +- metadata/modules/gmosspBidAdapter.json | 1 + metadata/modules/gnetBidAdapter.json | 1 + metadata/modules/goadserverBidAdapter.json | 1 + metadata/modules/goldbachBidAdapter.json | 72 ++-- metadata/modules/goldfishAdsRtdProvider.json | 1 + metadata/modules/gravitoIdSystem.json | 1 + .../modules/greenbidsAnalyticsAdapter.json | 1 + metadata/modules/greenbidsBidAdapter.json | 1 + metadata/modules/greenbidsRtdProvider.json | 1 + metadata/modules/gridBidAdapter.json | 17 +- metadata/modules/growadsBidAdapter.json | 1 + .../modules/growthCodeAnalyticsAdapter.json | 1 + metadata/modules/growthCodeIdSystem.json | 1 + metadata/modules/growthCodeRtdProvider.json | 1 + metadata/modules/gumgumBidAdapter.json | 19 +- metadata/modules/h12mediaBidAdapter.json | 1 + metadata/modules/hadronAnalyticsAdapter.json | 1 + metadata/modules/hadronIdSystem.json | 18 +- metadata/modules/hadronRtdProvider.json | 18 +- metadata/modules/haloadsBidAdapter.json | 1 + metadata/modules/harionBidAdapter.json | 18 +- metadata/modules/holidBidAdapter.json | 22 +- metadata/modules/hubvisorBidAdapter.json | 12 +- .../humansecurityMalvDefenseRtdProvider.json | 1 + .../modules/humansecurityRtdProvider.json | 1 + metadata/modules/hybridBidAdapter.json | 25 +- metadata/modules/hypelabBidAdapter.json | 1 + metadata/modules/iasRtdProvider.json | 1 + metadata/modules/id5AnalyticsAdapter.json | 1 + metadata/modules/id5IdSystem.json | 15 +- metadata/modules/identityLinkIdSystem.json | 21 +- metadata/modules/idxBidAdapter.json | 1 + metadata/modules/idxIdSystem.json | 1 + metadata/modules/illuminBidAdapter.json | 23 +- metadata/modules/imAnalyticsAdapter.json | 1 + metadata/modules/imRtdProvider.json | 1 + metadata/modules/impactifyBidAdapter.json | 27 +- .../modules/improvedigitalBidAdapter.json | 25 +- metadata/modules/imuIdSystem.json | 1 + metadata/modules/incrementxBidAdapter.json | 1 + metadata/modules/inmobiBidAdapter.json | 25 +- metadata/modules/innityBidAdapter.json | 1 + metadata/modules/insticatorBidAdapter.json | 31 +- metadata/modules/insuradsBidAdapter.json | 18 +- metadata/modules/insuradsRtdProvider.json | 18 +- metadata/modules/integr8BidAdapter.json | 1 + .../modules/intentIqAnalyticsAdapter.json | 1 + metadata/modules/intentIqIdSystem.json | 23 +- metadata/modules/intenzeBidAdapter.json | 1 + .../modules/interactiveOffersBidAdapter.json | 1 + metadata/modules/invamiaBidAdapter.json | 1 + metadata/modules/invibesBidAdapter.json | 25 +- .../modules/invisiblyAnalyticsAdapter.json | 1 + metadata/modules/ipromBidAdapter.json | 25 +- metadata/modules/iqxBidAdapter.json | 1 + metadata/modules/iqzoneBidAdapter.json | 1 + metadata/modules/ivsBidAdapter.json | 1 + metadata/modules/ixBidAdapter.json | 22 +- metadata/modules/jixieBidAdapter.json | 3 +- metadata/modules/jixieIdSystem.json | 3 +- metadata/modules/justIdSystem.json | 23 +- metadata/modules/justpremiumBidAdapter.json | 14 +- metadata/modules/jwplayerBidAdapter.json | 116 ++++++- metadata/modules/jwplayerRtdProvider.json | 1 + metadata/modules/kargoAnalyticsAdapter.json | 1 + metadata/modules/kargoBidAdapter.json | 18 +- metadata/modules/kimberliteBidAdapter.json | 1 + metadata/modules/kinessoIdSystem.json | 1 + metadata/modules/kiviadsBidAdapter.json | 1 + metadata/modules/koblerBidAdapter.json | 1 + metadata/modules/krushmediaBidAdapter.json | 1 + metadata/modules/kubientBidAdapter.json | 1 + metadata/modules/kueezRtbBidAdapter.json | 21 +- metadata/modules/lane4BidAdapter.json | 1 + metadata/modules/lassoBidAdapter.json | 1 + metadata/modules/leagueMBidAdapter.json | 1 + metadata/modules/lemmaDigitalBidAdapter.json | 1 + metadata/modules/lifestreetBidAdapter.json | 1 + .../modules/limelightDigitalBidAdapter.json | 47 ++- .../modules/liveIntentAnalyticsAdapter.json | 1 + metadata/modules/liveIntentIdSystem.json | 14 +- metadata/modules/liveIntentRtdProvider.json | 14 +- .../modules/livewrappedAnalyticsAdapter.json | 1 + metadata/modules/livewrappedBidAdapter.json | 19 +- metadata/modules/lkqdBidAdapter.json | 1 + metadata/modules/lm_kiviadsBidAdapter.json | 1 + metadata/modules/lmpIdSystem.json | 1 + metadata/modules/locIdSystem.json | 1 + metadata/modules/lockerdomeBidAdapter.json | 1 + metadata/modules/lockrAIMIdSystem.json | 1 + metadata/modules/loganBidAdapter.json | 1 + metadata/modules/logicadBidAdapter.json | 1 + metadata/modules/loglyBidAdapter.json | 1 + metadata/modules/loopmeBidAdapter.json | 21 +- metadata/modules/lotamePanoramaIdSystem.json | 22 +- metadata/modules/loyalBidAdapter.json | 1 + metadata/modules/luceadBidAdapter.json | 1 + metadata/modules/lunamediahbBidAdapter.json | 1 + metadata/modules/luponmediaBidAdapter.json | 30 +- metadata/modules/mabidderBidAdapter.json | 1 + metadata/modules/madsenseBidAdapter.json | 1 + metadata/modules/madvertiseBidAdapter.json | 21 +- metadata/modules/magniteAnalyticsAdapter.json | 1 + metadata/modules/magniteBidAdapter.json | 25 +- metadata/modules/malltvAnalyticsAdapter.json | 1 + metadata/modules/malltvBidAdapter.json | 1 + metadata/modules/mantisBidAdapter.json | 1 + metadata/modules/marsmediaBidAdapter.json | 12 +- metadata/modules/mathildeadsBidAdapter.json | 1 + metadata/modules/matterfullBidAdapter.json | 1 + .../modules/mediaConsortiumBidAdapter.json | 12 +- metadata/modules/mediabramaBidAdapter.json | 1 + metadata/modules/mediaeyesBidAdapter.json | 1 + metadata/modules/mediafilterRtdProvider.json | 1 + metadata/modules/mediaforceBidAdapter.json | 22 +- metadata/modules/mediafuseBidAdapter.json | 24 +- metadata/modules/mediagoBidAdapter.json | 18 +- metadata/modules/mediaimpactBidAdapter.json | 1 + metadata/modules/mediakeysBidAdapter.json | 19 +- .../modules/medianetAnalyticsAdapter.json | 1 + metadata/modules/medianetBidAdapter.json | 41 ++- metadata/modules/medianetRtdProvider.json | 1 + metadata/modules/mediasniperBidAdapter.json | 1 + metadata/modules/mediasquareBidAdapter.json | 13 +- metadata/modules/merkleIdSystem.json | 1 + metadata/modules/mgidBidAdapter.json | 25 +- metadata/modules/mgidRtdProvider.json | 25 +- metadata/modules/mgidXBidAdapter.json | 25 +- metadata/modules/michaoBidAdapter.json | 1 + metadata/modules/microadBidAdapter.json | 1 + metadata/modules/mileBidAdapter.json | 1 + metadata/modules/mileRtdProvider.json | 1 + metadata/modules/minutemediaBidAdapter.json | 23 +- metadata/modules/missenaBidAdapter.json | 18 +- metadata/modules/mobfoxpbBidAdapter.json | 1 + metadata/modules/mobianRtdProvider.json | 12 +- metadata/modules/mobilefuseBidAdapter.json | 1 + metadata/modules/mobkoiAnalyticsAdapter.json | 1 + metadata/modules/mobkoiBidAdapter.json | 15 +- metadata/modules/mobkoiIdSystem.json | 15 +- metadata/modules/movingupBidAdapter.json | 1 + metadata/modules/msftBidAdapter.json | 31 +- metadata/modules/mtcBidAdapter.json | 1 + metadata/modules/mwOpenLinkIdSystem.json | 1 + metadata/modules/my6senseBidAdapter.json | 1 + metadata/modules/mycodemediaBidAdapter.json | 1 + metadata/modules/mygaruIdSystem.json | 1 + metadata/modules/mytargetBidAdapter.json | 1 + metadata/modules/nativeryBidAdapter.json | 16 +- metadata/modules/nativoBidAdapter.json | 19 +- metadata/modules/naveggIdSystem.json | 1 + metadata/modules/netIdSystem.json | 1 + metadata/modules/neuwoRtdProvider.json | 1 + metadata/modules/newspassidBidAdapter.json | 26 +- .../modules/nextMillenniumBidAdapter.json | 16 +- metadata/modules/nextrollBidAdapter.json | 20 +- metadata/modules/nexverseBidAdapter.json | 1 + metadata/modules/nexx360BidAdapter.json | 107 +++++- metadata/modules/nobidAnalyticsAdapter.json | 1 + metadata/modules/nobidBidAdapter.json | 15 +- metadata/modules/nodalsAiRtdProvider.json | 16 +- metadata/modules/novatiqIdSystem.json | 14 +- metadata/modules/ntvagentsBidAdapter.json | 1 + metadata/modules/nubaBidAdapter.json | 1 + metadata/modules/oftmediaRtdProvider.json | 1 + metadata/modules/oguryBidAdapter.json | 18 +- metadata/modules/omnidexBidAdapter.json | 21 +- metadata/modules/omsBidAdapter.json | 16 +- metadata/modules/oneKeyIdSystem.json | 1 + metadata/modules/oneKeyRtdProvider.json | 1 + metadata/modules/onetagBidAdapter.json | 23 +- metadata/modules/onomagicBidAdapter.json | 1 + metadata/modules/ooloAnalyticsAdapter.json | 1 + .../modules/opaMarketplaceBidAdapter.json | 1 + metadata/modules/open8BidAdapter.json | 1 + metadata/modules/openPairIdSystem.json | 1 + metadata/modules/openwebBidAdapter.json | 22 +- metadata/modules/openxBidAdapter.json | 21 +- metadata/modules/operaadsBidAdapter.json | 22 +- metadata/modules/operaadsIdSystem.json | 1 + metadata/modules/oprxBidAdapter.json | 1 + metadata/modules/opscoBidAdapter.json | 1 + metadata/modules/optableRtdProvider.json | 1 + metadata/modules/optidigitalBidAdapter.json | 20 +- metadata/modules/optimeraRtdProvider.json | 1 + metadata/modules/optimonAnalyticsAdapter.json | 1 + metadata/modules/optoutBidAdapter.json | 25 +- metadata/modules/orakiBidAdapter.json | 1 + metadata/modules/orbidderBidAdapter.json | 25 +- metadata/modules/orbitsoftBidAdapter.json | 1 + metadata/modules/otmBidAdapter.json | 1 + metadata/modules/outbrainBidAdapter.json | 24 +- metadata/modules/overtoneRtdProvider.json | 1 + metadata/modules/ownadxBidAdapter.json | 1 + metadata/modules/oxxionAnalyticsAdapter.json | 1 + metadata/modules/oxxionRtdProvider.json | 1 + metadata/modules/ozoneBidAdapter.json | 22 +- metadata/modules/padsquadBidAdapter.json | 1 + metadata/modules/pairIdSystem.json | 24 +- metadata/modules/pangleBidAdapter.json | 1 + metadata/modules/panxoBidAdapter.json | 27 +- metadata/modules/panxoRtdProvider.json | 1 + metadata/modules/performaxBidAdapter.json | 19 +- .../permutiveIdentityManagerIdSystem.json | 3 +- metadata/modules/permutiveRtdProvider.json | 3 +- .../modules/pgamdirectAnalyticsAdapter.json | 1 + metadata/modules/pgamdirectBidAdapter.json | 22 +- metadata/modules/pgamsspBidAdapter.json | 1 + .../modules/pianoDmpAnalyticsAdapter.json | 1 + metadata/modules/pigeoonBidAdapter.json | 1 + metadata/modules/pilotxBidAdapter.json | 1 + metadata/modules/pinkLionBidAdapter.json | 1 + metadata/modules/pixfutureBidAdapter.json | 16 + metadata/modules/playdigoBidAdapter.json | 15 +- metadata/modules/playstreamBidAdapter.json | 1 + metadata/modules/prebid-core.json | 5 +- metadata/modules/prebidServerBidAdapter.json | 1 + metadata/modules/precisoBidAdapter.json | 22 +- metadata/modules/prismaBidAdapter.json | 16 +- metadata/modules/programmaticXBidAdapter.json | 16 +- metadata/modules/programmaticaBidAdapter.json | 1 + metadata/modules/proxistoreBidAdapter.json | 23 +- metadata/modules/pstudioBidAdapter.json | 1 + metadata/modules/pubCircleBidAdapter.json | 1 + metadata/modules/pubProvidedIdSystem.json | 1 + metadata/modules/pubgeniusBidAdapter.json | 1 + metadata/modules/publicGoodBidAdapter.json | 1 + metadata/modules/publinkIdSystem.json | 22 +- metadata/modules/publirBidAdapter.json | 1 + .../modules/pubmaticAnalyticsAdapter.json | 1 + metadata/modules/pubmaticBidAdapter.json | 26 +- metadata/modules/pubmaticIdSystem.json | 26 +- metadata/modules/pubmaticRtdProvider.json | 1 + metadata/modules/pubperfAnalyticsAdapter.json | 1 + metadata/modules/pubriseBidAdapter.json | 1 + .../modules/pubstackAnalyticsAdapter.json | 1 + metadata/modules/pubstackBidAdapter.json | 19 +- metadata/modules/pubwiseAnalyticsAdapter.json | 1 + metadata/modules/pubxBidAdapter.json | 1 + metadata/modules/pubxaiAnalyticsAdapter.json | 1 + metadata/modules/pubxaiRtdProvider.json | 1 + .../modules/pulsepointAnalyticsAdapter.json | 1 + metadata/modules/pulsepointBidAdapter.json | 18 +- metadata/modules/pwbidBidAdapter.json | 1 + metadata/modules/pxyzBidAdapter.json | 1 + metadata/modules/qortexRtdProvider.json | 1 + metadata/modules/qtBidAdapter.json | 1 + metadata/modules/qwarryBidAdapter.json | 1 + metadata/modules/r2b2AnalyticsAdapter.json | 1 + metadata/modules/r2b2BidAdapter.json | 15 +- metadata/modules/rakutenBidAdapter.json | 1 + metadata/modules/raveltechRtdProvider.json | 1 + metadata/modules/raynRtdProvider.json | 1 + metadata/modules/readpeakBidAdapter.json | 27 +- .../modules/reconciliationRtdProvider.json | 1 + metadata/modules/rediadsBidAdapter.json | 1 + metadata/modules/rediadsIdSystem.json | 1 + metadata/modules/redtramBidAdapter.json | 1 + metadata/modules/reklamupBidAdapter.json | 1 + metadata/modules/relaidoBidAdapter.json | 1 + metadata/modules/relayBidAdapter.json | 1 + metadata/modules/relevadRtdProvider.json | 1 + .../modules/relevantAnalyticsAdapter.json | 1 + .../modules/relevantdigitalBidAdapter.json | 20 +- .../modules/relevatehealthBidAdapter.json | 1 + metadata/modules/resetdigitalBidAdapter.json | 31 +- metadata/modules/responsiveAdsBidAdapter.json | 15 +- metadata/modules/retailspotBidAdapter.json | 1 + metadata/modules/revantageBidAdapter.json | 15 +- metadata/modules/revcontentBidAdapter.json | 22 +- metadata/modules/revealonBidAdapter.json | 1 + metadata/modules/revnewBidAdapter.json | 10 +- .../modules/rewardedInterestIdSystem.json | 1 + metadata/modules/rhythmoneBidAdapter.json | 23 +- metadata/modules/richaudienceBidAdapter.json | 18 +- metadata/modules/riseBidAdapter.json | 38 ++- metadata/modules/risemediatechBidAdapter.json | 1 + metadata/modules/rivrAnalyticsAdapter.json | 1 + metadata/modules/rixengineBidAdapter.json | 19 +- metadata/modules/robustAppsBidAdapter.json | 1 + metadata/modules/robustaBidAdapter.json | 1 + metadata/modules/rocketlabBidAdapter.json | 1 + metadata/modules/roxotAnalyticsAdapter.json | 1 + metadata/modules/rtbhouseBidAdapter.json | 18 +- metadata/modules/rtbsapeBidAdapter.json | 1 + metadata/modules/rubiconBidAdapter.json | 25 +- metadata/modules/rumbleBidAdapter.json | 1 + .../modules/scaleableAnalyticsAdapter.json | 1 + metadata/modules/scaliburBidAdapter.json | 27 +- metadata/modules/scatteredBidAdapter.json | 1 + metadata/modules/scope3RtdProvider.json | 1 + metadata/modules/screencoreBidAdapter.json | 18 +- .../modules/seedingAllianceBidAdapter.json | 30 +- metadata/modules/seedtagBidAdapter.json | 20 +- metadata/modules/selectmediaBidAdapter.json | 13 +- metadata/modules/semantiqRtdProvider.json | 24 +- metadata/modules/setupadBidAdapter.json | 25 +- metadata/modules/sevioBidAdapter.json | 22 +- metadata/modules/sharedIdSystem.json | 3 +- .../modules/sharethroughAnalyticsAdapter.json | 1 + metadata/modules/sharethroughBidAdapter.json | 19 +- metadata/modules/shinezBidAdapter.json | 1 + metadata/modules/shinezRtbBidAdapter.json | 1 + metadata/modules/showheroes-bsBidAdapter.json | 24 +- metadata/modules/showheroesBidAdapter.json | 24 +- metadata/modules/silvermobBidAdapter.json | 19 +- metadata/modules/silverpushBidAdapter.json | 1 + metadata/modules/sirdataRtdProvider.json | 28 +- metadata/modules/slimcutBidAdapter.json | 1 + metadata/modules/smaatoBidAdapter.json | 20 +- metadata/modules/smartadserverBidAdapter.json | 19 +- metadata/modules/smarthubBidAdapter.json | 1 + metadata/modules/smarticoBidAdapter.json | 1 + metadata/modules/smartxBidAdapter.json | 21 +- .../modules/smartyadsAnalyticsAdapter.json | 1 + metadata/modules/smartyadsBidAdapter.json | 18 +- metadata/modules/smartytechBidAdapter.json | 1 + metadata/modules/smilewantedBidAdapter.json | 21 +- metadata/modules/smootBidAdapter.json | 1 + metadata/modules/snigelBidAdapter.json | 23 +- metadata/modules/sonaradsBidAdapter.json | 19 +- metadata/modules/sonobiBidAdapter.json | 19 +- metadata/modules/sovrnBidAdapter.json | 18 +- metadata/modules/sparteoBidAdapter.json | 30 +- metadata/modules/ssmasBidAdapter.json | 15 +- metadata/modules/sspBCBidAdapter.json | 28 +- metadata/modules/ssp_genieeBidAdapter.json | 1 + metadata/modules/stackadaptBidAdapter.json | 162 ++++++--- metadata/modules/startioBidAdapter.json | 24 +- metadata/modules/startioIdSystem.json | 24 +- metadata/modules/stnBidAdapter.json | 1 + metadata/modules/stroeerCoreBidAdapter.json | 25 +- metadata/modules/stvBidAdapter.json | 24 +- metadata/modules/sublimeBidAdapter.json | 18 +- metadata/modules/suimBidAdapter.json | 1 + metadata/modules/symitriAnalyticsAdapter.json | 1 + metadata/modules/symitriDapRtdProvider.json | 1 + metadata/modules/taboolaBidAdapter.json | 29 +- metadata/modules/taboolaIdSystem.json | 29 +- metadata/modules/tadvertisingBidAdapter.json | 21 +- metadata/modules/tagorasBidAdapter.json | 1 + metadata/modules/talkadsBidAdapter.json | 1 + metadata/modules/tapadIdSystem.json | 1 + metadata/modules/tapnativeBidAdapter.json | 1 + metadata/modules/tappxBidAdapter.json | 20 +- metadata/modules/targetVideoBidAdapter.json | 17 +- metadata/modules/teadsBidAdapter.json | 21 +- metadata/modules/teadsIdSystem.json | 21 +- metadata/modules/tealBidAdapter.json | 22 +- metadata/modules/temedyaBidAdapter.json | 1 + metadata/modules/teqBlazeDemoBidAdapter.json | 1 + .../modules/teqBlazeSalesAgentBidAdapter.json | 1 + metadata/modules/terceptAnalyticsAdapter.json | 1 + metadata/modules/theAdxBidAdapter.json | 1 + metadata/modules/themoneytizerBidAdapter.json | 1 + metadata/modules/timeoutRtdProvider.json | 1 + metadata/modules/tncIdSystem.json | 25 +- metadata/modules/tne_catalystBidAdapter.json | 22 +- metadata/modules/topicsFpdModule.json | 3 +- metadata/modules/toponBidAdapter.json | 20 +- metadata/modules/tpmnBidAdapter.json | 1 + metadata/modules/trafficgateBidAdapter.json | 1 + metadata/modules/trionBidAdapter.json | 1 + metadata/modules/tripleliftBidAdapter.json | 26 +- metadata/modules/truereachBidAdapter.json | 1 + metadata/modules/trustxBidAdapter.json | 1 + metadata/modules/ttdBidAdapter.json | 24 +- metadata/modules/twistDigitalBidAdapter.json | 24 +- .../modules/ucfunnelAnalyticsAdapter.json | 1 + metadata/modules/ucfunnelBidAdapter.json | 1 + metadata/modules/uid2IdSystem.json | 1 + metadata/modules/underdogmediaBidAdapter.json | 14 +- metadata/modules/undertoneBidAdapter.json | 23 +- metadata/modules/unicornBidAdapter.json | 1 + metadata/modules/unifiedIdSystem.json | 24 +- .../modules/uniquestAnalyticsAdapter.json | 1 + metadata/modules/uniquestBidAdapter.json | 1 + .../modules/uniquest_widgetBidAdapter.json | 1 + metadata/modules/unrulyBidAdapter.json | 23 +- metadata/modules/userId.json | 3 +- metadata/modules/utiqIdSystem.json | 3 +- metadata/modules/utiqMtpIdSystem.json | 3 +- metadata/modules/validationFpdModule.json | 3 +- metadata/modules/valuadBidAdapter.json | 13 +- metadata/modules/vdoaiBidAdapter.json | 1 + metadata/modules/ventesBidAdapter.json | 1 + metadata/modules/verbenBidAdapter.json | 1 + metadata/modules/viantBidAdapter.json | 1 + metadata/modules/vibrantmediaBidAdapter.json | 1 + metadata/modules/vidazooBidAdapter.json | 23 +- metadata/modules/videobyteBidAdapter.json | 1 + metadata/modules/videoheroesBidAdapter.json | 1 + metadata/modules/videonowBidAdapter.json | 1 + metadata/modules/videoreachBidAdapter.json | 1 + metadata/modules/vidoomyBidAdapter.json | 20 +- metadata/modules/viewdeosDXBidAdapter.json | 1 + metadata/modules/viouslyBidAdapter.json | 30 +- metadata/modules/viqeoBidAdapter.json | 1 + .../modules/visiblemeasuresBidAdapter.json | 1 + metadata/modules/vistarsBidAdapter.json | 1 + metadata/modules/visxBidAdapter.json | 24 +- metadata/modules/vlybyBidAdapter.json | 13 +- metadata/modules/voxBidAdapter.json | 25 +- metadata/modules/vrtcalBidAdapter.json | 14 +- metadata/modules/vuukleBidAdapter.json | 30 +- metadata/modules/waardexBidAdapter.json | 1 + metadata/modules/weboramaRtdProvider.json | 32 +- metadata/modules/welectBidAdapter.json | 16 +- metadata/modules/widespaceBidAdapter.json | 1 + metadata/modules/winrBidAdapter.json | 1 + metadata/modules/wipesBidAdapter.json | 1 + metadata/modules/wurflRtdProvider.json | 3 +- metadata/modules/xeBidAdapter.json | 1 + metadata/modules/yahooAdsBidAdapter.json | 24 +- metadata/modules/yaleoBidAdapter.json | 24 +- metadata/modules/yandexAnalyticsAdapter.json | 1 + metadata/modules/yandexBidAdapter.json | 1 + metadata/modules/yandexIdSystem.json | 1 + metadata/modules/yieldlabBidAdapter.json | 19 +- metadata/modules/yieldliftBidAdapter.json | 1 + metadata/modules/yieldloveBidAdapter.json | 22 +- metadata/modules/yieldmoBidAdapter.json | 24 +- .../modules/yieldoneAnalyticsAdapter.json | 1 + metadata/modules/yieldoneBidAdapter.json | 1 + .../modules/yuktamediaAnalyticsAdapter.json | 1 + metadata/modules/zeotapIdPlusIdSystem.json | 18 +- metadata/modules/zeta_globalBidAdapter.json | 22 +- .../zeta_global_sspAnalyticsAdapter.json | 1 + .../modules/zeta_global_sspBidAdapter.json | 22 +- metadata/modules/zmaticooBidAdapter.json | 1 + metadata/storageDisclosure.mjs | 7 +- modules/tcfControl.ts | 99 +++++- plugins/callerContext.js | 10 +- plugins/gvlPurposes.js | 29 ++ plugins/utils.js | 18 + src/consentHandler.ts | 1 + test/build-logic/gvl_spec.mjs | 41 ++- test/spec/modules/tcfControl_spec.js | 314 +++++++++++++++--- 717 files changed, 6929 insertions(+), 587 deletions(-) create mode 100644 libraries/purposeDeclarations/validate.mjs create mode 100644 metadata/modules/acxiomRealIdSystem.json create mode 100644 plugins/gvlPurposes.js diff --git a/babelConfig.js b/babelConfig.js index f813c3f664e..ec528e6ce25 100644 --- a/babelConfig.js +++ b/babelConfig.js @@ -34,6 +34,7 @@ module.exports = function (options = {}) { const plugins = [ [path.resolve(__dirname, './plugins/pbjsGlobals.js'), options], [path.resolve(__dirname, './plugins/callerContext.js'), options], + [path.resolve(__dirname, './plugins/gvlPurposes.js'), options], [useLocal('@babel/plugin-transform-runtime')], ]; return plugins; diff --git a/gulp.precompilation.js b/gulp.precompilation.js index d46674078b8..b498fe7623d 100644 --- a/gulp.precompilation.js +++ b/gulp.precompilation.js @@ -55,6 +55,7 @@ function generateMetadataModules() { function cleanMetadata(file) { const data = JSON.parse(file.contents.toString()) delete data.NOTICE; + delete data.purposes; // directly included in adapter source data.components.forEach(component => { delete component.gvlid; if (component.aliasOf == null) { diff --git a/gulpfile.js b/gulpfile.js index b2e2a61ff99..a83024760f2 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -569,7 +569,7 @@ gulp.task('extract-metadata', function (done) { }) gulp.task('compile-metadata', function (done) { import('./metadata/compileMetadata.mjs').then(({default: compile}) => { - compile().then(() => done(), done); + compile(argv.fetch ?? true).then(() => done(), done); }) }) gulp.task('update-metadata', gulp.series('build', 'extract-metadata', 'compile-metadata')); diff --git a/libraries/purposeDeclarations/validate.mjs b/libraries/purposeDeclarations/validate.mjs new file mode 100644 index 00000000000..0ee11eeb93f --- /dev/null +++ b/libraries/purposeDeclarations/validate.mjs @@ -0,0 +1,13 @@ +// NOTE: this file is used both by the build system and Prebid runtime; the former +// needs the ".mjs" extension, but precompilation transforms this into a "normal" .js + +export function validatePurposeDeclarations({ purposes, legIntPurposes, flexiblePurposes }) { + const bothBases = purposes.concat(legIntPurposes).filter(purpose => purposes.includes(purpose) && legIntPurposes.includes(purpose)); + if (bothBases.length > 0) { + return `declares both consent and LI for purposes ${bothBases.join(', ')}` + } + const noBasis = flexiblePurposes.filter(purpose => !purposes.includes(purpose) && !legIntPurposes.includes(purpose)); + if (noBasis.length > 0) { + return `declares purposes ${noBasis.join(', ')} as flexible, but no legal basis for them` + } +} diff --git a/metadata/compileMetadata.mjs b/metadata/compileMetadata.mjs index 2909a7dc9ec..9ea043eb9d0 100644 --- a/metadata/compileMetadata.mjs +++ b/metadata/compileMetadata.mjs @@ -5,8 +5,9 @@ import moduleMetadata from './modules.json' with {type: 'json'}; import coreMetadata from './core.json' with {type: 'json'}; import overrides from './overrides.mjs'; -import {fetchDisclosure, getDisclosureUrl, logErrorSummary} from './storageDisclosure.mjs'; -import {isValidGvlId} from './gvl.mjs'; +import { fetchDisclosure, getDisclosureUrl, getPublicURL, logErrorSummary } from './storageDisclosure.mjs'; +import { getPurposes, isValidGvlId } from './gvl.mjs'; +import {validatePurposeDeclarations} from '../libraries/purposeDeclarations/validate.mjs'; const MAX_DISCLOSURE_AGE_DAYS = 14; @@ -57,11 +58,40 @@ function previousDisclosure(moduleName, {componentType, componentName, disclosur } }) }) +} + +const EXPECTED_PURPOSES = { + 'userId': [1], + 'bidder': [2], + 'analytics': [7] +} + +const RELEVANT_PURPOSES = [1, 2, 4, 7]; + +const purposeWarnings = []; +const purposeErrors = []; + +function logPurposeMsg(dest, component, gvlid, purposes, msg) { + dest.push(`${component} (GVL ID ${gvlid}) ${msg} (${JSON.stringify(purposes)})`) +} + +function checkPurpose({component, gvlid}, purpose, {legIntPurposes, purposes}) { + if (!purposes.includes(purpose) && !legIntPurposes.includes(purpose)) { + logPurposeMsg(purposeWarnings, component, gvlid, {legIntPurposes, purposes}, `does not declare consent or LI as legal basis for purpose ${purpose}`) + } +} +export function validatePurposes({component, gvlid}, {legIntPurposes, purposes, flexiblePurposes, specialFeatures}) { + RELEVANT_PURPOSES.forEach(purpose => { + if (legIntPurposes.includes(purpose) && !flexiblePurposes.includes(purpose)) { + logPurposeMsg(purposeWarnings, component, gvlid, {purposes, legIntPurposes, flexiblePurposes}, `declares LI only as legal basis for purpose ${purpose}`) + } + }) } -async function metadataFor(moduleName, metas) { +async function metadataFor(moduleName, metas, fetch = true) { const disclosures = {}; + const purposes = {}; for (const meta of metas) { if (meta.disclosureURL == null && meta.gvlid != null) { meta.disclosureURL = await getDisclosureUrl(meta.gvlid); @@ -69,22 +99,38 @@ async function metadataFor(moduleName, metas) { if (meta.disclosureURL) { const disclosure = { timestamp: new Date().toISOString(), - disclosures: await fetchDisclosure(meta) + disclosures: fetch ? await fetchDisclosure(meta) : null }; + meta.disclosureURL = getPublicURL(meta.disclosureURL); if (disclosure.disclosures == null) { Object.assign(disclosure, await previousDisclosure(moduleName, meta)); } disclosures[meta.disclosureURL] = disclosure; } + if (meta.gvlid != null && !purposes.hasOwnProperty(meta.gvlid)) { + purposes[meta.gvlid] = await getPurposes(meta.gvlid) + } } + metas.filter(({gvlid}) => gvlid != null).forEach(({componentType, componentName, gvlid}) => { + (EXPECTED_PURPOSES[componentType] ?? []).forEach(purpose => { + checkPurpose({component: `${componentType}.${componentName}`, gvlid}, purpose, purposes[gvlid]); + }); + const validationError = validatePurposeDeclarations(purposes[gvlid]); + if (validationError) { + logPurposeMsg(purposeErrors, `${componentType}.${componentName}`, purposes[gvlid], validationError); + } + validatePurposes({component: `${componentType}.${componentName}`, gvlid}, purposes[gvlid]); + + }) return { 'NOTICE': 'do not edit - this file is autogenerated by `gulp update-metadata`', disclosures, + purposes, components: metas }; } -async function compileCoreMetadata() { +async function compileCoreMetadata(fetch = true) { const modules = coreMetadata.components.reduce((byModule, item) => { if (!byModule.hasOwnProperty(item.moduleName)) { byModule[item.moduleName] = []; @@ -94,7 +140,7 @@ async function compileCoreMetadata() { return byModule; }, {}); for (let [moduleName, metadata] of Object.entries(modules)) { - await updateModuleMetadata(moduleName, metadata); + await updateModuleMetadata(moduleName, metadata, fetch); } return Object.keys(modules); } @@ -103,10 +149,10 @@ function moduleMetadataPath(moduleName) { return path.resolve(`./metadata/modules/${moduleName}.json`); } -async function updateModuleMetadata(moduleName, metadata) { +async function updateModuleMetadata(moduleName, metadata, fetch = true) { fs.writeFileSync( moduleMetadataPath(moduleName), - JSON.stringify(await metadataFor(moduleName, metadata), null, 2) + JSON.stringify(await metadataFor(moduleName, metadata, fetch), null, 2) ); } @@ -132,7 +178,7 @@ async function validateGvlIds() { } } -async function compileModuleMetadata() { +async function compileModuleMetadata(fetch = true) { const processed = []; const found = new WeakSet(); let err = false; @@ -158,7 +204,7 @@ async function compileModuleMetadata() { console.error('More than one module name matches module file:', moduleName, names); err = true; } else { - await updateModuleMetadata(moduleName, meta); + await updateModuleMetadata(moduleName, meta, fetch); processed.push(moduleName); } } @@ -177,10 +223,19 @@ async function compileModuleMetadata() { } -export default async function compileMetadata() { +export default async function compileMetadata(fetch = true) { await validateGvlIds(); - const allModules = new Set((await compileCoreMetadata()) - .concat(await compileModuleMetadata())); + const allModules = new Set((await compileCoreMetadata(fetch)) + .concat(await compileModuleMetadata(fetch))); + if (purposeWarnings.length > 0) { + console.warn("Some vendors have unexpected purpose declarations:"); + purposeWarnings.forEach(warn => console.warn(` ${warn}`)); + } + if (purposeErrors.length > 0) { + console.error("Some vendors have invalid purpose declarations:"); + purposeErrors.forEach(err => console.error(` ${err}`)); + throw new Error('Some purpose declarations are out of spec') + } logErrorSummary(); fs.readdirSync('./metadata/modules') .map(name => path.parse(name)) diff --git a/metadata/gvl.mjs b/metadata/gvl.mjs index 149a09d79ea..1bf598cfa03 100644 --- a/metadata/gvl.mjs +++ b/metadata/gvl.mjs @@ -20,3 +20,12 @@ export function isValidGvlId(gvlId, gvl = getGvl) { return !!(gvl.vendors[gvlId] && !gvl.vendors[gvlId].deletedDate); }) } + +export function getPurposes(gvlId, gvl = getGvl) { + return gvl().then(gvl => { + const {purposes, legIntPurposes, flexiblePurposes, specialFeatures} = gvl.vendors[gvlId]; + return { + purposes, legIntPurposes, flexiblePurposes, specialFeatures + } + }) +} diff --git a/metadata/modules.json b/metadata/modules.json index 00d78021fe8..0e755f57a52 100644 --- a/metadata/modules.json +++ b/metadata/modules.json @@ -691,7 +691,7 @@ "componentType": "bidder", "componentName": "adnow", "aliasOf": null, - "gvlid": 1210, + "gvlid": null, "disclosureURL": null }, { @@ -1338,13 +1338,6 @@ "gvlid": 32, "disclosureURL": null }, - { - "componentType": "bidder", - "componentName": "oftmedia", - "aliasOf": "appnexus", - "gvlid": 32, - "disclosureURL": null - }, { "componentType": "bidder", "componentName": "adasta", @@ -2175,7 +2168,7 @@ "componentType": "bidder", "componentName": "distroscale", "aliasOf": null, - "gvlid": 754, + "gvlid": null, "disclosureURL": null }, { @@ -3417,6 +3410,13 @@ "gvlid": 32, "disclosureURL": null }, + { + "componentType": "bidder", + "componentName": "oftmedia", + "aliasOf": "msft", + "gvlid": 32, + "disclosureURL": null + }, { "componentType": "bidder", "componentName": "mtc", @@ -5806,6 +5806,13 @@ "disclosureURL": null, "aliasOf": null }, + { + "componentType": "userId", + "componentName": "acxiomRealId", + "gvlid": null, + "disclosureURL": null, + "aliasOf": null + }, { "componentType": "userId", "componentName": "admixerId", diff --git a/metadata/modules/1plusXRtdProvider.json b/metadata/modules/1plusXRtdProvider.json index f761dfac2dd..1b1d163e948 100644 --- a/metadata/modules/1plusXRtdProvider.json +++ b/metadata/modules/1plusXRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/33acrossAnalyticsAdapter.json b/metadata/modules/33acrossAnalyticsAdapter.json index d3ac68259fd..40222c3250d 100644 --- a/metadata/modules/33acrossAnalyticsAdapter.json +++ b/metadata/modules/33acrossAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/33acrossBidAdapter.json b/metadata/modules/33acrossBidAdapter.json index e20d4086224..8247df012b1 100644 --- a/metadata/modules/33acrossBidAdapter.json +++ b/metadata/modules/33acrossBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://platform.33across.com/disclosures.json": { - "timestamp": "2026-05-27T12:17:29.215Z", + "timestamp": "2026-06-02T15:42:53.595Z", "disclosures": [] } }, + "purposes": { + "58": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/33acrossIdSystem.json b/metadata/modules/33acrossIdSystem.json index ad5a9a33c35..781203bb6ec 100644 --- a/metadata/modules/33acrossIdSystem.json +++ b/metadata/modules/33acrossIdSystem.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://platform.33across.com/disclosures.json": { - "timestamp": "2026-05-27T12:17:29.317Z", + "timestamp": "2026-06-02T15:42:53.993Z", "disclosures": [] } }, + "purposes": { + "58": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/360playvidBidAdapter.json b/metadata/modules/360playvidBidAdapter.json index 54cb0ea9b4b..510625476ea 100644 --- a/metadata/modules/360playvidBidAdapter.json +++ b/metadata/modules/360playvidBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/51DegreesRtdProvider.json b/metadata/modules/51DegreesRtdProvider.json index b0c5b9f0e6a..cbb2ac59277 100644 --- a/metadata/modules/51DegreesRtdProvider.json +++ b/metadata/modules/51DegreesRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/AsteriobidPbmAnalyticsAdapter.json b/metadata/modules/AsteriobidPbmAnalyticsAdapter.json index ce3208afcb6..f257d2c3878 100644 --- a/metadata/modules/AsteriobidPbmAnalyticsAdapter.json +++ b/metadata/modules/AsteriobidPbmAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/a1MediaBidAdapter.json b/metadata/modules/a1MediaBidAdapter.json index 0f036b5a2d1..dd83991d271 100644 --- a/metadata/modules/a1MediaBidAdapter.json +++ b/metadata/modules/a1MediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/a1MediaRtdProvider.json b/metadata/modules/a1MediaRtdProvider.json index e07c2220170..9e5b4a4e409 100644 --- a/metadata/modules/a1MediaRtdProvider.json +++ b/metadata/modules/a1MediaRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/a4gBidAdapter.json b/metadata/modules/a4gBidAdapter.json index abbae0b4378..96a81cf3006 100644 --- a/metadata/modules/a4gBidAdapter.json +++ b/metadata/modules/a4gBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/aaxBlockmeterRtdProvider.json b/metadata/modules/aaxBlockmeterRtdProvider.json index 4170821fcf8..0e612db2789 100644 --- a/metadata/modules/aaxBlockmeterRtdProvider.json +++ b/metadata/modules/aaxBlockmeterRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/ablidaBidAdapter.json b/metadata/modules/ablidaBidAdapter.json index ee67b79ecfd..d7f137a250b 100644 --- a/metadata/modules/ablidaBidAdapter.json +++ b/metadata/modules/ablidaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/abtshieldIdSystem.json b/metadata/modules/abtshieldIdSystem.json index b831496b214..4656cf7390c 100644 --- a/metadata/modules/abtshieldIdSystem.json +++ b/metadata/modules/abtshieldIdSystem.json @@ -2,10 +2,38 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d1.abtshield.com/disclosures.json": { - "timestamp": "2026-05-27T12:17:29.319Z", + "timestamp": "2026-06-02T15:42:53.995Z", "disclosures": [] } }, + "purposes": { + "825": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/aceexBidAdapter.json b/metadata/modules/aceexBidAdapter.json index 4bd6be65eba..970d90f6ba0 100644 --- a/metadata/modules/aceexBidAdapter.json +++ b/metadata/modules/aceexBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://aceex.io/tcf.json": { - "timestamp": "2026-05-27T12:17:29.956Z", + "timestamp": "2026-06-02T15:42:55.082Z", "disclosures": [] } }, + "purposes": { + "1387": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/acuityadsBidAdapter.json b/metadata/modules/acuityadsBidAdapter.json index f5a8f863f20..89fde319279 100644 --- a/metadata/modules/acuityadsBidAdapter.json +++ b/metadata/modules/acuityadsBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.acuityads.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:17:30.166Z", + "timestamp": "2026-06-02T15:42:55.609Z", "disclosures": [] } }, + "purposes": { + "231": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/acxiomRealIdSystem.json b/metadata/modules/acxiomRealIdSystem.json new file mode 100644 index 00000000000..b4f12c9b707 --- /dev/null +++ b/metadata/modules/acxiomRealIdSystem.json @@ -0,0 +1,14 @@ +{ + "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", + "disclosures": {}, + "purposes": {}, + "components": [ + { + "componentType": "userId", + "componentName": "acxiomRealId", + "gvlid": null, + "disclosureURL": null, + "aliasOf": null + } + ] +} \ No newline at end of file diff --git a/metadata/modules/ad2ictionBidAdapter.json b/metadata/modules/ad2ictionBidAdapter.json index b6e564d1ea0..1e15a7cf851 100644 --- a/metadata/modules/ad2ictionBidAdapter.json +++ b/metadata/modules/ad2ictionBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adWMGAnalyticsAdapter.json b/metadata/modules/adWMGAnalyticsAdapter.json index 6a377462260..f9ff050b2a3 100644 --- a/metadata/modules/adWMGAnalyticsAdapter.json +++ b/metadata/modules/adWMGAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adWMGBidAdapter.json b/metadata/modules/adWMGBidAdapter.json index f2e0540abea..9d0d9e8dc47 100644 --- a/metadata/modules/adWMGBidAdapter.json +++ b/metadata/modules/adWMGBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adagioAnalyticsAdapter.json b/metadata/modules/adagioAnalyticsAdapter.json index 93c5dbbd55e..0998adff5a2 100644 --- a/metadata/modules/adagioAnalyticsAdapter.json +++ b/metadata/modules/adagioAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adagioBidAdapter.json b/metadata/modules/adagioBidAdapter.json index 27f5327db51..c906531bf05 100644 --- a/metadata/modules/adagioBidAdapter.json +++ b/metadata/modules/adagioBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adagio.io/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:17:30.215Z", + "timestamp": "2026-06-02T15:42:56.002Z", "disclosures": [] } }, + "purposes": { + "617": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adagioRtdProvider.json b/metadata/modules/adagioRtdProvider.json index e6d52808a44..8ec042ea1b4 100644 --- a/metadata/modules/adagioRtdProvider.json +++ b/metadata/modules/adagioRtdProvider.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adagio.io/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:17:30.425Z", + "timestamp": "2026-06-02T15:42:56.341Z", "disclosures": [] } }, + "purposes": { + "617": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/adbroBidAdapter.json b/metadata/modules/adbroBidAdapter.json index c24a36eb2ac..d791e5bb6f1 100644 --- a/metadata/modules/adbroBidAdapter.json +++ b/metadata/modules/adbroBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tag.adbro.me/privacy/devicestorage.json": { - "timestamp": "2026-05-27T12:17:30.425Z", + "timestamp": "2026-06-02T15:42:56.341Z", "disclosures": [] } }, + "purposes": { + "1316": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 7, + 8, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adbutlerBidAdapter.json b/metadata/modules/adbutlerBidAdapter.json index 86b7ab5e52b..5ae5492214c 100644 --- a/metadata/modules/adbutlerBidAdapter.json +++ b/metadata/modules/adbutlerBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adclusterBidAdapter.json b/metadata/modules/adclusterBidAdapter.json index 72d44231bb6..c8a4f1930d7 100644 --- a/metadata/modules/adclusterBidAdapter.json +++ b/metadata/modules/adclusterBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/addefendBidAdapter.json b/metadata/modules/addefendBidAdapter.json index fbb1a91cafc..5bb798cd1c0 100644 --- a/metadata/modules/addefendBidAdapter.json +++ b/metadata/modules/addefendBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.addefend.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:17:30.460Z", + "timestamp": "2026-06-02T15:42:56.640Z", "disclosures": [] } }, + "purposes": { + "539": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adelerateBidAdapter.json b/metadata/modules/adelerateBidAdapter.json index 2e3f06fa6ab..0889ca5276a 100644 --- a/metadata/modules/adelerateBidAdapter.json +++ b/metadata/modules/adelerateBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adfBidAdapter.json b/metadata/modules/adfBidAdapter.json index 24411d54d8d..d72401586fa 100644 --- a/metadata/modules/adfBidAdapter.json +++ b/metadata/modules/adfBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://site.adform.com/assets/devicestorage.json": { - "timestamp": "2026-05-27T12:17:31.287Z", + "timestamp": "2026-06-02T15:42:58.110Z", "disclosures": [] } }, + "purposes": { + "50": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adfusionBidAdapter.json b/metadata/modules/adfusionBidAdapter.json index 4004ccc6f87..895e9c84ef5 100644 --- a/metadata/modules/adfusionBidAdapter.json +++ b/metadata/modules/adfusionBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://spicyrtb.com/static/iab-disclosure.json": { - "timestamp": "2026-05-27T12:17:31.287Z", + "timestamp": "2026-06-02T15:42:58.110Z", "disclosures": [] } }, + "purposes": { + "844": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adgenerationBidAdapter.json b/metadata/modules/adgenerationBidAdapter.json index 0cb6aff6eb0..e906b5f8c3e 100644 --- a/metadata/modules/adgenerationBidAdapter.json +++ b/metadata/modules/adgenerationBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adgridBidAdapter.json b/metadata/modules/adgridBidAdapter.json index 8991b61935b..8a9fcbf4f48 100644 --- a/metadata/modules/adgridBidAdapter.json +++ b/metadata/modules/adgridBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adhashBidAdapter.json b/metadata/modules/adhashBidAdapter.json index 44ce3f735db..493899ac4f1 100644 --- a/metadata/modules/adhashBidAdapter.json +++ b/metadata/modules/adhashBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adheseBidAdapter.json b/metadata/modules/adheseBidAdapter.json index 6fd4cc7a0d3..567e766c71d 100644 --- a/metadata/modules/adheseBidAdapter.json +++ b/metadata/modules/adheseBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adhese.com/deviceStorage.json": { - "timestamp": "2026-05-18T20:03:49.553Z", + "timestamp": "2026-06-02T15:42:59.037Z", "disclosures": [] } }, + "purposes": { + "553": { + "purposes": [ + 1, + 2, + 4, + 6, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adipoloBidAdapter.json b/metadata/modules/adipoloBidAdapter.json index bc224e2c6cd..411f02f59a6 100644 --- a/metadata/modules/adipoloBidAdapter.json +++ b/metadata/modules/adipoloBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adipolo.com/device_storage_disclosure.json": { - "timestamp": "2026-05-18T20:03:50.000Z", + "timestamp": "2026-06-02T15:42:59.750Z", "disclosures": [] } }, + "purposes": { + "1456": { + "purposes": [ + 1, + 2, + 3, + 4, + 8, + 9, + 10 + ], + "legIntPurposes": [ + 7 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adkernelAdnAnalyticsAdapter.json b/metadata/modules/adkernelAdnAnalyticsAdapter.json index d9cd7a18e58..af11591b798 100644 --- a/metadata/modules/adkernelAdnAnalyticsAdapter.json +++ b/metadata/modules/adkernelAdnAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adkernelAdnBidAdapter.json b/metadata/modules/adkernelAdnBidAdapter.json index a274b751c30..347f4296744 100644 --- a/metadata/modules/adkernelAdnBidAdapter.json +++ b/metadata/modules/adkernelAdnBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.adkernel.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:05.688Z", + "timestamp": "2026-06-02T15:43:00.206Z", "disclosures": [ { "identifier": "adk_rtb_conv_id", @@ -17,6 +17,26 @@ ] } }, + "purposes": { + "14": { + "purposes": [ + 1, + 3, + 4, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adkernelBidAdapter.json b/metadata/modules/adkernelBidAdapter.json index ca4bf6e4fd2..e8ea53c4610 100644 --- a/metadata/modules/adkernelBidAdapter.json +++ b/metadata/modules/adkernelBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.adkernel.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:05.738Z", + "timestamp": "2026-06-02T15:43:00.593Z", "disclosures": [ { "identifier": "adk_rtb_conv_id", @@ -17,22 +17,83 @@ ] }, "https://data.converge-digital.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:05.738Z", + "timestamp": "2026-06-02T15:43:00.593Z", "disclosures": [] }, "https://spinx.biz/tcf-spinx.json": { - "timestamp": "2026-05-27T12:18:05.962Z", + "timestamp": "2026-06-02T15:43:01.032Z", "disclosures": [] }, "https://gdpr.memob.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:06.662Z", + "timestamp": "2026-06-02T15:43:01.842Z", "disclosures": [] }, "https://appmonsta.ai/DeviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:18:06.761Z", + "timestamp": "2026-06-02T15:43:02.280Z", "disclosures": [] } }, + "purposes": { + "14": { + "purposes": [ + 1, + 3, + 4, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + }, + "248": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + }, + "1209": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + }, + "1283": { + "purposes": [ + 1 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + }, + "1308": { + "purposes": [], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adlaneRtdProvider.json b/metadata/modules/adlaneRtdProvider.json index f3327726a74..c531a137cc9 100644 --- a/metadata/modules/adlaneRtdProvider.json +++ b/metadata/modules/adlaneRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/adlooxAnalyticsAdapter.json b/metadata/modules/adlooxAnalyticsAdapter.json index 7561ae65b53..00028f87236 100644 --- a/metadata/modules/adlooxAnalyticsAdapter.json +++ b/metadata/modules/adlooxAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adlooxRtdProvider.json b/metadata/modules/adlooxRtdProvider.json index 0d0b1ca000a..1b674c5b739 100644 --- a/metadata/modules/adlooxRtdProvider.json +++ b/metadata/modules/adlooxRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/admaruBidAdapter.json b/metadata/modules/admaruBidAdapter.json index 552c0d8a78c..75fb345ccee 100644 --- a/metadata/modules/admaruBidAdapter.json +++ b/metadata/modules/admaruBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/admaticBidAdapter.json b/metadata/modules/admaticBidAdapter.json index d9f31267986..d659f28b1cf 100644 --- a/metadata/modules/admaticBidAdapter.json +++ b/metadata/modules/admaticBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.admatic.de/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-27T12:18:07.811Z", + "timestamp": "2026-06-02T15:43:04.427Z", "disclosures": [ { "identifier": "px_pbjs", @@ -12,7 +12,7 @@ ] }, "https://adtarget.com.tr/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:07.811Z", + "timestamp": "2026-06-02T15:43:04.427Z", "disclosures": [ { "identifier": "adt_pbjs", @@ -22,6 +22,33 @@ ] } }, + "purposes": { + "779": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + }, + "1281": { + "purposes": [ + 1, + 2 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/admediaBidAdapter.json b/metadata/modules/admediaBidAdapter.json index 8674aa4aca8..a9fa6f54a89 100644 --- a/metadata/modules/admediaBidAdapter.json +++ b/metadata/modules/admediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/admixerBidAdapter.json b/metadata/modules/admixerBidAdapter.json index b5fac8daebb..7f75b4c5e82 100644 --- a/metadata/modules/admixerBidAdapter.json +++ b/metadata/modules/admixerBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admixer.com/tcf.json": { - "timestamp": "2026-05-27T12:18:07.812Z", + "timestamp": "2026-06-02T15:43:04.428Z", "disclosures": [] } }, + "purposes": { + "511": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 7, + 9 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/admixerIdSystem.json b/metadata/modules/admixerIdSystem.json index bb56b549cdb..a0bd2dcde34 100644 --- a/metadata/modules/admixerIdSystem.json +++ b/metadata/modules/admixerIdSystem.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admixer.com/tcf.json": { - "timestamp": "2026-05-27T12:18:08.272Z", + "timestamp": "2026-06-02T15:43:05.348Z", "disclosures": [] } }, + "purposes": { + "511": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 7, + 9 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/adnimationBidAdapter.json b/metadata/modules/adnimationBidAdapter.json index 7bb7fce194e..9a361ad55a5 100644 --- a/metadata/modules/adnimationBidAdapter.json +++ b/metadata/modules/adnimationBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adnowBidAdapter.json b/metadata/modules/adnowBidAdapter.json index 82cdb641292..d86ce51439f 100644 --- a/metadata/modules/adnowBidAdapter.json +++ b/metadata/modules/adnowBidAdapter.json @@ -1,78 +1,14 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", - "disclosures": { - "https://adnow.com/vdsod.json": { - "timestamp": "2026-05-27T12:18:08.272Z", - "disclosures": [ - { - "identifier": "SC_unique_*", - "type": "cookie", - "maxAgeSeconds": 86400, - "cookieRefresh": false, - "purposes": [ - 1, - 2 - ] - }, - { - "identifier": "SC_showNum_*", - "type": "cookie", - "maxAgeSeconds": 86400, - "cookieRefresh": true, - "purposes": [ - 1, - 2 - ] - }, - { - "identifier": "SC_showNumExpires_*", - "type": "cookie", - "maxAgeSeconds": 86400, - "cookieRefresh": true, - "purposes": [ - 1, - 2 - ] - }, - { - "identifier": "SC_showNumV_*", - "type": "cookie", - "maxAgeSeconds": 86400, - "cookieRefresh": true, - "purposes": [ - 1, - 2 - ] - }, - { - "identifier": "SC_showNumVExpires_*", - "type": "cookie", - "maxAgeSeconds": 86400, - "cookieRefresh": true, - "purposes": [ - 1, - 2 - ] - }, - { - "identifier": "SC_dsp_uuid_v3_*", - "type": "cookie", - "maxAgeSeconds": 1209600, - "cookieRefresh": false, - "purposes": [ - 1 - ] - } - ] - } - }, + "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", "componentName": "adnow", "aliasOf": null, - "gvlid": 1210, - "disclosureURL": "https://adnow.com/vdsod.json" + "gvlid": null, + "disclosureURL": null } ] } \ No newline at end of file diff --git a/metadata/modules/adnuntiusAnalyticsAdapter.json b/metadata/modules/adnuntiusAnalyticsAdapter.json index 5e449fdc75c..bdf9b55281c 100644 --- a/metadata/modules/adnuntiusAnalyticsAdapter.json +++ b/metadata/modules/adnuntiusAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adnuntiusBidAdapter.json b/metadata/modules/adnuntiusBidAdapter.json index 5089bb4149d..25352d54bd0 100644 --- a/metadata/modules/adnuntiusBidAdapter.json +++ b/metadata/modules/adnuntiusBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.adnuntius.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:08.534Z", + "timestamp": "2026-06-02T15:43:05.349Z", "disclosures": [ { "identifier": "adn.metaData", @@ -18,6 +18,26 @@ ] } }, + "purposes": { + "855": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adnuntiusRtdProvider.json b/metadata/modules/adnuntiusRtdProvider.json index 9dd74cd4a36..a2347c35f37 100644 --- a/metadata/modules/adnuntiusRtdProvider.json +++ b/metadata/modules/adnuntiusRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.adnuntius.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:08.864Z", + "timestamp": "2026-06-02T15:43:05.987Z", "disclosures": [ { "identifier": "adn.metaData", @@ -18,6 +18,26 @@ ] } }, + "purposes": { + "855": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/adoceanBidAdapter.json b/metadata/modules/adoceanBidAdapter.json index 3e07d220872..66330d8636f 100644 --- a/metadata/modules/adoceanBidAdapter.json +++ b/metadata/modules/adoceanBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gemius.com/media/documents/Gemius_SA_Vendor_Device_Storage.json": { - "timestamp": "2026-05-27T12:18:08.864Z", + "timestamp": "2026-06-02T15:43:05.988Z", "disclosures": [ { "identifier": "__gsyncs_gdpr", @@ -268,6 +268,23 @@ ] } }, + "purposes": { + "328": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adotBidAdapter.json b/metadata/modules/adotBidAdapter.json index da6babeb8eb..446758dd702 100644 --- a/metadata/modules/adotBidAdapter.json +++ b/metadata/modules/adotBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.adotmob.com/tcf/tcf.json": { - "timestamp": "2026-05-27T12:18:09.650Z", + "timestamp": "2026-06-02T15:43:07.086Z", "disclosures": [] } }, + "purposes": { + "272": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adpartnerBidAdapter.json b/metadata/modules/adpartnerBidAdapter.json index 6edd2fcd306..7c3a56994c8 100644 --- a/metadata/modules/adpartnerBidAdapter.json +++ b/metadata/modules/adpartnerBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adplusAnalyticsAdapter.json b/metadata/modules/adplusAnalyticsAdapter.json index 92dc4a0c0d4..aa0ba8ca422 100644 --- a/metadata/modules/adplusAnalyticsAdapter.json +++ b/metadata/modules/adplusAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adplusBidAdapter.json b/metadata/modules/adplusBidAdapter.json index cfe4dd9e392..34a948d019a 100644 --- a/metadata/modules/adplusBidAdapter.json +++ b/metadata/modules/adplusBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adplusIdSystem.json b/metadata/modules/adplusIdSystem.json index 76e88200f0d..0a3250362e6 100644 --- a/metadata/modules/adplusIdSystem.json +++ b/metadata/modules/adplusIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/adponeBidAdapter.json b/metadata/modules/adponeBidAdapter.json index ce1c8f6f6d7..86502583a4c 100644 --- a/metadata/modules/adponeBidAdapter.json +++ b/metadata/modules/adponeBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserver.adpone.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:09.751Z", + "timestamp": "2026-06-02T15:43:07.322Z", "disclosures": [] } }, + "purposes": { + "799": { + "purposes": [ + 1, + 2, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adprimeBidAdapter.json b/metadata/modules/adprimeBidAdapter.json index a18bb1d23d7..89bf77a13d0 100644 --- a/metadata/modules/adprimeBidAdapter.json +++ b/metadata/modules/adprimeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adqueryBidAdapter.json b/metadata/modules/adqueryBidAdapter.json index f1a3ad5c617..f9f1384dd0d 100644 --- a/metadata/modules/adqueryBidAdapter.json +++ b/metadata/modules/adqueryBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.adquery.io/tcf/adQuery.json": { - "timestamp": "2026-05-27T12:18:09.902Z", + "timestamp": "2026-06-02T15:43:07.592Z", "disclosures": [] } }, + "purposes": { + "902": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adqueryIdSystem.json b/metadata/modules/adqueryIdSystem.json index a8b20e4fbc4..56116e499fa 100644 --- a/metadata/modules/adqueryIdSystem.json +++ b/metadata/modules/adqueryIdSystem.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.adquery.io/tcf/adQuery.json": { - "timestamp": "2026-05-27T12:18:10.244Z", + "timestamp": "2026-06-02T15:43:08.274Z", "disclosures": [] } }, + "purposes": { + "902": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/adrelevantisBidAdapter.json b/metadata/modules/adrelevantisBidAdapter.json index 82802aa3793..395a743985f 100644 --- a/metadata/modules/adrelevantisBidAdapter.json +++ b/metadata/modules/adrelevantisBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adrinoBidAdapter.json b/metadata/modules/adrinoBidAdapter.json index 3b71a80623e..12c4b08115d 100644 --- a/metadata/modules/adrinoBidAdapter.json +++ b/metadata/modules/adrinoBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.adrino.cloud/iab/device-storage.json": { - "timestamp": "2026-05-27T12:18:10.245Z", + "timestamp": "2026-06-02T15:43:08.274Z", "disclosures": [] } }, + "purposes": { + "1072": { + "purposes": [ + 2, + 4, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adriverBidAdapter.json b/metadata/modules/adriverBidAdapter.json index a95b6e2a4f8..26dd63a5b94 100644 --- a/metadata/modules/adriverBidAdapter.json +++ b/metadata/modules/adriverBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adriverIdSystem.json b/metadata/modules/adriverIdSystem.json index 65e92d38ede..c0aad2fb8b0 100644 --- a/metadata/modules/adriverIdSystem.json +++ b/metadata/modules/adriverIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/ads_interactiveBidAdapter.json b/metadata/modules/ads_interactiveBidAdapter.json index e263a9aeeac..4664fb8c59f 100644 --- a/metadata/modules/ads_interactiveBidAdapter.json +++ b/metadata/modules/ads_interactiveBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adsinteractive.com/vendor.json": { - "timestamp": "2026-05-27T12:18:10.328Z", + "timestamp": "2026-06-02T15:43:08.566Z", "disclosures": [] } }, + "purposes": { + "1212": { + "purposes": [ + 1, + 2, + 3, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adsmartxBidAdapter.json b/metadata/modules/adsmartxBidAdapter.json index 21ea5dcef03..f04eee0847b 100644 --- a/metadata/modules/adsmartxBidAdapter.json +++ b/metadata/modules/adsmartxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adsmovilBidAdapter.json b/metadata/modules/adsmovilBidAdapter.json index e66f70daa81..0710c37db6e 100644 --- a/metadata/modules/adsmovilBidAdapter.json +++ b/metadata/modules/adsmovilBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adspiritBidAdapter.json b/metadata/modules/adspiritBidAdapter.json index 282a48a4a62..8f1679ca941 100644 --- a/metadata/modules/adspiritBidAdapter.json +++ b/metadata/modules/adspiritBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adstirBidAdapter.json b/metadata/modules/adstirBidAdapter.json index 09affafc6ad..42ba7937361 100644 --- a/metadata/modules/adstirBidAdapter.json +++ b/metadata/modules/adstirBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adtargetBidAdapter.json b/metadata/modules/adtargetBidAdapter.json index 899731be23e..3c1a2a41976 100644 --- a/metadata/modules/adtargetBidAdapter.json +++ b/metadata/modules/adtargetBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtarget.com.tr/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:10.642Z", + "timestamp": "2026-06-02T15:43:09.255Z", "disclosures": [ { "identifier": "adt_pbjs", @@ -12,6 +12,22 @@ ] } }, + "purposes": { + "779": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adtelligentBidAdapter.json b/metadata/modules/adtelligentBidAdapter.json index 9dc3893a9c8..136dcb50c9a 100644 --- a/metadata/modules/adtelligentBidAdapter.json +++ b/metadata/modules/adtelligentBidAdapter.json @@ -2,14 +2,45 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtelligent.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:10.643Z", + "timestamp": "2026-06-02T15:43:09.255Z", "disclosures": [] }, "https://orangeclickmedia.com/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:18:10.660Z", + "timestamp": "2026-06-02T15:43:09.667Z", "disclosures": [] } }, + "purposes": { + "410": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + }, + "1148": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 11 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 8 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adtelligentIdSystem.json b/metadata/modules/adtelligentIdSystem.json index 3f991204ae4..7b2ffd35188 100644 --- a/metadata/modules/adtelligentIdSystem.json +++ b/metadata/modules/adtelligentIdSystem.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adtelligent.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:10.796Z", + "timestamp": "2026-06-02T15:43:09.935Z", "disclosures": [] } }, + "purposes": { + "410": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/adtrgtmeBidAdapter.json b/metadata/modules/adtrgtmeBidAdapter.json index 068738548a6..62b80aaafe5 100644 --- a/metadata/modules/adtrgtmeBidAdapter.json +++ b/metadata/modules/adtrgtmeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adtrueBidAdapter.json b/metadata/modules/adtrueBidAdapter.json index 501b214de2c..90d79d7f4b3 100644 --- a/metadata/modules/adtrueBidAdapter.json +++ b/metadata/modules/adtrueBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/aduptechBidAdapter.json b/metadata/modules/aduptechBidAdapter.json index 7a65ce67ba4..ce9651574b1 100644 --- a/metadata/modules/aduptechBidAdapter.json +++ b/metadata/modules/aduptechBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.d.adup-tech.com/gdpr/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:10.796Z", + "timestamp": "2026-06-02T15:43:09.935Z", "disclosures": [] } }, + "purposes": { + "647": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/advRedAnalyticsAdapter.json b/metadata/modules/advRedAnalyticsAdapter.json index f05bd01d52a..78de91c66ff 100644 --- a/metadata/modules/advRedAnalyticsAdapter.json +++ b/metadata/modules/advRedAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/advangelistsBidAdapter.json b/metadata/modules/advangelistsBidAdapter.json index ee7565ac337..2a6dc36f1f7 100644 --- a/metadata/modules/advangelistsBidAdapter.json +++ b/metadata/modules/advangelistsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/advertisingBidAdapter.json b/metadata/modules/advertisingBidAdapter.json index 99d357e2b8f..cd64202fb2e 100644 --- a/metadata/modules/advertisingBidAdapter.json +++ b/metadata/modules/advertisingBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adverxoBidAdapter.json b/metadata/modules/adverxoBidAdapter.json index e3cec5f59de..efd221d69a9 100644 --- a/metadata/modules/adverxoBidAdapter.json +++ b/metadata/modules/adverxoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adxcgAnalyticsAdapter.json b/metadata/modules/adxcgAnalyticsAdapter.json index a9d0f3286ed..c98c0f4d18c 100644 --- a/metadata/modules/adxcgAnalyticsAdapter.json +++ b/metadata/modules/adxcgAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adxcgBidAdapter.json b/metadata/modules/adxcgBidAdapter.json index 97481c5829e..16685c048da 100644 --- a/metadata/modules/adxcgBidAdapter.json +++ b/metadata/modules/adxcgBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/adxpremiumAnalyticsAdapter.json b/metadata/modules/adxpremiumAnalyticsAdapter.json index 4f0ecb7effb..d46b53445b0 100644 --- a/metadata/modules/adxpremiumAnalyticsAdapter.json +++ b/metadata/modules/adxpremiumAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/adyoulikeBidAdapter.json b/metadata/modules/adyoulikeBidAdapter.json index f8a327fd4c0..4c89e6084b8 100644 --- a/metadata/modules/adyoulikeBidAdapter.json +++ b/metadata/modules/adyoulikeBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adyoulike.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-27T12:18:10.854Z", + "timestamp": "2026-06-02T15:43:10.446Z", "disclosures": [] } }, + "purposes": { + "259": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/afpBidAdapter.json b/metadata/modules/afpBidAdapter.json index 3ffe9d26ffa..2be30a0b938 100644 --- a/metadata/modules/afpBidAdapter.json +++ b/metadata/modules/afpBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/agenticAudienceRtdProvider.json b/metadata/modules/agenticAudienceRtdProvider.json index 2eab4d92d64..db2e9d2cb43 100644 --- a/metadata/modules/agenticAudienceRtdProvider.json +++ b/metadata/modules/agenticAudienceRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/agmaAnalyticsAdapter.json b/metadata/modules/agmaAnalyticsAdapter.json index a79d93be0e7..e5a73a005b4 100644 --- a/metadata/modules/agmaAnalyticsAdapter.json +++ b/metadata/modules/agmaAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/aidemBidAdapter.json b/metadata/modules/aidemBidAdapter.json index b6577ae755d..87de70ee42c 100644 --- a/metadata/modules/aidemBidAdapter.json +++ b/metadata/modules/aidemBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/airgridRtdProvider.json b/metadata/modules/airgridRtdProvider.json index aa5631a9a02..c77c9487a53 100644 --- a/metadata/modules/airgridRtdProvider.json +++ b/metadata/modules/airgridRtdProvider.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.wearemiq.com/privacy-and-compliance/devicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:18:11.439Z", + "timestamp": "2026-06-02T15:43:11.441Z", "disclosures": [] } }, + "purposes": { + "101": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/ajaBidAdapter.json b/metadata/modules/ajaBidAdapter.json index eab9d7e911e..0ae945d8fa1 100644 --- a/metadata/modules/ajaBidAdapter.json +++ b/metadata/modules/ajaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/akceloBidAdapter.json b/metadata/modules/akceloBidAdapter.json index a14c5fe275d..e3badd05a71 100644 --- a/metadata/modules/akceloBidAdapter.json +++ b/metadata/modules/akceloBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/alkimiBidAdapter.json b/metadata/modules/alkimiBidAdapter.json index 334f02524e8..d59f931e2a2 100644 --- a/metadata/modules/alkimiBidAdapter.json +++ b/metadata/modules/alkimiBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d1xjh92lb8fey3.cloudfront.net/tcf/alkimi_exchange_tcf.json": { - "timestamp": "2026-05-27T12:18:11.580Z", + "timestamp": "2026-06-02T15:43:11.723Z", "disclosures": [] } }, + "purposes": { + "1169": { + "purposes": [ + 1, + 3, + 4, + 5, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/allegroBidAdapter.json b/metadata/modules/allegroBidAdapter.json index 9a2fe9cd1fb..f8bad2b098d 100644 --- a/metadata/modules/allegroBidAdapter.json +++ b/metadata/modules/allegroBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.allegrostatic.com/dsp-tcf-external/device-storage.json": { - "timestamp": "2026-05-27T12:18:11.956Z", + "timestamp": "2026-06-02T15:43:12.488Z", "disclosures": [] } }, + "purposes": { + "1493": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/alliance_gravityBidAdapter.json b/metadata/modules/alliance_gravityBidAdapter.json index 0f793ebb5f9..cf4c3f37a54 100644 --- a/metadata/modules/alliance_gravityBidAdapter.json +++ b/metadata/modules/alliance_gravityBidAdapter.json @@ -6,6 +6,21 @@ "disclosures": [] } }, + "purposes": { + "501": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/alvadsBidAdapter.json b/metadata/modules/alvadsBidAdapter.json index c7e7f306402..2bb54b8d3b6 100644 --- a/metadata/modules/alvadsBidAdapter.json +++ b/metadata/modules/alvadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ampliffyBidAdapter.json b/metadata/modules/ampliffyBidAdapter.json index a21bb52099f..2a8163464ca 100644 --- a/metadata/modules/ampliffyBidAdapter.json +++ b/metadata/modules/ampliffyBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/amxBidAdapter.json b/metadata/modules/amxBidAdapter.json index 81868e6e09a..d15b3101b23 100644 --- a/metadata/modules/amxBidAdapter.json +++ b/metadata/modules/amxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.a-mo.net/tcf/device-storage.json": { - "timestamp": "2026-05-27T12:18:12.967Z", + "timestamp": "2026-06-02T15:43:17.826Z", "disclosures": [ { "identifier": "amuid2", @@ -43,6 +43,19 @@ ] } }, + "purposes": { + "737": { + "purposes": [ + 1, + 2, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/amxIdSystem.json b/metadata/modules/amxIdSystem.json index 6105e7a2bdd..40c58d1e9c8 100644 --- a/metadata/modules/amxIdSystem.json +++ b/metadata/modules/amxIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.a-mo.net/tcf/device-storage.json": { - "timestamp": "2026-05-27T12:18:13.076Z", + "timestamp": "2026-06-02T15:43:18.167Z", "disclosures": [ { "identifier": "amuid2", @@ -43,6 +43,19 @@ ] } }, + "purposes": { + "737": { + "purposes": [ + 1, + 2, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/aniviewBidAdapter.json b/metadata/modules/aniviewBidAdapter.json index 7cee4d2e888..b03a6b01bae 100644 --- a/metadata/modules/aniviewBidAdapter.json +++ b/metadata/modules/aniviewBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://player.aniview.com/gdpr/gdpr.json": { - "timestamp": "2026-05-27T12:18:13.076Z", + "timestamp": "2026-06-02T15:43:18.167Z", "disclosures": [ { "identifier": "av_*", @@ -18,6 +18,24 @@ ] } }, + "purposes": { + "780": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/anonymisedRtdProvider.json b/metadata/modules/anonymisedRtdProvider.json index 0ad41428f58..ae64ed6ff47 100644 --- a/metadata/modules/anonymisedRtdProvider.json +++ b/metadata/modules/anonymisedRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn1.anonymised.io/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:13.226Z", + "timestamp": "2026-06-02T15:43:18.531Z", "disclosures": [ { "identifier": "oidc.user*", @@ -62,6 +62,22 @@ ] } }, + "purposes": { + "1116": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/anyclipBidAdapter.json b/metadata/modules/anyclipBidAdapter.json index 6c23cf83add..b13cda59941 100644 --- a/metadata/modules/anyclipBidAdapter.json +++ b/metadata/modules/anyclipBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/anzuDSPBidAdapter.json b/metadata/modules/anzuDSPBidAdapter.json index ced13a64540..3b47a116f2a 100644 --- a/metadata/modules/anzuDSPBidAdapter.json +++ b/metadata/modules/anzuDSPBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/anzuSSPBidAdapter.json b/metadata/modules/anzuSSPBidAdapter.json index ae7cbc0f9ef..a58dd39eb37 100644 --- a/metadata/modules/anzuSSPBidAdapter.json +++ b/metadata/modules/anzuSSPBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/apacdexBidAdapter.json b/metadata/modules/apacdexBidAdapter.json index 501814779f2..6193faca4e4 100644 --- a/metadata/modules/apacdexBidAdapter.json +++ b/metadata/modules/apacdexBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/apesterBidAdapter.json b/metadata/modules/apesterBidAdapter.json index 2cb3747c47e..7695106d35e 100644 --- a/metadata/modules/apesterBidAdapter.json +++ b/metadata/modules/apesterBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apester.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:13.652Z", + "timestamp": "2026-06-02T15:43:18.977Z", "disclosures": [] } }, + "purposes": { + "354": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/appMonstaMediaBidAdapter.json b/metadata/modules/appMonstaMediaBidAdapter.json index 1b2449a2d60..791ee6ae20f 100644 --- a/metadata/modules/appMonstaMediaBidAdapter.json +++ b/metadata/modules/appMonstaMediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/appStockSSPBidAdapter.json b/metadata/modules/appStockSSPBidAdapter.json index 95401963f4b..7138ef3adb8 100644 --- a/metadata/modules/appStockSSPBidAdapter.json +++ b/metadata/modules/appStockSSPBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://app-stock.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:13.743Z", + "timestamp": "2026-06-02T15:43:19.359Z", "disclosures": [] } }, + "purposes": { + "1223": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/appierAnalyticsAdapter.json b/metadata/modules/appierAnalyticsAdapter.json index e231a8fdb82..6807418c839 100644 --- a/metadata/modules/appierAnalyticsAdapter.json +++ b/metadata/modules/appierAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/appierBidAdapter.json b/metadata/modules/appierBidAdapter.json index b27b418ac70..9b755798a7e 100644 --- a/metadata/modules/appierBidAdapter.json +++ b/metadata/modules/appierBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.appier.com/deviceStorage2025.json": { - "timestamp": "2026-05-27T12:18:13.907Z", + "timestamp": "2026-06-02T15:43:19.725Z", "disclosures": [ { "identifier": "_atrk_ssid", @@ -238,6 +238,33 @@ ] } }, + "purposes": { + "728": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 11 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/appnexusBidAdapter.json b/metadata/modules/appnexusBidAdapter.json index 4b977e723a9..683e6d4a16f 100644 --- a/metadata/modules/appnexusBidAdapter.json +++ b/metadata/modules/appnexusBidAdapter.json @@ -2,22 +2,82 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:18:14.276Z", + "timestamp": "2026-06-02T15:43:20.977Z", "disclosures": [] }, "https://beintoo-support.b-cdn.net/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:14.056Z", + "timestamp": "2026-06-02T15:43:20.294Z", "disclosures": [] }, "https://projectagora.net/1032_deviceStorageDisclosure.json": { - "timestamp": "2026-05-18T20:04:01.198Z", - "disclosures": [] + "timestamp": "2026-06-02T15:43:20.683Z", + "disclosures": null }, "https://adzymic.com/tcf.json": { - "timestamp": "2026-05-27T12:18:14.276Z", + "timestamp": "2026-06-02T15:43:20.977Z", "disclosures": [] } }, + "purposes": { + "32": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + }, + "618": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + }, + "723": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + }, + "1032": { + "purposes": [ + 1, + 7, + 8 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", @@ -68,13 +128,6 @@ "gvlid": 32, "disclosureURL": "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json" }, - { - "componentType": "bidder", - "componentName": "oftmedia", - "aliasOf": "appnexus", - "gvlid": 32, - "disclosureURL": "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json" - }, { "componentType": "bidder", "componentName": "adasta", diff --git a/metadata/modules/appushBidAdapter.json b/metadata/modules/appushBidAdapter.json index 306dea4f699..838045e5908 100644 --- a/metadata/modules/appushBidAdapter.json +++ b/metadata/modules/appushBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.thebiding.com/disclosures.json": { - "timestamp": "2026-05-27T12:18:14.359Z", + "timestamp": "2026-06-02T15:43:21.191Z", "disclosures": [] } }, + "purposes": { + "879": { + "purposes": [ + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/apsBidAdapter.json b/metadata/modules/apsBidAdapter.json index d8be8eca34f..694c96b09d8 100644 --- a/metadata/modules/apsBidAdapter.json +++ b/metadata/modules/apsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://m.media-amazon.com/images/G/01/adprefs/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:18:14.500Z", + "timestamp": "2026-06-02T15:43:21.704Z", "disclosures": [ { "identifier": "vendor-id", @@ -40,6 +40,27 @@ ] } }, + "purposes": { + "793": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/apstreamBidAdapter.json b/metadata/modules/apstreamBidAdapter.json index 5a48736f3af..5fa61b9cb3e 100644 --- a/metadata/modules/apstreamBidAdapter.json +++ b/metadata/modules/apstreamBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sak.userreport.com/tcf.json": { - "timestamp": "2026-05-27T12:18:14.598Z", + "timestamp": "2026-06-02T15:43:21.946Z", "disclosures": [ { "identifier": "apr_dsu", @@ -81,6 +81,30 @@ ] } }, + "purposes": { + "394": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/arcspanRtdProvider.json b/metadata/modules/arcspanRtdProvider.json index 3e4f7b737f5..87b8c00d3f1 100644 --- a/metadata/modules/arcspanRtdProvider.json +++ b/metadata/modules/arcspanRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/asealBidAdapter.json b/metadata/modules/asealBidAdapter.json index 719c755bb33..471674c705e 100644 --- a/metadata/modules/asealBidAdapter.json +++ b/metadata/modules/asealBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/asoBidAdapter.json b/metadata/modules/asoBidAdapter.json index 556f7a02ace..e1f6bbc452d 100644 --- a/metadata/modules/asoBidAdapter.json +++ b/metadata/modules/asoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/asterioBidAdapter.json b/metadata/modules/asterioBidAdapter.json index e64fe7d0f5c..d2c2edb6567 100644 --- a/metadata/modules/asterioBidAdapter.json +++ b/metadata/modules/asterioBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/asteriobidAnalyticsAdapter.json b/metadata/modules/asteriobidAnalyticsAdapter.json index cdd07141659..46dcc9757a0 100644 --- a/metadata/modules/asteriobidAnalyticsAdapter.json +++ b/metadata/modules/asteriobidAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/astraoneBidAdapter.json b/metadata/modules/astraoneBidAdapter.json index 0d5bb0d2685..63543842894 100644 --- a/metadata/modules/astraoneBidAdapter.json +++ b/metadata/modules/astraoneBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/atsAnalyticsAdapter.json b/metadata/modules/atsAnalyticsAdapter.json index 09e9750aea8..b967c392232 100644 --- a/metadata/modules/atsAnalyticsAdapter.json +++ b/metadata/modules/atsAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/audiencerunBidAdapter.json b/metadata/modules/audiencerunBidAdapter.json index 4747a0fda9f..6a7ef140d8a 100644 --- a/metadata/modules/audiencerunBidAdapter.json +++ b/metadata/modules/audiencerunBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.audiencerun.com/tcf.json": { - "timestamp": "2026-05-27T12:18:14.849Z", + "timestamp": "2026-06-02T15:43:22.166Z", "disclosures": [] } }, + "purposes": { + "944": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/automatadAnalyticsAdapter.json b/metadata/modules/automatadAnalyticsAdapter.json index c92f4dad3de..2833d3d08a7 100644 --- a/metadata/modules/automatadAnalyticsAdapter.json +++ b/metadata/modules/automatadAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/automatadBidAdapter.json b/metadata/modules/automatadBidAdapter.json index 52227a79b0a..31abb83d6ba 100644 --- a/metadata/modules/automatadBidAdapter.json +++ b/metadata/modules/automatadBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/axisBidAdapter.json b/metadata/modules/axisBidAdapter.json index 7157daf1365..0763ce8216a 100644 --- a/metadata/modules/axisBidAdapter.json +++ b/metadata/modules/axisBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://axis-marketplace.com/tcf.json": { - "timestamp": "2026-05-27T12:18:15.005Z", + "timestamp": "2026-06-02T15:43:22.523Z", "disclosures": [] } }, + "purposes": { + "1197": { + "purposes": [ + 1, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [ + 8, + 9, + 11 + ], + "flexiblePurposes": [ + 9 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/axonixBidAdapter.json b/metadata/modules/axonixBidAdapter.json index 0db1e8e9a19..b5fdbe932ed 100644 --- a/metadata/modules/axonixBidAdapter.json +++ b/metadata/modules/axonixBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/azerionedgeRtdProvider.json b/metadata/modules/azerionedgeRtdProvider.json index b1712b7b2d9..f6121a4c776 100644 --- a/metadata/modules/azerionedgeRtdProvider.json +++ b/metadata/modules/azerionedgeRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sellers.improvedigital.com/tcf-cookies.json": { - "timestamp": "2026-05-27T12:18:15.053Z", + "timestamp": "2026-06-02T15:43:23.049Z", "disclosures": [ { "identifier": "tuuid", @@ -133,6 +133,29 @@ ] } }, + "purposes": { + "253": { + "purposes": [ + 1, + 3, + 4, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/beachfrontBidAdapter.json b/metadata/modules/beachfrontBidAdapter.json index 45feaffc826..d701e87d7ab 100644 --- a/metadata/modules/beachfrontBidAdapter.json +++ b/metadata/modules/beachfrontBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.seedtag.com/vendor.json": { - "timestamp": "2026-05-27T12:18:15.361Z", + "timestamp": "2026-06-02T15:43:23.285Z", "disclosures": [] } }, + "purposes": { + "157": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bedigitechBidAdapter.json b/metadata/modules/bedigitechBidAdapter.json index 2da5c96e03b..285f9e77bd1 100644 --- a/metadata/modules/bedigitechBidAdapter.json +++ b/metadata/modules/bedigitechBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/beopBidAdapter.json b/metadata/modules/beopBidAdapter.json index 6e2e5f7f358..9a7c3c52057 100644 --- a/metadata/modules/beopBidAdapter.json +++ b/metadata/modules/beopBidAdapter.json @@ -2,10 +2,38 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://beop.collectiveaudience.co/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:15.505Z", + "timestamp": "2026-06-02T15:43:23.778Z", "disclosures": [] } }, + "purposes": { + "666": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8 + ], + "legIntPurposes": [ + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/betweenBidAdapter.json b/metadata/modules/betweenBidAdapter.json index 1e1b0e8e60b..749748d0948 100644 --- a/metadata/modules/betweenBidAdapter.json +++ b/metadata/modules/betweenBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://en.betweenx.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:15.677Z", + "timestamp": "2026-06-02T15:43:24.144Z", "disclosures": [] } }, + "purposes": { + "724": { + "purposes": [ + 1, + 9 + ], + "legIntPurposes": [ + 7, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/beyondmediaBidAdapter.json b/metadata/modules/beyondmediaBidAdapter.json index d19ff3231a5..b671e499a4f 100644 --- a/metadata/modules/beyondmediaBidAdapter.json +++ b/metadata/modules/beyondmediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/biddoBidAdapter.json b/metadata/modules/biddoBidAdapter.json index 9f8386e04ba..0877b92ffa1 100644 --- a/metadata/modules/biddoBidAdapter.json +++ b/metadata/modules/biddoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bidfuseBidAdapter.json b/metadata/modules/bidfuseBidAdapter.json index 4b928a42a77..41f10a780c0 100644 --- a/metadata/modules/bidfuseBidAdapter.json +++ b/metadata/modules/bidfuseBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bidfuse.com/disclosure.json": { - "timestamp": "2026-05-27T12:18:15.822Z", + "timestamp": "2026-06-02T15:43:24.689Z", "disclosures": [] } }, + "purposes": { + "1466": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bidglassBidAdapter.json b/metadata/modules/bidglassBidAdapter.json index fb4142cb8ca..bfd20d0e60e 100644 --- a/metadata/modules/bidglassBidAdapter.json +++ b/metadata/modules/bidglassBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bidmaticBidAdapter.json b/metadata/modules/bidmaticBidAdapter.json index c8ec29ed705..244bac77836 100644 --- a/metadata/modules/bidmaticBidAdapter.json +++ b/metadata/modules/bidmaticBidAdapter.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bidmatic.io/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:18.434Z", + "timestamp": "2026-06-02T15:43:25.252Z", "disclosures": [] } }, + "purposes": { + "1134": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bidscubeBidAdapter.json b/metadata/modules/bidscubeBidAdapter.json index 7cb1d0bfa42..f1a086d3adb 100644 --- a/metadata/modules/bidscubeBidAdapter.json +++ b/metadata/modules/bidscubeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bidtheatreBidAdapter.json b/metadata/modules/bidtheatreBidAdapter.json index 5d4a1191b43..da1e185d575 100644 --- a/metadata/modules/bidtheatreBidAdapter.json +++ b/metadata/modules/bidtheatreBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.bidtheatre.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:18.488Z", + "timestamp": "2026-06-02T15:43:25.806Z", "disclosures": [] } }, + "purposes": { + "30": { + "purposes": [ + 1, + 3, + 4, + 7 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/big-richmediaBidAdapter.json b/metadata/modules/big-richmediaBidAdapter.json index d5c7888c7a9..83da3628877 100644 --- a/metadata/modules/big-richmediaBidAdapter.json +++ b/metadata/modules/big-richmediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/billow_rtb25BidAdapter.json b/metadata/modules/billow_rtb25BidAdapter.json index aaa6b7ad431..8669134e519 100644 --- a/metadata/modules/billow_rtb25BidAdapter.json +++ b/metadata/modules/billow_rtb25BidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bitmediaBidAdapter.json b/metadata/modules/bitmediaBidAdapter.json index 24beaea7ae8..ce84744b354 100644 --- a/metadata/modules/bitmediaBidAdapter.json +++ b/metadata/modules/bitmediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/blastoBidAdapter.json b/metadata/modules/blastoBidAdapter.json index 3e9396578c3..343bef4d2e3 100644 --- a/metadata/modules/blastoBidAdapter.json +++ b/metadata/modules/blastoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bliinkBidAdapter.json b/metadata/modules/bliinkBidAdapter.json index d3ba2675bcf..d96019c323e 100644 --- a/metadata/modules/bliinkBidAdapter.json +++ b/metadata/modules/bliinkBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/blockthroughBidAdapter.json b/metadata/modules/blockthroughBidAdapter.json index de062103b1b..11fe3a80d19 100644 --- a/metadata/modules/blockthroughBidAdapter.json +++ b/metadata/modules/blockthroughBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://blockthrough.com/tcf_disclosures.json": { - "timestamp": "2026-05-27T12:18:18.781Z", + "timestamp": "2026-06-02T15:43:26.424Z", "disclosures": [ { "identifier": "BT_AA_DETECTION", @@ -322,6 +322,27 @@ ] } }, + "purposes": { + "815": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/blueBidAdapter.json b/metadata/modules/blueBidAdapter.json index 6858b1b75af..403205fd9a9 100644 --- a/metadata/modules/blueBidAdapter.json +++ b/metadata/modules/blueBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://getblue.io/iab/iab.json": { - "timestamp": "2026-05-27T12:18:18.916Z", + "timestamp": "2026-06-02T15:43:26.847Z", "disclosures": null } }, + "purposes": { + "620": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/blueconicRtdProvider.json b/metadata/modules/blueconicRtdProvider.json index 739413e7b21..32802bff3ee 100644 --- a/metadata/modules/blueconicRtdProvider.json +++ b/metadata/modules/blueconicRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/bmsBidAdapter.json b/metadata/modules/bmsBidAdapter.json index 8b1ae8bbcdd..287667b8eb0 100644 --- a/metadata/modules/bmsBidAdapter.json +++ b/metadata/modules/bmsBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bluems.com/iab.json": { - "timestamp": "2026-05-27T12:18:19.441Z", + "timestamp": "2026-06-02T15:43:29.478Z", "disclosures": [] } }, + "purposes": { + "1105": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bmtmBidAdapter.json b/metadata/modules/bmtmBidAdapter.json index eeed7ab1d80..91fb0f6b9f6 100644 --- a/metadata/modules/bmtmBidAdapter.json +++ b/metadata/modules/bmtmBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/boldwinBidAdapter.json b/metadata/modules/boldwinBidAdapter.json index 5596dd44500..30809ebb7da 100644 --- a/metadata/modules/boldwinBidAdapter.json +++ b/metadata/modules/boldwinBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://magav.videowalldirect.com/iab/videowalldirectiab.json": { - "timestamp": "2026-05-27T12:18:19.541Z", + "timestamp": "2026-06-02T15:43:29.754Z", "disclosures": [] } }, + "purposes": { + "1151": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/brainxBidAdapter.json b/metadata/modules/brainxBidAdapter.json index 1b0a2960ab1..755b5693430 100644 --- a/metadata/modules/brainxBidAdapter.json +++ b/metadata/modules/brainxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/brandmetricsRtdProvider.json b/metadata/modules/brandmetricsRtdProvider.json index a87f0cc021a..7d11d5d4619 100644 --- a/metadata/modules/brandmetricsRtdProvider.json +++ b/metadata/modules/brandmetricsRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/braveBidAdapter.json b/metadata/modules/braveBidAdapter.json index c4a749177ff..3755f9a4337 100644 --- a/metadata/modules/braveBidAdapter.json +++ b/metadata/modules/braveBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bridBidAdapter.json b/metadata/modules/bridBidAdapter.json index 8d742f5c84f..6cf6191e856 100644 --- a/metadata/modules/bridBidAdapter.json +++ b/metadata/modules/bridBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://target-video.com/vendors-device-storage-and-operational-disclosures.json": { - "timestamp": "2026-05-27T12:18:19.811Z", + "timestamp": "2026-06-02T15:43:30.107Z", "disclosures": [ { "identifier": "brid_location", @@ -112,6 +112,21 @@ ] } }, + "purposes": { + "786": { + "purposes": [ + 1, + 2, + 4, + 7, + 8, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/bridgewellBidAdapter.json b/metadata/modules/bridgewellBidAdapter.json index 018eba9dc33..d2b2d462c29 100644 --- a/metadata/modules/bridgewellBidAdapter.json +++ b/metadata/modules/bridgewellBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/browsiAnalyticsAdapter.json b/metadata/modules/browsiAnalyticsAdapter.json index 19dea91a5a1..3518beca325 100644 --- a/metadata/modules/browsiAnalyticsAdapter.json +++ b/metadata/modules/browsiAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/browsiBidAdapter.json b/metadata/modules/browsiBidAdapter.json index 11d4b18d696..7150260a6ca 100644 --- a/metadata/modules/browsiBidAdapter.json +++ b/metadata/modules/browsiBidAdapter.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.browsiprod.com/ads/tcf.json": { - "timestamp": "2026-05-27T12:18:20.102Z", + "timestamp": "2026-06-02T15:43:31.110Z", "disclosures": [] } }, + "purposes": { + "329": { + "purposes": [ + 1, + 7, + 8 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/browsiRtdProvider.json b/metadata/modules/browsiRtdProvider.json index bc1e801e40f..3597c4ddaff 100644 --- a/metadata/modules/browsiRtdProvider.json +++ b/metadata/modules/browsiRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/bucksenseBidAdapter.json b/metadata/modules/bucksenseBidAdapter.json index e7415ea979f..0afcf15d9a6 100644 --- a/metadata/modules/bucksenseBidAdapter.json +++ b/metadata/modules/bucksenseBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://j.bksnimages.com/iab/devsto03.json": { - "timestamp": "2026-05-27T12:18:20.193Z", + "timestamp": "2026-06-02T15:43:31.293Z", "disclosures": [] } }, + "purposes": { + "235": { + "purposes": [ + 1, + 2, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 9 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/buzzoolaBidAdapter.json b/metadata/modules/buzzoolaBidAdapter.json index 97390fc2638..ac5dfe7b04f 100644 --- a/metadata/modules/buzzoolaBidAdapter.json +++ b/metadata/modules/buzzoolaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/byDataAnalyticsAdapter.json b/metadata/modules/byDataAnalyticsAdapter.json index 84a4dcc7ffb..f3496ed1664 100644 --- a/metadata/modules/byDataAnalyticsAdapter.json +++ b/metadata/modules/byDataAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/c1xBidAdapter.json b/metadata/modules/c1xBidAdapter.json index 5418f8a5cc4..2b9f61218b5 100644 --- a/metadata/modules/c1xBidAdapter.json +++ b/metadata/modules/c1xBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/cadent_aperture_mxBidAdapter.json b/metadata/modules/cadent_aperture_mxBidAdapter.json index f61828675e8..e755cd4a11b 100644 --- a/metadata/modules/cadent_aperture_mxBidAdapter.json +++ b/metadata/modules/cadent_aperture_mxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/carodaBidAdapter.json b/metadata/modules/carodaBidAdapter.json index e27a5838f49..68a91ec1a5c 100644 --- a/metadata/modules/carodaBidAdapter.json +++ b/metadata/modules/carodaBidAdapter.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn2.caroda.io/tcfvds/2022-05-17/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:20.333Z", + "timestamp": "2026-06-02T15:43:31.671Z", "disclosures": [] } }, + "purposes": { + "954": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ccxBidAdapter.json b/metadata/modules/ccxBidAdapter.json index 277cbd85550..dfe05ec406c 100644 --- a/metadata/modules/ccxBidAdapter.json +++ b/metadata/modules/ccxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ceeIdSystem.json b/metadata/modules/ceeIdSystem.json index 276bd531b51..3f6689d5afc 100644 --- a/metadata/modules/ceeIdSystem.json +++ b/metadata/modules/ceeIdSystem.json @@ -2,10 +2,36 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.wp.pl/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:20.597Z", + "timestamp": "2026-06-02T15:43:31.976Z", "disclosures": [] } }, + "purposes": { + "676": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 7, + 8, + 9 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/chromeAiRtdProvider.json b/metadata/modules/chromeAiRtdProvider.json index a41a0d34245..76b13baf940 100644 --- a/metadata/modules/chromeAiRtdProvider.json +++ b/metadata/modules/chromeAiRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/chromeAiRtdProvider.json": { - "timestamp": "2026-05-27T12:18:21.010Z", + "timestamp": "2026-06-02T15:43:32.629Z", "disclosures": [ { "identifier": "chromeAi_detected_data", @@ -17,6 +17,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/chtnwBidAdapter.json b/metadata/modules/chtnwBidAdapter.json index f75f683a6f7..f652593d0dd 100644 --- a/metadata/modules/chtnwBidAdapter.json +++ b/metadata/modules/chtnwBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/cleanioRtdProvider.json b/metadata/modules/cleanioRtdProvider.json index c2496ffca06..668fc9fc157 100644 --- a/metadata/modules/cleanioRtdProvider.json +++ b/metadata/modules/cleanioRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/clickforceBidAdapter.json b/metadata/modules/clickforceBidAdapter.json index 4c8bb7fda82..d18802f7185 100644 --- a/metadata/modules/clickforceBidAdapter.json +++ b/metadata/modules/clickforceBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/clickioBidAdapter.json b/metadata/modules/clickioBidAdapter.json index a0bf1e464ea..416dd7dd2bb 100644 --- a/metadata/modules/clickioBidAdapter.json +++ b/metadata/modules/clickioBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://o.clickiocdn.com/tcf_storage_info.json": { - "timestamp": "2026-05-27T12:18:21.011Z", + "timestamp": "2026-06-02T15:43:32.645Z", "disclosures": [] } }, + "purposes": { + "1500": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/clydoBidAdapter.json b/metadata/modules/clydoBidAdapter.json index 9d4cca50254..325c796f5cb 100644 --- a/metadata/modules/clydoBidAdapter.json +++ b/metadata/modules/clydoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/codefuelBidAdapter.json b/metadata/modules/codefuelBidAdapter.json index 87fafe67635..197ef4bc22b 100644 --- a/metadata/modules/codefuelBidAdapter.json +++ b/metadata/modules/codefuelBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/cointrafficBidAdapter.json b/metadata/modules/cointrafficBidAdapter.json index 8c09c265a05..e3d040ae5d6 100644 --- a/metadata/modules/cointrafficBidAdapter.json +++ b/metadata/modules/cointrafficBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/coinzillaBidAdapter.json b/metadata/modules/coinzillaBidAdapter.json index 81291c814c8..c5e9d9b9c9c 100644 --- a/metadata/modules/coinzillaBidAdapter.json +++ b/metadata/modules/coinzillaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/colombiaBidAdapter.json b/metadata/modules/colombiaBidAdapter.json index c685f0b91ce..ab5a113e1f2 100644 --- a/metadata/modules/colombiaBidAdapter.json +++ b/metadata/modules/colombiaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/colossussspBidAdapter.json b/metadata/modules/colossussspBidAdapter.json index dc2142b0a80..39b65381876 100644 --- a/metadata/modules/colossussspBidAdapter.json +++ b/metadata/modules/colossussspBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/compassBidAdapter.json b/metadata/modules/compassBidAdapter.json index 946c51b5da6..95031b295a8 100644 --- a/metadata/modules/compassBidAdapter.json +++ b/metadata/modules/compassBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.marphezis.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-27T12:18:21.470Z", + "timestamp": "2026-06-02T15:43:33.481Z", "disclosures": [] } }, + "purposes": { + "883": { + "purposes": [], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/conceptxBidAdapter.json b/metadata/modules/conceptxBidAdapter.json index 2225c11962f..db7bd89ab44 100644 --- a/metadata/modules/conceptxBidAdapter.json +++ b/metadata/modules/conceptxBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cncptx.com/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:18:21.652Z", + "timestamp": "2026-06-02T15:43:33.827Z", "disclosures": [] } }, + "purposes": { + "1340": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/concertAnalyticsAdapter.json b/metadata/modules/concertAnalyticsAdapter.json index c2f0b44fe47..ca4d835845c 100644 --- a/metadata/modules/concertAnalyticsAdapter.json +++ b/metadata/modules/concertAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/concertBidAdapter.json b/metadata/modules/concertBidAdapter.json index 6f2018bd8f0..e16694be02d 100644 --- a/metadata/modules/concertBidAdapter.json +++ b/metadata/modules/concertBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/condorxBidAdapter.json b/metadata/modules/condorxBidAdapter.json index ae1c06f092b..26ffd106558 100644 --- a/metadata/modules/condorxBidAdapter.json +++ b/metadata/modules/condorxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/confiantRtdProvider.json b/metadata/modules/confiantRtdProvider.json index b2ec2d8000f..f69730e4c0a 100644 --- a/metadata/modules/confiantRtdProvider.json +++ b/metadata/modules/confiantRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/connatixBidAdapter.json b/metadata/modules/connatixBidAdapter.json index 5ec05310213..33763069caa 100644 --- a/metadata/modules/connatixBidAdapter.json +++ b/metadata/modules/connatixBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://connatix.com/iab-tcf-disclosure.json": { - "timestamp": "2026-05-27T12:18:21.763Z", + "timestamp": "2026-06-02T15:43:34.062Z", "disclosures": [ { "identifier": "cnx_userId", @@ -21,6 +21,23 @@ ] } }, + "purposes": { + "143": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/connectIdSystem.json b/metadata/modules/connectIdSystem.json index e87695a02fc..1b4a1807175 100644 --- a/metadata/modules/connectIdSystem.json +++ b/metadata/modules/connectIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://meta.legal.yahoo.com/iab-tcf/v2/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:18:21.855Z", + "timestamp": "2026-06-02T15:43:34.451Z", "disclosures": [ { "identifier": "vmcid", @@ -57,6 +57,28 @@ ] } }, + "purposes": { + "25": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/connectadBidAdapter.json b/metadata/modules/connectadBidAdapter.json index eaee4cb09f1..475d697ca22 100644 --- a/metadata/modules/connectadBidAdapter.json +++ b/metadata/modules/connectadBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.connectad.io/tcf_storage_info.json": { - "timestamp": "2026-05-27T12:18:21.913Z", + "timestamp": "2026-06-02T15:43:34.690Z", "disclosures": [] } }, + "purposes": { + "138": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/consumableBidAdapter.json b/metadata/modules/consumableBidAdapter.json index 11ce0708f2b..1b7f83420d0 100644 --- a/metadata/modules/consumableBidAdapter.json +++ b/metadata/modules/consumableBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/contentexchangeBidAdapter.json b/metadata/modules/contentexchangeBidAdapter.json index b047d283459..e7526242c1d 100644 --- a/metadata/modules/contentexchangeBidAdapter.json +++ b/metadata/modules/contentexchangeBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://hb.contentexchange.me/template/device_storage.json": { - "timestamp": "2026-05-27T12:18:22.362Z", + "timestamp": "2026-06-02T15:43:35.633Z", "disclosures": [] } }, + "purposes": { + "864": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/contxtfulBidAdapter.json b/metadata/modules/contxtfulBidAdapter.json index 0bdb9bc2060..d9f3ab078a9 100644 --- a/metadata/modules/contxtfulBidAdapter.json +++ b/metadata/modules/contxtfulBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/contxtfulRtdProvider.json b/metadata/modules/contxtfulRtdProvider.json index d953fdb245e..ae8eca4c32a 100644 --- a/metadata/modules/contxtfulRtdProvider.json +++ b/metadata/modules/contxtfulRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/conversantBidAdapter.json b/metadata/modules/conversantBidAdapter.json index 5da24c2e6fa..3bd6d5dd3d4 100644 --- a/metadata/modules/conversantBidAdapter.json +++ b/metadata/modules/conversantBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s-usweb.dotomi.com/assets/js/taggy-js/2.18.13/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:18:22.839Z", + "timestamp": "2026-06-02T15:43:36.488Z", "disclosures": [ { "identifier": "dtm_status", @@ -579,6 +579,26 @@ ] } }, + "purposes": { + "24": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/copper6sspBidAdapter.json b/metadata/modules/copper6sspBidAdapter.json index 48e18c8a286..9fb387a69fe 100644 --- a/metadata/modules/copper6sspBidAdapter.json +++ b/metadata/modules/copper6sspBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.copper6.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:22.861Z", + "timestamp": "2026-06-02T15:43:36.798Z", "disclosures": [] } }, + "purposes": { + "1356": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/cortexBidAdapter.json b/metadata/modules/cortexBidAdapter.json index 1277eb43e1a..6603743b505 100644 --- a/metadata/modules/cortexBidAdapter.json +++ b/metadata/modules/cortexBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/cpmstarBidAdapter.json b/metadata/modules/cpmstarBidAdapter.json index cdaacbf3a8a..06f7b955193 100644 --- a/metadata/modules/cpmstarBidAdapter.json +++ b/metadata/modules/cpmstarBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn-prod.aditude.com/storageaccess.json": { - "timestamp": "2026-05-27T12:18:22.921Z", + "timestamp": "2026-06-02T15:43:37.267Z", "disclosures": [] } }, + "purposes": { + "1317": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/craftBidAdapter.json b/metadata/modules/craftBidAdapter.json index 405c278b5db..717f6e77215 100644 --- a/metadata/modules/craftBidAdapter.json +++ b/metadata/modules/craftBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/criteoBidAdapter.json b/metadata/modules/criteoBidAdapter.json index c414020d5f1..409bd4890a9 100644 --- a/metadata/modules/criteoBidAdapter.json +++ b/metadata/modules/criteoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.criteo.com/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-27T12:18:23.048Z", + "timestamp": "2026-06-02T15:43:37.568Z", "disclosures": [ { "identifier": "criteo_fast_bid", @@ -63,6 +63,24 @@ ] } }, + "purposes": { + "91": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/criteoIdSystem.json b/metadata/modules/criteoIdSystem.json index 3c733079a8e..d8bbbba7995 100644 --- a/metadata/modules/criteoIdSystem.json +++ b/metadata/modules/criteoIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.criteo.com/iab-europe/tcfv2/disclosure.json": { - "timestamp": "2026-05-27T12:18:23.185Z", + "timestamp": "2026-06-02T15:43:37.963Z", "disclosures": [ { "identifier": "criteo_fast_bid", @@ -63,6 +63,24 @@ ] } }, + "purposes": { + "91": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/cwireBidAdapter.json b/metadata/modules/cwireBidAdapter.json index 2cb1fb90385..ecdf9dd2589 100644 --- a/metadata/modules/cwireBidAdapter.json +++ b/metadata/modules/cwireBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.cwi.re/artifacts/iab/iab.json": { - "timestamp": "2026-05-27T12:18:23.185Z", + "timestamp": "2026-06-02T15:43:37.963Z", "disclosures": [] } }, + "purposes": { + "1081": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/czechAdIdSystem.json b/metadata/modules/czechAdIdSystem.json index ac0716f18a0..0f49f2bf06e 100644 --- a/metadata/modules/czechAdIdSystem.json +++ b/metadata/modules/czechAdIdSystem.json @@ -2,10 +2,25 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cpex.cz/storagedisclosure.json": { - "timestamp": "2026-05-27T12:18:23.280Z", + "timestamp": "2026-06-02T15:43:39.113Z", "disclosures": [] } }, + "purposes": { + "570": { + "purposes": [ + 1, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/dacIdSystem.json b/metadata/modules/dacIdSystem.json index 6886b206788..cfc3676ee99 100644 --- a/metadata/modules/dacIdSystem.json +++ b/metadata/modules/dacIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/dailyhuntBidAdapter.json b/metadata/modules/dailyhuntBidAdapter.json index 40a78dd65b5..1ca4d38290f 100644 --- a/metadata/modules/dailyhuntBidAdapter.json +++ b/metadata/modules/dailyhuntBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dailymotionBidAdapter.json b/metadata/modules/dailymotionBidAdapter.json index d46d095b6b3..440d9e32433 100644 --- a/metadata/modules/dailymotionBidAdapter.json +++ b/metadata/modules/dailymotionBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://statics.dmcdn.net/a/vds.json": { - "timestamp": "2026-05-27T12:18:24.044Z", + "timestamp": "2026-06-02T15:43:40.363Z", "disclosures": [ { "identifier": "uid_dm", @@ -36,6 +36,33 @@ ] } }, + "purposes": { + "573": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dasBidAdapter.json b/metadata/modules/dasBidAdapter.json index 1ca1c72523f..b3f8f906a77 100644 --- a/metadata/modules/dasBidAdapter.json +++ b/metadata/modules/dasBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/datablocksAnalyticsAdapter.json b/metadata/modules/datablocksAnalyticsAdapter.json index f0e6840e782..b2715f723f5 100644 --- a/metadata/modules/datablocksAnalyticsAdapter.json +++ b/metadata/modules/datablocksAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/datablocksBidAdapter.json b/metadata/modules/datablocksBidAdapter.json index 4291e83a3c7..c648840a1da 100644 --- a/metadata/modules/datablocksBidAdapter.json +++ b/metadata/modules/datablocksBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/datamageRtdProvider.json b/metadata/modules/datamageRtdProvider.json index 73a495c9bce..6686d2c2350 100644 --- a/metadata/modules/datamageRtdProvider.json +++ b/metadata/modules/datamageRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/datawrkzAnalyticsAdapter.json b/metadata/modules/datawrkzAnalyticsAdapter.json index 54bae4e4f2c..6d6432288e3 100644 --- a/metadata/modules/datawrkzAnalyticsAdapter.json +++ b/metadata/modules/datawrkzAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/datawrkzBidAdapter.json b/metadata/modules/datawrkzBidAdapter.json index d30a8fa610d..df44f597900 100644 --- a/metadata/modules/datawrkzBidAdapter.json +++ b/metadata/modules/datawrkzBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/debugging.json b/metadata/modules/debugging.json index a7a04bee20e..7dc9f0b5a39 100644 --- a/metadata/modules/debugging.json +++ b/metadata/modules/debugging.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/debugging.json": { - "timestamp": "2026-05-27T12:17:29.211Z", + "timestamp": "2026-06-02T15:42:53.593Z", "disclosures": [ { "identifier": "__*_debugging__", @@ -14,6 +14,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "prebid", diff --git a/metadata/modules/deepintentBidAdapter.json b/metadata/modules/deepintentBidAdapter.json index bfff44bdee4..969c10b76ac 100644 --- a/metadata/modules/deepintentBidAdapter.json +++ b/metadata/modules/deepintentBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://option.deepintent.com/iabeurope_vendor_disclosures.json": { - "timestamp": "2026-05-27T12:18:24.506Z", + "timestamp": "2026-06-02T15:43:40.757Z", "disclosures": [] } }, + "purposes": { + "541": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/deepintentDpesIdSystem.json b/metadata/modules/deepintentDpesIdSystem.json index e0f780b07ce..2986e9a43a5 100644 --- a/metadata/modules/deepintentDpesIdSystem.json +++ b/metadata/modules/deepintentDpesIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/defineMediaBidAdapter.json b/metadata/modules/defineMediaBidAdapter.json index db9bc19c440..8314e219020 100644 --- a/metadata/modules/defineMediaBidAdapter.json +++ b/metadata/modules/defineMediaBidAdapter.json @@ -2,28 +2,66 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://definemedia.de/tcf/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-27T12:18:24.554Z", + "timestamp": "2026-06-02T15:43:41.192Z", "disclosures": [ { - "identifier": "conative$dataGathering$Adex", + "identifier": "__storage__test", "type": "web", "maxAgeSeconds": null, "purposes": [ - 1, - 2 - ] + 1 + ], + "description": "Session storage availability probe before first-party cache access." + }, + { + "identifier": "__dm_storage_test", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Session storage availability probe performed when storage use is checked against the TCF state." }, { - "identifier": "conative$proddataGathering$ContextId$*", + "identifier": "dm-as4-default$conative_config", "type": "web", "maxAgeSeconds": null, "purposes": [ 1 - ] + ], + "description": "Session storage cache for the domain configuration response." + }, + { + "identifier": "dm-as4-default$context$*", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Session storage cache for Ceres context responses." } ] } }, + "purposes": { + "440": { + "purposes": [ + 1, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/deltaprojectsBidAdapter.json b/metadata/modules/deltaprojectsBidAdapter.json index 8aa75dbdef1..eb0832f5052 100644 --- a/metadata/modules/deltaprojectsBidAdapter.json +++ b/metadata/modules/deltaprojectsBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.de17a.com/policy/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:24.971Z", + "timestamp": "2026-06-02T15:43:41.848Z", "disclosures": [] } }, + "purposes": { + "209": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dexertoBidAdapter.json b/metadata/modules/dexertoBidAdapter.json index 444d9adedfa..a18a1b9d3f3 100644 --- a/metadata/modules/dexertoBidAdapter.json +++ b/metadata/modules/dexertoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dgkeywordRtdProvider.json b/metadata/modules/dgkeywordRtdProvider.json index 2cafbbe31ae..679a723446e 100644 --- a/metadata/modules/dgkeywordRtdProvider.json +++ b/metadata/modules/dgkeywordRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/dianomiBidAdapter.json b/metadata/modules/dianomiBidAdapter.json index c5dce0f7757..0e5efded190 100644 --- a/metadata/modules/dianomiBidAdapter.json +++ b/metadata/modules/dianomiBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.dianomi.com/device_storage.json": { - "timestamp": "2026-05-27T12:18:25.476Z", + "timestamp": "2026-06-02T15:43:42.964Z", "disclosures": [] } }, + "purposes": { + "885": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 8, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/digitalMatterBidAdapter.json b/metadata/modules/digitalMatterBidAdapter.json index 6d43ca146d8..5c9a699a305 100644 --- a/metadata/modules/digitalMatterBidAdapter.json +++ b/metadata/modules/digitalMatterBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://digitalmatter.ai/disclosures.json": { - "timestamp": "2026-05-27T12:18:25.477Z", + "timestamp": "2026-06-02T15:43:42.965Z", "disclosures": [] } }, + "purposes": { + "1345": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/digitalcaramelBidAdapter.json b/metadata/modules/digitalcaramelBidAdapter.json index 87dce8cb47a..edb5213be98 100644 --- a/metadata/modules/digitalcaramelBidAdapter.json +++ b/metadata/modules/digitalcaramelBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/discoveryBidAdapter.json b/metadata/modules/discoveryBidAdapter.json index f3b1b36f6da..0ea8dd4c149 100644 --- a/metadata/modules/discoveryBidAdapter.json +++ b/metadata/modules/discoveryBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/displayioBidAdapter.json b/metadata/modules/displayioBidAdapter.json index d8bc577ff1e..aa5f2789547 100644 --- a/metadata/modules/displayioBidAdapter.json +++ b/metadata/modules/displayioBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/distroscaleBidAdapter.json b/metadata/modules/distroscaleBidAdapter.json index 427c2c24fc6..743f306c576 100644 --- a/metadata/modules/distroscaleBidAdapter.json +++ b/metadata/modules/distroscaleBidAdapter.json @@ -1,18 +1,14 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", - "disclosures": { - "https://a.jsrdn.com/tcf/tcf-vendor-disclosure.json": { - "timestamp": "2026-05-27T12:18:25.820Z", - "disclosures": [] - } - }, + "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", "componentName": "distroscale", "aliasOf": null, - "gvlid": 754, - "disclosureURL": "https://a.jsrdn.com/tcf/tcf-vendor-disclosure.json" + "gvlid": null, + "disclosureURL": null }, { "componentType": "bidder", diff --git a/metadata/modules/djaxBidAdapter.json b/metadata/modules/djaxBidAdapter.json index 63b0bb766b5..9192ab2fba9 100644 --- a/metadata/modules/djaxBidAdapter.json +++ b/metadata/modules/djaxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/docereeAdManagerBidAdapter.json b/metadata/modules/docereeAdManagerBidAdapter.json index f0fc306fa03..a21b57c8b15 100644 --- a/metadata/modules/docereeAdManagerBidAdapter.json +++ b/metadata/modules/docereeAdManagerBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://doceree.com/.well-known/iab/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:25.974Z", + "timestamp": "2026-06-02T15:43:43.722Z", "disclosures": [] } }, + "purposes": { + "1063": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/docereeBidAdapter.json b/metadata/modules/docereeBidAdapter.json index 842940a37c0..ec716507891 100644 --- a/metadata/modules/docereeBidAdapter.json +++ b/metadata/modules/docereeBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://doceree.com/.well-known/iab/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:26.868Z", + "timestamp": "2026-06-02T15:43:45.529Z", "disclosures": [] } }, + "purposes": { + "1063": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dochaseBidAdapter.json b/metadata/modules/dochaseBidAdapter.json index 7a71ed0565b..e5a8c715e5e 100644 --- a/metadata/modules/dochaseBidAdapter.json +++ b/metadata/modules/dochaseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dpaiBidAdapter.json b/metadata/modules/dpaiBidAdapter.json index 901b09a3355..7ce31aa9f2a 100644 --- a/metadata/modules/dpaiBidAdapter.json +++ b/metadata/modules/dpaiBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/driftpixelBidAdapter.json b/metadata/modules/driftpixelBidAdapter.json index fb06c46a8d1..978dcf7cb76 100644 --- a/metadata/modules/driftpixelBidAdapter.json +++ b/metadata/modules/driftpixelBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dsp_genieeBidAdapter.json b/metadata/modules/dsp_genieeBidAdapter.json index 881f4a94f4d..9f94f0e7736 100644 --- a/metadata/modules/dsp_genieeBidAdapter.json +++ b/metadata/modules/dsp_genieeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dspxBidAdapter.json b/metadata/modules/dspxBidAdapter.json index 6d67ae7a115..b34a61d7f8b 100644 --- a/metadata/modules/dspxBidAdapter.json +++ b/metadata/modules/dspxBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.adtech.app/gen/deviceStorageDisclosure/os.json": { - "timestamp": "2026-05-27T12:18:26.869Z", + "timestamp": "2026-06-02T15:43:45.530Z", "disclosures": [] } }, + "purposes": { + "602": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dvgroupBidAdapter.json b/metadata/modules/dvgroupBidAdapter.json index fff5d0e662a..050f4626790 100644 --- a/metadata/modules/dvgroupBidAdapter.json +++ b/metadata/modules/dvgroupBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dxkultureBidAdapter.json b/metadata/modules/dxkultureBidAdapter.json index eb7dd9d98c8..de0534a4c46 100644 --- a/metadata/modules/dxkultureBidAdapter.json +++ b/metadata/modules/dxkultureBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dxtechBidAdapter.json b/metadata/modules/dxtechBidAdapter.json index 08ad174229b..0f0ee7a1ce6 100644 --- a/metadata/modules/dxtechBidAdapter.json +++ b/metadata/modules/dxtechBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/dynamicAdBoostRtdProvider.json b/metadata/modules/dynamicAdBoostRtdProvider.json index 7ec18bd785c..336c2092e0c 100644 --- a/metadata/modules/dynamicAdBoostRtdProvider.json +++ b/metadata/modules/dynamicAdBoostRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/e_volutionBidAdapter.json b/metadata/modules/e_volutionBidAdapter.json index facd92f6468..5d0c3c302d5 100644 --- a/metadata/modules/e_volutionBidAdapter.json +++ b/metadata/modules/e_volutionBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://e-volution.ai/file.json": { - "timestamp": "2026-05-18T20:04:27.992Z", + "timestamp": "2026-06-02T15:43:47.073Z", "disclosures": [] } }, + "purposes": { + "957": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/eclickBidAdapter.json b/metadata/modules/eclickBidAdapter.json index c19ca4af158..b49d3fa811a 100644 --- a/metadata/modules/eclickBidAdapter.json +++ b/metadata/modules/eclickBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/edge226BidAdapter.json b/metadata/modules/edge226BidAdapter.json index acd0054835a..08304b8ddaf 100644 --- a/metadata/modules/edge226BidAdapter.json +++ b/metadata/modules/edge226BidAdapter.json @@ -2,10 +2,25 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.serveteck.com/cdn_storage/tcf/tcf.json?a=1.io": { - "timestamp": "2026-05-27T12:18:55.613Z", + "timestamp": "2026-06-02T15:43:47.703Z", "disclosures": null } }, + "purposes": { + "1202": { + "purposes": [ + 2, + 7, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ehealthcaresolutionsBidAdapter.json b/metadata/modules/ehealthcaresolutionsBidAdapter.json index 8027a295a9f..d703721e264 100644 --- a/metadata/modules/ehealthcaresolutionsBidAdapter.json +++ b/metadata/modules/ehealthcaresolutionsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/eightPodAnalyticsAdapter.json b/metadata/modules/eightPodAnalyticsAdapter.json index 52e87cea2e8..4d4e8941f65 100644 --- a/metadata/modules/eightPodAnalyticsAdapter.json +++ b/metadata/modules/eightPodAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/eightPodBidAdapter.json b/metadata/modules/eightPodBidAdapter.json index 5759d698d0d..a5f19165b9f 100644 --- a/metadata/modules/eightPodBidAdapter.json +++ b/metadata/modules/eightPodBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/empowerBidAdapter.json b/metadata/modules/empowerBidAdapter.json index a59256a700b..c66e7453a96 100644 --- a/metadata/modules/empowerBidAdapter.json +++ b/metadata/modules/empowerBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.empower.net/vendor/vendor.json": { - "timestamp": "2026-05-27T12:18:55.705Z", + "timestamp": "2026-06-02T15:43:48.028Z", "disclosures": [] } }, + "purposes": { + "1248": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/emtvBidAdapter.json b/metadata/modules/emtvBidAdapter.json index 5ac33bad8de..85d7ab4bde9 100644 --- a/metadata/modules/emtvBidAdapter.json +++ b/metadata/modules/emtvBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/encypherRtdProvider.json b/metadata/modules/encypherRtdProvider.json index 645d68136f5..86cf8dece8e 100644 --- a/metadata/modules/encypherRtdProvider.json +++ b/metadata/modules/encypherRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/engageyaBidAdapter.json b/metadata/modules/engageyaBidAdapter.json index 31b39e5fb34..9211115a8ef 100644 --- a/metadata/modules/engageyaBidAdapter.json +++ b/metadata/modules/engageyaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/eplanningBidAdapter.json b/metadata/modules/eplanningBidAdapter.json index 542f121e550..2eb7d866d58 100644 --- a/metadata/modules/eplanningBidAdapter.json +++ b/metadata/modules/eplanningBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/epom_dspBidAdapter.json b/metadata/modules/epom_dspBidAdapter.json index 6f2acc45ccd..22e873e0c55 100644 --- a/metadata/modules/epom_dspBidAdapter.json +++ b/metadata/modules/epom_dspBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/equativBidAdapter.json b/metadata/modules/equativBidAdapter.json index d110753884d..9be45dc0e66 100644 --- a/metadata/modules/equativBidAdapter.json +++ b/metadata/modules/equativBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apps.smartadserver.com/device-storage-disclosures/equativDeviceStorageDisclosures.json": { - "timestamp": "2026-05-27T12:18:55.818Z", + "timestamp": "2026-06-02T15:43:48.278Z", "disclosures": [] } }, + "purposes": { + "45": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/escalaxBidAdapter.json b/metadata/modules/escalaxBidAdapter.json index e23275023bb..f8dd754c958 100644 --- a/metadata/modules/escalaxBidAdapter.json +++ b/metadata/modules/escalaxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/eskimiBidAdapter.json b/metadata/modules/eskimiBidAdapter.json index 791f3cd6416..823e5792484 100644 --- a/metadata/modules/eskimiBidAdapter.json +++ b/metadata/modules/eskimiBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://dsp-media.eskimi.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:56.518Z", + "timestamp": "2026-06-02T15:43:49.733Z", "disclosures": [] } }, + "purposes": { + "814": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/etargetBidAdapter.json b/metadata/modules/etargetBidAdapter.json index af93ce8844e..299e406c6bd 100644 --- a/metadata/modules/etargetBidAdapter.json +++ b/metadata/modules/etargetBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.etarget.sk/cookies3.json": { - "timestamp": "2026-05-27T12:18:56.603Z", + "timestamp": "2026-06-02T15:43:49.991Z", "disclosures": [] } }, + "purposes": { + "29": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/euidIdSystem.json b/metadata/modules/euidIdSystem.json index cd4026f8a26..5886f905bdc 100644 --- a/metadata/modules/euidIdSystem.json +++ b/metadata/modules/euidIdSystem.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-27T12:18:57.385Z", + "timestamp": "2026-06-02T15:43:51.023Z", "disclosures": [] } }, + "purposes": { + "21": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/exadsBidAdapter.json b/metadata/modules/exadsBidAdapter.json index b43d90c8e38..ddf188999cf 100644 --- a/metadata/modules/exadsBidAdapter.json +++ b/metadata/modules/exadsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://a.native7.com/tcf/deviceStorage.php": { - "timestamp": "2026-05-27T12:18:57.771Z", + "timestamp": "2026-06-02T15:43:51.300Z", "disclosures": [ { "identifier": "pn-zone-*", @@ -34,6 +34,22 @@ ] } }, + "purposes": { + "1084": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/excoBidAdapter.json b/metadata/modules/excoBidAdapter.json index 4a69b1275f8..7014e29ea33 100644 --- a/metadata/modules/excoBidAdapter.json +++ b/metadata/modules/excoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/experianRtdProvider.json b/metadata/modules/experianRtdProvider.json index f7eb7b5356c..5c63957d403 100644 --- a/metadata/modules/experianRtdProvider.json +++ b/metadata/modules/experianRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/fabrickIdSystem.json b/metadata/modules/fabrickIdSystem.json index af900e1027c..efe90a6e022 100644 --- a/metadata/modules/fabrickIdSystem.json +++ b/metadata/modules/fabrickIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/fanBidAdapter.json b/metadata/modules/fanBidAdapter.json index 017e7a019d4..c63fd48f2db 100644 --- a/metadata/modules/fanBidAdapter.json +++ b/metadata/modules/fanBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/feedadBidAdapter.json b/metadata/modules/feedadBidAdapter.json index 9bdbbaec0dc..f87ff64a4dd 100644 --- a/metadata/modules/feedadBidAdapter.json +++ b/metadata/modules/feedadBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://api.feedad.com/tcf-device-disclosures.json": { - "timestamp": "2026-05-27T12:18:58.105Z", + "timestamp": "2026-06-02T15:43:51.695Z", "disclosures": [ { "identifier": "__fad_data", @@ -36,6 +36,33 @@ ] } }, + "purposes": { + "781": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 8, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/finativeBidAdapter.json b/metadata/modules/finativeBidAdapter.json index 99ec9cb9ae8..d01b9b47dd4 100644 --- a/metadata/modules/finativeBidAdapter.json +++ b/metadata/modules/finativeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/fintezaAnalyticsAdapter.json b/metadata/modules/fintezaAnalyticsAdapter.json index 2e3bd8b78fe..b0c6a49f912 100644 --- a/metadata/modules/fintezaAnalyticsAdapter.json +++ b/metadata/modules/fintezaAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/flippBidAdapter.json b/metadata/modules/flippBidAdapter.json index 7ccd9710e52..58e37a48b34 100644 --- a/metadata/modules/flippBidAdapter.json +++ b/metadata/modules/flippBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/floxisBidAdapter.json b/metadata/modules/floxisBidAdapter.json index c58d76bc57a..13713d8c5f1 100644 --- a/metadata/modules/floxisBidAdapter.json +++ b/metadata/modules/floxisBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/fluctBidAdapter.json b/metadata/modules/fluctBidAdapter.json index 2abf3439bdb..d2ba52cb455 100644 --- a/metadata/modules/fluctBidAdapter.json +++ b/metadata/modules/fluctBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/freepassBidAdapter.json b/metadata/modules/freepassBidAdapter.json index dd65dbf7c02..7d776aba110 100644 --- a/metadata/modules/freepassBidAdapter.json +++ b/metadata/modules/freepassBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/freepassIdSystem.json b/metadata/modules/freepassIdSystem.json index 880129574ee..4ffb24f8d67 100644 --- a/metadata/modules/freepassIdSystem.json +++ b/metadata/modules/freepassIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/ftrackIdSystem.json b/metadata/modules/ftrackIdSystem.json index 54974ce3b57..b3be1a7de54 100644 --- a/metadata/modules/ftrackIdSystem.json +++ b/metadata/modules/ftrackIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/fwsspBidAdapter.json b/metadata/modules/fwsspBidAdapter.json index b6226248f4d..77d8e5568d6 100644 --- a/metadata/modules/fwsspBidAdapter.json +++ b/metadata/modules/fwsspBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab.fwmrm.net/g/devicedisclosure.json": { - "timestamp": "2026-05-27T12:18:58.333Z", + "timestamp": "2026-06-02T15:43:52.130Z", "disclosures": [] } }, + "purposes": { + "285": { + "purposes": [ + 1, + 2, + 4 + ], + "legIntPurposes": [ + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gameraRtdProvider.json b/metadata/modules/gameraRtdProvider.json index 2e1be18dd94..10ee33c734d 100644 --- a/metadata/modules/gameraRtdProvider.json +++ b/metadata/modules/gameraRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/gammaBidAdapter.json b/metadata/modules/gammaBidAdapter.json index 2ccba02bc58..3800efd98c7 100644 --- a/metadata/modules/gammaBidAdapter.json +++ b/metadata/modules/gammaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gamoshiBidAdapter.json b/metadata/modules/gamoshiBidAdapter.json index 11d6dee0700..b4426cc3381 100644 --- a/metadata/modules/gamoshiBidAdapter.json +++ b/metadata/modules/gamoshiBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resources.gamoshi.io/disclosures-client-storage.json": { - "timestamp": "2026-05-27T12:18:58.450Z", + "timestamp": "2026-06-02T15:43:52.744Z", "disclosures": [] } }, + "purposes": { + "644": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gemiusIdSystem.json b/metadata/modules/gemiusIdSystem.json index 2a0a0e30e97..8acfcb4042b 100644 --- a/metadata/modules/gemiusIdSystem.json +++ b/metadata/modules/gemiusIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gemius.com/media/documents/Gemius_SA_Vendor_Device_Storage.json": { - "timestamp": "2026-05-27T12:18:58.748Z", + "timestamp": "2026-06-02T15:43:53.250Z", "disclosures": [ { "identifier": "__gsyncs_gdpr", @@ -268,6 +268,23 @@ ] } }, + "purposes": { + "328": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/genericAnalyticsAdapter.json b/metadata/modules/genericAnalyticsAdapter.json index 91b862b5997..9b836192538 100644 --- a/metadata/modules/genericAnalyticsAdapter.json +++ b/metadata/modules/genericAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/geoedgeRtdProvider.json b/metadata/modules/geoedgeRtdProvider.json index eb835c81886..b043eb7c224 100644 --- a/metadata/modules/geoedgeRtdProvider.json +++ b/metadata/modules/geoedgeRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/geolocationRtdProvider.json b/metadata/modules/geolocationRtdProvider.json index d55c073cb8b..986bd31c39b 100644 --- a/metadata/modules/geolocationRtdProvider.json +++ b/metadata/modules/geolocationRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/getintentBidAdapter.json b/metadata/modules/getintentBidAdapter.json index 06386b819d4..5ca5741c30a 100644 --- a/metadata/modules/getintentBidAdapter.json +++ b/metadata/modules/getintentBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gjirafaBidAdapter.json b/metadata/modules/gjirafaBidAdapter.json index c2687b75491..b4568b4ecde 100644 --- a/metadata/modules/gjirafaBidAdapter.json +++ b/metadata/modules/gjirafaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/glomexBidAdapter.json b/metadata/modules/glomexBidAdapter.json index 7bb9b3d2e8c..c489e2357b5 100644 --- a/metadata/modules/glomexBidAdapter.json +++ b/metadata/modules/glomexBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://player.glomex.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:18:58.749Z", + "timestamp": "2026-06-02T15:43:53.251Z", "disclosures": [ { "identifier": "glomexUser", @@ -43,6 +43,32 @@ ] } }, + "purposes": { + "967": { + "purposes": [ + 1, + 3, + 4, + 6, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gmosspBidAdapter.json b/metadata/modules/gmosspBidAdapter.json index 6a7d8d19d0e..4189919440e 100644 --- a/metadata/modules/gmosspBidAdapter.json +++ b/metadata/modules/gmosspBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/gnetBidAdapter.json b/metadata/modules/gnetBidAdapter.json index f06016b2173..572ee7ac374 100644 --- a/metadata/modules/gnetBidAdapter.json +++ b/metadata/modules/gnetBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/goadserverBidAdapter.json b/metadata/modules/goadserverBidAdapter.json index fcbecacfb0d..a084292e772 100644 --- a/metadata/modules/goadserverBidAdapter.json +++ b/metadata/modules/goadserverBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/goldbachBidAdapter.json b/metadata/modules/goldbachBidAdapter.json index 56e056ea6e1..da0fdb3ee69 100644 --- a/metadata/modules/goldbachBidAdapter.json +++ b/metadata/modules/goldbachBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gb-next.ch/TcfGoldbachDeviceStorage.json": { - "timestamp": "2026-05-27T12:18:58.908Z", + "timestamp": "2026-06-02T15:43:53.508Z", "disclosures": [ { "identifier": "dakt_2_session_id", @@ -17,10 +17,6 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, { @@ -36,10 +32,6 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, { @@ -49,9 +41,6 @@ "cookieRefresh": true, "purposes": [ 1 - ], - "specialPurposes": [ - 1 ] }, { @@ -67,23 +56,8 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, - { - "identifier": "dakt_2_dnt", - "type": "cookie", - "maxAgeSeconds": 15552000, - "cookieRefresh": false, - "purposes": [], - "specialPurposes": [ - 1 - ], - "optOut": true - }, { "identifier": "DqSync", "type": "cookie", @@ -91,9 +65,6 @@ "cookieRefresh": false, "purposes": [ 1 - ], - "specialPurposes": [ - 2 ] }, { @@ -108,10 +79,6 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, { @@ -126,10 +93,6 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, { @@ -144,10 +107,6 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] }, { @@ -162,15 +121,36 @@ 7, 9, 10 - ], - "specialPurposes": [ - 1, - 2 ] } ] } }, + "purposes": { + "580": { + "purposes": [ + 1, + 3, + 4, + 8 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/goldfishAdsRtdProvider.json b/metadata/modules/goldfishAdsRtdProvider.json index c0acee296e4..7efc8f37481 100644 --- a/metadata/modules/goldfishAdsRtdProvider.json +++ b/metadata/modules/goldfishAdsRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/gravitoIdSystem.json b/metadata/modules/gravitoIdSystem.json index 51c3a1659d3..f0e1d572539 100644 --- a/metadata/modules/gravitoIdSystem.json +++ b/metadata/modules/gravitoIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/greenbidsAnalyticsAdapter.json b/metadata/modules/greenbidsAnalyticsAdapter.json index 4c26700e5e0..f85a6f7ff43 100644 --- a/metadata/modules/greenbidsAnalyticsAdapter.json +++ b/metadata/modules/greenbidsAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/greenbidsBidAdapter.json b/metadata/modules/greenbidsBidAdapter.json index 28bdff986be..9c73efb5487 100644 --- a/metadata/modules/greenbidsBidAdapter.json +++ b/metadata/modules/greenbidsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/greenbidsRtdProvider.json b/metadata/modules/greenbidsRtdProvider.json index 3d377e9661d..45c06afc2b3 100644 --- a/metadata/modules/greenbidsRtdProvider.json +++ b/metadata/modules/greenbidsRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/gridBidAdapter.json b/metadata/modules/gridBidAdapter.json index bc09accd001..e842ac2496f 100644 --- a/metadata/modules/gridBidAdapter.json +++ b/metadata/modules/gridBidAdapter.json @@ -2,10 +2,25 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.themediagrid.com/devicestorage.json": { - "timestamp": "2026-05-27T12:18:59.055Z", + "timestamp": "2026-06-02T15:43:53.731Z", "disclosures": [] } }, + "purposes": { + "686": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/growadsBidAdapter.json b/metadata/modules/growadsBidAdapter.json index 30f80c1f341..63d95a10499 100644 --- a/metadata/modules/growadsBidAdapter.json +++ b/metadata/modules/growadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/growthCodeAnalyticsAdapter.json b/metadata/modules/growthCodeAnalyticsAdapter.json index b75b0fd8c0d..30652957a1e 100644 --- a/metadata/modules/growthCodeAnalyticsAdapter.json +++ b/metadata/modules/growthCodeAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/growthCodeIdSystem.json b/metadata/modules/growthCodeIdSystem.json index e4bdce1366d..16846a12586 100644 --- a/metadata/modules/growthCodeIdSystem.json +++ b/metadata/modules/growthCodeIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/growthCodeRtdProvider.json b/metadata/modules/growthCodeRtdProvider.json index 277d9ab2d54..79c58ba9720 100644 --- a/metadata/modules/growthCodeRtdProvider.json +++ b/metadata/modules/growthCodeRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/gumgumBidAdapter.json b/metadata/modules/gumgumBidAdapter.json index d540b6b8a84..873670558f9 100644 --- a/metadata/modules/gumgumBidAdapter.json +++ b/metadata/modules/gumgumBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://marketing.gumgum.com/devicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:18:59.240Z", + "timestamp": "2026-06-02T15:43:54.250Z", "disclosures": [] } }, + "purposes": { + "61": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/h12mediaBidAdapter.json b/metadata/modules/h12mediaBidAdapter.json index f28bd6bb539..726d0435c7f 100644 --- a/metadata/modules/h12mediaBidAdapter.json +++ b/metadata/modules/h12mediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/hadronAnalyticsAdapter.json b/metadata/modules/hadronAnalyticsAdapter.json index b6fa5356e6d..b6bb813889b 100644 --- a/metadata/modules/hadronAnalyticsAdapter.json +++ b/metadata/modules/hadronAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/hadronIdSystem.json b/metadata/modules/hadronIdSystem.json index bb728b90fef..c61538908ed 100644 --- a/metadata/modules/hadronIdSystem.json +++ b/metadata/modules/hadronIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://p.ad.gt/static/iab_tcf.json": { - "timestamp": "2026-05-27T12:18:59.408Z", + "timestamp": "2026-06-02T15:43:54.717Z", "disclosures": [ { "identifier": "au/sid", @@ -48,6 +48,22 @@ ] } }, + "purposes": { + "561": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/hadronRtdProvider.json b/metadata/modules/hadronRtdProvider.json index bb6919e6642..6f8ad2db4b5 100644 --- a/metadata/modules/hadronRtdProvider.json +++ b/metadata/modules/hadronRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://p.ad.gt/static/iab_tcf.json": { - "timestamp": "2026-05-27T12:18:59.573Z", + "timestamp": "2026-06-02T15:43:55.034Z", "disclosures": [ { "identifier": "au/sid", @@ -48,6 +48,22 @@ ] } }, + "purposes": { + "561": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/haloadsBidAdapter.json b/metadata/modules/haloadsBidAdapter.json index 6062fa52652..804b1921153 100644 --- a/metadata/modules/haloadsBidAdapter.json +++ b/metadata/modules/haloadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/harionBidAdapter.json b/metadata/modules/harionBidAdapter.json index d740806f7b7..3048dda4b5f 100644 --- a/metadata/modules/harionBidAdapter.json +++ b/metadata/modules/harionBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://markappmedia.site/vendor.json": { - "timestamp": "2026-05-27T12:18:59.574Z", + "timestamp": "2026-06-02T15:43:55.034Z", "disclosures": [] } }, + "purposes": { + "1406": { + "purposes": [ + 1, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/holidBidAdapter.json b/metadata/modules/holidBidAdapter.json index 931908a0ef6..0cf584409d1 100644 --- a/metadata/modules/holidBidAdapter.json +++ b/metadata/modules/holidBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ads.holid.io/devicestorage.json": { - "timestamp": "2026-05-27T12:18:59.978Z", + "timestamp": "2026-06-02T15:43:55.858Z", "disclosures": [ { "identifier": "uids", @@ -19,6 +19,26 @@ ] } }, + "purposes": { + "1177": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/hubvisorBidAdapter.json b/metadata/modules/hubvisorBidAdapter.json index 51e92fda7fc..6574419a535 100644 --- a/metadata/modules/hubvisorBidAdapter.json +++ b/metadata/modules/hubvisorBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.hubvisor.io/assets/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:00.225Z", + "timestamp": "2026-06-02T15:43:56.624Z", "disclosures": [ { "identifier": "hbv:turbo-cmp", @@ -52,6 +52,16 @@ ] } }, + "purposes": { + "1112": { + "purposes": [ + 1 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/humansecurityMalvDefenseRtdProvider.json b/metadata/modules/humansecurityMalvDefenseRtdProvider.json index 98fec2f0fd9..45b983f9cbe 100644 --- a/metadata/modules/humansecurityMalvDefenseRtdProvider.json +++ b/metadata/modules/humansecurityMalvDefenseRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/humansecurityRtdProvider.json b/metadata/modules/humansecurityRtdProvider.json index 5e2c398f499..147f99759a8 100644 --- a/metadata/modules/humansecurityRtdProvider.json +++ b/metadata/modules/humansecurityRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/hybridBidAdapter.json b/metadata/modules/hybridBidAdapter.json index 69408c404dc..2dc151628af 100644 --- a/metadata/modules/hybridBidAdapter.json +++ b/metadata/modules/hybridBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://st.hybrid.ai/policy/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:00.481Z", + "timestamp": "2026-06-02T15:43:57.087Z", "disclosures": [] } }, + "purposes": { + "206": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/hypelabBidAdapter.json b/metadata/modules/hypelabBidAdapter.json index 36b95ee1ad2..6d5a45fe0a9 100644 --- a/metadata/modules/hypelabBidAdapter.json +++ b/metadata/modules/hypelabBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/iasRtdProvider.json b/metadata/modules/iasRtdProvider.json index 1df9cab11b2..7148dce33a4 100644 --- a/metadata/modules/iasRtdProvider.json +++ b/metadata/modules/iasRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/id5AnalyticsAdapter.json b/metadata/modules/id5AnalyticsAdapter.json index 40507d9eb00..f4d74402432 100644 --- a/metadata/modules/id5AnalyticsAdapter.json +++ b/metadata/modules/id5AnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/id5IdSystem.json b/metadata/modules/id5IdSystem.json index 4340cad79d4..e91ee657df6 100644 --- a/metadata/modules/id5IdSystem.json +++ b/metadata/modules/id5IdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://id5-sync.com/tcf/disclosures.json": { - "timestamp": "2026-05-27T12:19:00.650Z", + "timestamp": "2026-06-02T15:43:57.626Z", "disclosures": [ { "identifier": "id5id", @@ -248,6 +248,19 @@ ] } }, + "purposes": { + "131": { + "purposes": [ + 1, + 3, + 5, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/identityLinkIdSystem.json b/metadata/modules/identityLinkIdSystem.json index 8f7d38701cb..024e81468eb 100644 --- a/metadata/modules/identityLinkIdSystem.json +++ b/metadata/modules/identityLinkIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.ats.rlcdn.com/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:00.938Z", + "timestamp": "2026-06-02T15:44:11.063Z", "disclosures": [ { "identifier": "_lr_retry_request", @@ -115,6 +115,25 @@ ] } }, + "purposes": { + "97": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/idxBidAdapter.json b/metadata/modules/idxBidAdapter.json index fb6c9f31b8e..d3a1313a9fe 100644 --- a/metadata/modules/idxBidAdapter.json +++ b/metadata/modules/idxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/idxIdSystem.json b/metadata/modules/idxIdSystem.json index 0e3965dfad9..d92266d05de 100644 --- a/metadata/modules/idxIdSystem.json +++ b/metadata/modules/idxIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/illuminBidAdapter.json b/metadata/modules/illuminBidAdapter.json index 02015477e10..260aa02d0c7 100644 --- a/metadata/modules/illuminBidAdapter.json +++ b/metadata/modules/illuminBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://admanmedia.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:01.103Z", + "timestamp": "2026-06-02T15:44:11.276Z", "disclosures": [] } }, + "purposes": { + "149": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/imAnalyticsAdapter.json b/metadata/modules/imAnalyticsAdapter.json index 57de64bd1fc..1602fdb2652 100644 --- a/metadata/modules/imAnalyticsAdapter.json +++ b/metadata/modules/imAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/imRtdProvider.json b/metadata/modules/imRtdProvider.json index 4139f96274c..566e250d661 100644 --- a/metadata/modules/imRtdProvider.json +++ b/metadata/modules/imRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/impactifyBidAdapter.json b/metadata/modules/impactifyBidAdapter.json index d93fb161a72..492da45fa39 100644 --- a/metadata/modules/impactifyBidAdapter.json +++ b/metadata/modules/impactifyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.impactify.io/tcfvendors.json": { - "timestamp": "2026-05-27T12:19:01.386Z", + "timestamp": "2026-06-02T15:44:11.887Z", "disclosures": [ { "identifier": "_im*", @@ -17,6 +17,31 @@ ] } }, + "purposes": { + "606": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/improvedigitalBidAdapter.json b/metadata/modules/improvedigitalBidAdapter.json index ea561a2a7e1..2711db58597 100644 --- a/metadata/modules/improvedigitalBidAdapter.json +++ b/metadata/modules/improvedigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sellers.improvedigital.com/tcf-cookies.json": { - "timestamp": "2026-05-27T12:19:01.750Z", + "timestamp": "2026-06-02T15:44:12.702Z", "disclosures": [ { "identifier": "tuuid", @@ -133,6 +133,29 @@ ] } }, + "purposes": { + "253": { + "purposes": [ + 1, + 3, + 4, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/imuIdSystem.json b/metadata/modules/imuIdSystem.json index 5b04170d7da..1ce36386dcb 100644 --- a/metadata/modules/imuIdSystem.json +++ b/metadata/modules/imuIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/incrementxBidAdapter.json b/metadata/modules/incrementxBidAdapter.json index c46ce484c7b..7b3b9abba7a 100644 --- a/metadata/modules/incrementxBidAdapter.json +++ b/metadata/modules/incrementxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/inmobiBidAdapter.json b/metadata/modules/inmobiBidAdapter.json index aa174888fbb..fc86f3a4831 100644 --- a/metadata/modules/inmobiBidAdapter.json +++ b/metadata/modules/inmobiBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://publisher.inmobi.com/public/disclosure.json": { - "timestamp": "2026-05-27T12:19:01.751Z", + "timestamp": "2026-06-02T15:44:12.702Z", "disclosures": [ { "identifier": "iDSP_Cookie", @@ -42,6 +42,29 @@ ] } }, + "purposes": { + "333": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/innityBidAdapter.json b/metadata/modules/innityBidAdapter.json index 51500e6582f..482a57872b2 100644 --- a/metadata/modules/innityBidAdapter.json +++ b/metadata/modules/innityBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/insticatorBidAdapter.json b/metadata/modules/insticatorBidAdapter.json index 122957d7c48..0186fab2ade 100644 --- a/metadata/modules/insticatorBidAdapter.json +++ b/metadata/modules/insticatorBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.insticator.com/iab/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:01.829Z", + "timestamp": "2026-06-02T15:44:13.196Z", "disclosures": [ { "identifier": "visitorGeo", @@ -68,6 +68,35 @@ ] } }, + "purposes": { + "910": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/insuradsBidAdapter.json b/metadata/modules/insuradsBidAdapter.json index 2c3d6494fbf..7e5fd9de0b3 100644 --- a/metadata/modules/insuradsBidAdapter.json +++ b/metadata/modules/insuradsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.insurads.com/tcf-vdsod.json": { - "timestamp": "2026-05-27T12:19:02.177Z", + "timestamp": "2026-06-02T15:44:13.463Z", "disclosures": [ { "identifier": "___iat_ses", @@ -33,6 +33,22 @@ ] } }, + "purposes": { + "596": { + "purposes": [ + 1, + 2, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/insuradsRtdProvider.json b/metadata/modules/insuradsRtdProvider.json index 6e068abc8b8..123ad8b7e93 100644 --- a/metadata/modules/insuradsRtdProvider.json +++ b/metadata/modules/insuradsRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.insurads.com/tcf-vdsod.json": { - "timestamp": "2026-05-27T12:19:02.544Z", + "timestamp": "2026-06-02T15:44:14.162Z", "disclosures": [ { "identifier": "___iat_ses", @@ -33,6 +33,22 @@ ] } }, + "purposes": { + "596": { + "purposes": [ + 1, + 2, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/integr8BidAdapter.json b/metadata/modules/integr8BidAdapter.json index 84199d3446d..23ecccb8185 100644 --- a/metadata/modules/integr8BidAdapter.json +++ b/metadata/modules/integr8BidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/intentIqAnalyticsAdapter.json b/metadata/modules/intentIqAnalyticsAdapter.json index 10122d938eb..99f37ac13c3 100644 --- a/metadata/modules/intentIqAnalyticsAdapter.json +++ b/metadata/modules/intentIqAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/intentIqIdSystem.json b/metadata/modules/intentIqIdSystem.json index 70146b9e020..d076de1f18b 100644 --- a/metadata/modules/intentIqIdSystem.json +++ b/metadata/modules/intentIqIdSystem.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://agent.intentiq.com/GDPR/gdpr.json": { - "timestamp": "2026-05-27T12:19:02.545Z", + "timestamp": "2026-06-02T15:44:14.162Z", "disclosures": [] } }, + "purposes": { + "1323": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/intenzeBidAdapter.json b/metadata/modules/intenzeBidAdapter.json index 9734e2cc237..2726dba2f5c 100644 --- a/metadata/modules/intenzeBidAdapter.json +++ b/metadata/modules/intenzeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/interactiveOffersBidAdapter.json b/metadata/modules/interactiveOffersBidAdapter.json index eef3197ae04..f344e55781c 100644 --- a/metadata/modules/interactiveOffersBidAdapter.json +++ b/metadata/modules/interactiveOffersBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/invamiaBidAdapter.json b/metadata/modules/invamiaBidAdapter.json index 3103fbdbc0c..26c226bfa1f 100644 --- a/metadata/modules/invamiaBidAdapter.json +++ b/metadata/modules/invamiaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/invibesBidAdapter.json b/metadata/modules/invibesBidAdapter.json index fa86eaef642..9f8b62be72d 100644 --- a/metadata/modules/invibesBidAdapter.json +++ b/metadata/modules/invibesBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.invibes.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:02.759Z", + "timestamp": "2026-06-02T15:44:14.641Z", "disclosures": [ { "identifier": "ivvcap", @@ -159,6 +159,29 @@ ] } }, + "purposes": { + "436": { + "purposes": [ + 1, + 3, + 4, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/invisiblyAnalyticsAdapter.json b/metadata/modules/invisiblyAnalyticsAdapter.json index 172c87e0f5b..7828b2c4d41 100644 --- a/metadata/modules/invisiblyAnalyticsAdapter.json +++ b/metadata/modules/invisiblyAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/ipromBidAdapter.json b/metadata/modules/ipromBidAdapter.json index 48393aed581..ead4795de26 100644 --- a/metadata/modules/ipromBidAdapter.json +++ b/metadata/modules/ipromBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://core.iprom.net/info/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:03.140Z", + "timestamp": "2026-06-02T15:44:15.304Z", "disclosures": [] } }, + "purposes": { + "811": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/iqxBidAdapter.json b/metadata/modules/iqxBidAdapter.json index 7d247b6d698..44a81140581 100644 --- a/metadata/modules/iqxBidAdapter.json +++ b/metadata/modules/iqxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/iqzoneBidAdapter.json b/metadata/modules/iqzoneBidAdapter.json index 3a67c35912c..173d274a10a 100644 --- a/metadata/modules/iqzoneBidAdapter.json +++ b/metadata/modules/iqzoneBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ivsBidAdapter.json b/metadata/modules/ivsBidAdapter.json index dc55ba29251..3aebd4f69e5 100644 --- a/metadata/modules/ivsBidAdapter.json +++ b/metadata/modules/ivsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ixBidAdapter.json b/metadata/modules/ixBidAdapter.json index d79d46ae676..454ddb0b0ab 100644 --- a/metadata/modules/ixBidAdapter.json +++ b/metadata/modules/ixBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.indexexchange.com/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:03.577Z", + "timestamp": "2026-06-02T15:44:16.160Z", "disclosures": [ { "identifier": "ix_features", @@ -49,6 +49,26 @@ ] } }, + "purposes": { + "10": { + "purposes": [ + 1, + 2, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/jixieBidAdapter.json b/metadata/modules/jixieBidAdapter.json index 3febcd85122..2484a7c96dc 100644 --- a/metadata/modules/jixieBidAdapter.json +++ b/metadata/modules/jixieBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/jixieBidAdapterDisclosure.json": { - "timestamp": "2026-05-27T12:19:03.884Z", + "timestamp": "2026-06-02T15:44:16.754Z", "disclosures": [ { "identifier": "_jxx", @@ -84,6 +84,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/jixieIdSystem.json b/metadata/modules/jixieIdSystem.json index 6cba32ef9ac..3e5a5043a90 100644 --- a/metadata/modules/jixieIdSystem.json +++ b/metadata/modules/jixieIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/jixieIdSystemDisclosure.json": { - "timestamp": "2026-05-27T12:19:03.884Z", + "timestamp": "2026-06-02T15:44:16.755Z", "disclosures": [ { "identifier": "_jxx", @@ -57,6 +57,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/justIdSystem.json b/metadata/modules/justIdSystem.json index 9776b93a1de..93a2da0c310 100644 --- a/metadata/modules/justIdSystem.json +++ b/metadata/modules/justIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audience-solutions.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:03.885Z", + "timestamp": "2026-06-02T15:44:16.755Z", "disclosures": [ { "identifier": "__jtuid", @@ -25,6 +25,27 @@ ] } }, + "purposes": { + "160": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/justpremiumBidAdapter.json b/metadata/modules/justpremiumBidAdapter.json index c2a9ba0703f..5d16777f13d 100644 --- a/metadata/modules/justpremiumBidAdapter.json +++ b/metadata/modules/justpremiumBidAdapter.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.justpremium.com/devicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:19:04.352Z", + "timestamp": "2026-06-02T15:44:17.650Z", "disclosures": [] } }, + "purposes": { + "62": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/jwplayerBidAdapter.json b/metadata/modules/jwplayerBidAdapter.json index 2b04e286e7b..352f7827297 100644 --- a/metadata/modules/jwplayerBidAdapter.json +++ b/metadata/modules/jwplayerBidAdapter.json @@ -2,8 +2,120 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.jwplayer.com/devicestorage.json": { - "timestamp": "2026-05-27T12:19:04.688Z", - "disclosures": [] + "timestamp": "2026-06-02T15:44:17.988Z", + "disclosures": [ + { + "identifier": "jwplayer.volume", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's preferred volume level (0–100) in browser localStorage so it can be restored the next time the player loads on this device." + }, + { + "identifier": "jwplayer.mute", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's mute preference (true/false) in browser localStorage so it can be restored the next time the player loads on this device." + }, + { + "identifier": "jwplayer.captionLabel", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the label of the user's selected closed-caption track in browser localStorage so the same caption language is pre-selected on future visits." + }, + { + "identifier": "jwplayer.captions", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's caption style preferences (font, size, color, etc.) as a JSON object in browser localStorage so custom styling is preserved across sessions." + }, + { + "identifier": "jwplayer.bandwidthEstimate", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores a numeric estimate of the user's available network bandwidth in browser localStorage to improve initial adaptive-bitrate quality selection on the next page load, avoiding unnecessary buffering." + }, + { + "identifier": "jwplayer.bitrateSelection", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's manually selected video bitrate in browser localStorage so the same bitrate is pre-selected when the player next loads on this device." + }, + { + "identifier": "jwplayer.qualityLabel", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's manually selected video quality label (e.g. '1080p') in browser localStorage so the same quality level is pre-selected on future visits." + }, + { + "identifier": "jwplayer.enableShortcuts", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores the user's keyboard shortcut preference (enabled/disabled) in browser localStorage so the setting is preserved across sessions." + }, + { + "identifier": "jwplayerLocalId", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores a randomly generated 12-character alphanumeric identifier in browser localStorage used to correlate analytics pings across page loads on the same device." + }, + { + "identifier": "jwplayer.mediaIds", + "type": "web", + "maxAgeSeconds": null, + "purposes": [ + 1 + ], + "description": "Stores a JSON object mapping recently viewed media IDs to their expiry timestamps in browser localStorage to avoid re-surfacing content the user has already watched." + } + ] + } + }, + "purposes": { + "1046": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] } }, "components": [ diff --git a/metadata/modules/jwplayerRtdProvider.json b/metadata/modules/jwplayerRtdProvider.json index a924245c581..247dccfc912 100644 --- a/metadata/modules/jwplayerRtdProvider.json +++ b/metadata/modules/jwplayerRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/kargoAnalyticsAdapter.json b/metadata/modules/kargoAnalyticsAdapter.json index 89a29c21999..a62460784f0 100644 --- a/metadata/modules/kargoAnalyticsAdapter.json +++ b/metadata/modules/kargoAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/kargoBidAdapter.json b/metadata/modules/kargoBidAdapter.json index 9bb3160b5cf..b2995187120 100644 --- a/metadata/modules/kargoBidAdapter.json +++ b/metadata/modules/kargoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://storage.cloud.kargo.com/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:05.075Z", + "timestamp": "2026-06-02T15:44:18.877Z", "disclosures": [ { "identifier": "krg_crb", @@ -36,6 +36,22 @@ ] } }, + "purposes": { + "972": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/kimberliteBidAdapter.json b/metadata/modules/kimberliteBidAdapter.json index 2390e10fa1d..da33a265079 100644 --- a/metadata/modules/kimberliteBidAdapter.json +++ b/metadata/modules/kimberliteBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/kinessoIdSystem.json b/metadata/modules/kinessoIdSystem.json index 9a7719f22e2..2221e3c27b1 100644 --- a/metadata/modules/kinessoIdSystem.json +++ b/metadata/modules/kinessoIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/kiviadsBidAdapter.json b/metadata/modules/kiviadsBidAdapter.json index a1b73cb3275..7ccc6af5936 100644 --- a/metadata/modules/kiviadsBidAdapter.json +++ b/metadata/modules/kiviadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/koblerBidAdapter.json b/metadata/modules/koblerBidAdapter.json index f942422acbe..fee1988b24e 100644 --- a/metadata/modules/koblerBidAdapter.json +++ b/metadata/modules/koblerBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/krushmediaBidAdapter.json b/metadata/modules/krushmediaBidAdapter.json index 96352c242d6..bca2febf9bf 100644 --- a/metadata/modules/krushmediaBidAdapter.json +++ b/metadata/modules/krushmediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/kubientBidAdapter.json b/metadata/modules/kubientBidAdapter.json index eabc6e2fd80..cabee93937b 100644 --- a/metadata/modules/kubientBidAdapter.json +++ b/metadata/modules/kubientBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/kueezRtbBidAdapter.json b/metadata/modules/kueezRtbBidAdapter.json index ccdb590de0a..9d68c1424ae 100644 --- a/metadata/modules/kueezRtbBidAdapter.json +++ b/metadata/modules/kueezRtbBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://en.kueez.com/tcf.json": { - "timestamp": "2026-05-27T12:19:05.235Z", + "timestamp": "2026-06-02T15:44:19.188Z", "disclosures": [ { "identifier": "ck48wz12sqj7", @@ -77,6 +77,25 @@ ] } }, + "purposes": { + "1165": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lane4BidAdapter.json b/metadata/modules/lane4BidAdapter.json index d9f268a4e31..74090a12fd6 100644 --- a/metadata/modules/lane4BidAdapter.json +++ b/metadata/modules/lane4BidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lassoBidAdapter.json b/metadata/modules/lassoBidAdapter.json index 6380660d7ca..daaaab166bc 100644 --- a/metadata/modules/lassoBidAdapter.json +++ b/metadata/modules/lassoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/leagueMBidAdapter.json b/metadata/modules/leagueMBidAdapter.json index f4b02875bbb..f4ef325c50f 100644 --- a/metadata/modules/leagueMBidAdapter.json +++ b/metadata/modules/leagueMBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lemmaDigitalBidAdapter.json b/metadata/modules/lemmaDigitalBidAdapter.json index 38ea096d9dd..c0f6575558b 100644 --- a/metadata/modules/lemmaDigitalBidAdapter.json +++ b/metadata/modules/lemmaDigitalBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lifestreetBidAdapter.json b/metadata/modules/lifestreetBidAdapter.json index 041662d82fa..6c13b54f981 100644 --- a/metadata/modules/lifestreetBidAdapter.json +++ b/metadata/modules/lifestreetBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/limelightDigitalBidAdapter.json b/metadata/modules/limelightDigitalBidAdapter.json index 4a7913c95eb..d8a0e53360f 100644 --- a/metadata/modules/limelightDigitalBidAdapter.json +++ b/metadata/modules/limelightDigitalBidAdapter.json @@ -2,14 +2,57 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://policy.iion.io/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:05.281Z", + "timestamp": "2026-06-02T15:44:19.517Z", "disclosures": [] }, "https://orangeclickmedia.com/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:05.565Z", + "timestamp": "2026-06-02T15:44:19.890Z", "disclosures": [] } }, + "purposes": { + "1148": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 11 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 8 + ], + "specialFeatures": [] + }, + "1358": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/liveIntentAnalyticsAdapter.json b/metadata/modules/liveIntentAnalyticsAdapter.json index e8043f9ae7c..f7c6ad26150 100644 --- a/metadata/modules/liveIntentAnalyticsAdapter.json +++ b/metadata/modules/liveIntentAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/liveIntentIdSystem.json b/metadata/modules/liveIntentIdSystem.json index c1d99acc62a..89c488592ff 100644 --- a/metadata/modules/liveIntentIdSystem.json +++ b/metadata/modules/liveIntentIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://b-code.liadm.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:05.565Z", + "timestamp": "2026-06-02T15:44:19.890Z", "disclosures": [ { "identifier": "_lc2_fpi", @@ -173,6 +173,18 @@ ] } }, + "purposes": { + "148": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/liveIntentRtdProvider.json b/metadata/modules/liveIntentRtdProvider.json index d7495d7abb1..34f92369896 100644 --- a/metadata/modules/liveIntentRtdProvider.json +++ b/metadata/modules/liveIntentRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://b-code.liadm.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:05.747Z", + "timestamp": "2026-06-02T15:44:20.131Z", "disclosures": [ { "identifier": "_lc2_fpi", @@ -173,6 +173,18 @@ ] } }, + "purposes": { + "148": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/livewrappedAnalyticsAdapter.json b/metadata/modules/livewrappedAnalyticsAdapter.json index 2190e7465de..8c399362515 100644 --- a/metadata/modules/livewrappedAnalyticsAdapter.json +++ b/metadata/modules/livewrappedAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/livewrappedBidAdapter.json b/metadata/modules/livewrappedBidAdapter.json index 91477cb0d8a..5cdad81e4e8 100644 --- a/metadata/modules/livewrappedBidAdapter.json +++ b/metadata/modules/livewrappedBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://content.lwadm.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:05.747Z", + "timestamp": "2026-06-02T15:44:20.131Z", "disclosures": [ { "cookieRefresh": false, @@ -43,6 +43,23 @@ ] } }, + "purposes": { + "919": { + "purposes": [ + 1, + 10 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lkqdBidAdapter.json b/metadata/modules/lkqdBidAdapter.json index ae90fcb82b4..a1db1947690 100644 --- a/metadata/modules/lkqdBidAdapter.json +++ b/metadata/modules/lkqdBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lm_kiviadsBidAdapter.json b/metadata/modules/lm_kiviadsBidAdapter.json index a9e3d6a074a..eefe44742a8 100644 --- a/metadata/modules/lm_kiviadsBidAdapter.json +++ b/metadata/modules/lm_kiviadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lmpIdSystem.json b/metadata/modules/lmpIdSystem.json index 1a59c9bee6d..c098bf9f052 100644 --- a/metadata/modules/lmpIdSystem.json +++ b/metadata/modules/lmpIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/locIdSystem.json b/metadata/modules/locIdSystem.json index 87e8fc03475..79a1b5fa0b6 100644 --- a/metadata/modules/locIdSystem.json +++ b/metadata/modules/locIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/lockerdomeBidAdapter.json b/metadata/modules/lockerdomeBidAdapter.json index 21a1ab40f47..f4f8c163221 100644 --- a/metadata/modules/lockerdomeBidAdapter.json +++ b/metadata/modules/lockerdomeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lockrAIMIdSystem.json b/metadata/modules/lockrAIMIdSystem.json index f7ea79371db..10d06943809 100644 --- a/metadata/modules/lockrAIMIdSystem.json +++ b/metadata/modules/lockrAIMIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/loganBidAdapter.json b/metadata/modules/loganBidAdapter.json index 2a3e8bd80e2..8efbb0ba6a3 100644 --- a/metadata/modules/loganBidAdapter.json +++ b/metadata/modules/loganBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/logicadBidAdapter.json b/metadata/modules/logicadBidAdapter.json index 6315c6f43ea..0a11cf2fec8 100644 --- a/metadata/modules/logicadBidAdapter.json +++ b/metadata/modules/logicadBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/loglyBidAdapter.json b/metadata/modules/loglyBidAdapter.json index bd00192e2a4..c8504a535e0 100644 --- a/metadata/modules/loglyBidAdapter.json +++ b/metadata/modules/loglyBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/loopmeBidAdapter.json b/metadata/modules/loopmeBidAdapter.json index 4621bda4e36..632659ace17 100644 --- a/metadata/modules/loopmeBidAdapter.json +++ b/metadata/modules/loopmeBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://co.loopme.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:05.887Z", + "timestamp": "2026-06-02T15:44:20.387Z", "disclosures": [] } }, + "purposes": { + "109": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lotamePanoramaIdSystem.json b/metadata/modules/lotamePanoramaIdSystem.json index 98e0bb89031..330b14e0f75 100644 --- a/metadata/modules/lotamePanoramaIdSystem.json +++ b/metadata/modules/lotamePanoramaIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tags.crwdcntrl.net/privacy/tcf-purposes.json": { - "timestamp": "2026-05-27T12:19:06.105Z", + "timestamp": "2026-06-02T15:44:20.916Z", "disclosures": [ { "identifier": "_cc_id", @@ -221,6 +221,26 @@ ] } }, + "purposes": { + "95": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/loyalBidAdapter.json b/metadata/modules/loyalBidAdapter.json index 6ceaaf6c42f..90d978dcc81 100644 --- a/metadata/modules/loyalBidAdapter.json +++ b/metadata/modules/loyalBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/luceadBidAdapter.json b/metadata/modules/luceadBidAdapter.json index 1e0ed3b7453..e70232833a9 100644 --- a/metadata/modules/luceadBidAdapter.json +++ b/metadata/modules/luceadBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/lunamediahbBidAdapter.json b/metadata/modules/lunamediahbBidAdapter.json index dff1335b034..0eb773078ed 100644 --- a/metadata/modules/lunamediahbBidAdapter.json +++ b/metadata/modules/lunamediahbBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/luponmediaBidAdapter.json b/metadata/modules/luponmediaBidAdapter.json index 0bcfe104263..5fde51b7aa3 100644 --- a/metadata/modules/luponmediaBidAdapter.json +++ b/metadata/modules/luponmediaBidAdapter.json @@ -2,10 +2,38 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://luponmedia.com/vendor_device_storage.json": { - "timestamp": "2026-05-27T12:19:06.262Z", + "timestamp": "2026-06-02T15:44:21.141Z", "disclosures": [] } }, + "purposes": { + "1132": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mabidderBidAdapter.json b/metadata/modules/mabidderBidAdapter.json index 60a4eca6f90..abde16e7dfe 100644 --- a/metadata/modules/mabidderBidAdapter.json +++ b/metadata/modules/mabidderBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/madsenseBidAdapter.json b/metadata/modules/madsenseBidAdapter.json index c18b0d7bef9..2d9ec7b4872 100644 --- a/metadata/modules/madsenseBidAdapter.json +++ b/metadata/modules/madsenseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/madvertiseBidAdapter.json b/metadata/modules/madvertiseBidAdapter.json index d626c5ffdd3..ad11ab52018 100644 --- a/metadata/modules/madvertiseBidAdapter.json +++ b/metadata/modules/madvertiseBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserver.bluestack.app/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:06.693Z", + "timestamp": "2026-06-02T15:44:22.053Z", "disclosures": [] } }, + "purposes": { + "153": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/magniteAnalyticsAdapter.json b/metadata/modules/magniteAnalyticsAdapter.json index 3a8ec985911..8092f1df833 100644 --- a/metadata/modules/magniteAnalyticsAdapter.json +++ b/metadata/modules/magniteAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/magniteBidAdapter.json b/metadata/modules/magniteBidAdapter.json index 933df2a08b1..135970db34f 100644 --- a/metadata/modules/magniteBidAdapter.json +++ b/metadata/modules/magniteBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.rubiconproject.com/dvplus/devicestoragedisclosure.json": { - "timestamp": "2026-05-27T12:19:07.130Z", + "timestamp": "2026-06-02T15:44:22.919Z", "disclosures": [] } }, + "purposes": { + "52": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/malltvAnalyticsAdapter.json b/metadata/modules/malltvAnalyticsAdapter.json index 84f2fcbe6b9..758a80bd9ed 100644 --- a/metadata/modules/malltvAnalyticsAdapter.json +++ b/metadata/modules/malltvAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/malltvBidAdapter.json b/metadata/modules/malltvBidAdapter.json index 90875da57d2..15cde636de8 100644 --- a/metadata/modules/malltvBidAdapter.json +++ b/metadata/modules/malltvBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mantisBidAdapter.json b/metadata/modules/mantisBidAdapter.json index cfcbcbfa59d..bd55c87110d 100644 --- a/metadata/modules/mantisBidAdapter.json +++ b/metadata/modules/mantisBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/marsmediaBidAdapter.json b/metadata/modules/marsmediaBidAdapter.json index 78dbe5d41dd..465afee1bcd 100644 --- a/metadata/modules/marsmediaBidAdapter.json +++ b/metadata/modules/marsmediaBidAdapter.json @@ -2,10 +2,20 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mars.media/apis/tcf-v2.json": { - "timestamp": "2026-05-27T12:19:07.406Z", + "timestamp": "2026-06-02T15:44:23.365Z", "disclosures": [] } }, + "purposes": { + "776": { + "purposes": [ + 2 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mathildeadsBidAdapter.json b/metadata/modules/mathildeadsBidAdapter.json index 38e7830419a..2dda742971a 100644 --- a/metadata/modules/mathildeadsBidAdapter.json +++ b/metadata/modules/mathildeadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/matterfullBidAdapter.json b/metadata/modules/matterfullBidAdapter.json index 9e13d965d97..7333990e352 100644 --- a/metadata/modules/matterfullBidAdapter.json +++ b/metadata/modules/matterfullBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediaConsortiumBidAdapter.json b/metadata/modules/mediaConsortiumBidAdapter.json index 5e4bdec73c9..69993732452 100644 --- a/metadata/modules/mediaConsortiumBidAdapter.json +++ b/metadata/modules/mediaConsortiumBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.hubvisor.io/assets/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:07.601Z", + "timestamp": "2026-06-02T15:44:23.783Z", "disclosures": [ { "identifier": "hbv:turbo-cmp", @@ -52,6 +52,16 @@ ] } }, + "purposes": { + "1112": { + "purposes": [ + 1 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediabramaBidAdapter.json b/metadata/modules/mediabramaBidAdapter.json index 0037bc9e8d3..0730f34ec28 100644 --- a/metadata/modules/mediabramaBidAdapter.json +++ b/metadata/modules/mediabramaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediaeyesBidAdapter.json b/metadata/modules/mediaeyesBidAdapter.json index 51ee478fa49..20270f40a85 100644 --- a/metadata/modules/mediaeyesBidAdapter.json +++ b/metadata/modules/mediaeyesBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediafilterRtdProvider.json b/metadata/modules/mediafilterRtdProvider.json index b004566f20d..d6a09757a60 100644 --- a/metadata/modules/mediafilterRtdProvider.json +++ b/metadata/modules/mediafilterRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/mediaforceBidAdapter.json b/metadata/modules/mediaforceBidAdapter.json index 323f54affcd..b7ff008155d 100644 --- a/metadata/modules/mediaforceBidAdapter.json +++ b/metadata/modules/mediaforceBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://comparisons.org/privacy.json": { - "timestamp": "2026-05-27T12:19:07.602Z", + "timestamp": "2026-06-02T15:44:23.783Z", "disclosures": [] } }, + "purposes": { + "671": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "legIntPurposes": [ + 2, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediafuseBidAdapter.json b/metadata/modules/mediafuseBidAdapter.json index 8493e920091..1b3a9b4c296 100644 --- a/metadata/modules/mediafuseBidAdapter.json +++ b/metadata/modules/mediafuseBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:19:07.864Z", + "timestamp": "2026-06-02T15:44:24.321Z", "disclosures": [] } }, + "purposes": { + "32": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediagoBidAdapter.json b/metadata/modules/mediagoBidAdapter.json index d7f51e59636..baa249fb5ea 100644 --- a/metadata/modules/mediagoBidAdapter.json +++ b/metadata/modules/mediagoBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.mediago.io/js/tcf.json": { - "timestamp": "2026-05-27T12:19:07.865Z", + "timestamp": "2026-06-02T15:44:24.321Z", "disclosures": [] } }, + "purposes": { + "1020": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediaimpactBidAdapter.json b/metadata/modules/mediaimpactBidAdapter.json index 8b3b30c8cc5..f680a9c83c1 100644 --- a/metadata/modules/mediaimpactBidAdapter.json +++ b/metadata/modules/mediaimpactBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediakeysBidAdapter.json b/metadata/modules/mediakeysBidAdapter.json index 7287a4249b7..c8c18fc3390 100644 --- a/metadata/modules/mediakeysBidAdapter.json +++ b/metadata/modules/mediakeysBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s3.eu-west-3.amazonaws.com/adserving.resourcekeys.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:07.956Z", + "timestamp": "2026-06-02T15:44:24.898Z", "disclosures": [] } }, + "purposes": { + "498": { + "purposes": [ + 1, + 2, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/medianetAnalyticsAdapter.json b/metadata/modules/medianetAnalyticsAdapter.json index af974640059..4b9535bf91f 100644 --- a/metadata/modules/medianetAnalyticsAdapter.json +++ b/metadata/modules/medianetAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/medianetBidAdapter.json b/metadata/modules/medianetBidAdapter.json index 675cf7a58ed..69af5f63c60 100644 --- a/metadata/modules/medianetBidAdapter.json +++ b/metadata/modules/medianetBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.media.net/tcfv2/gvl/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:08.398Z", + "timestamp": "2026-06-02T15:44:25.529Z", "disclosures": [ { "identifier": "_mNExInsl", @@ -246,7 +246,7 @@ ] }, "https://trustedstack.com/tcf/gvl/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:08.534Z", + "timestamp": "2026-06-02T15:44:26.256Z", "disclosures": [ { "identifier": "usp_status", @@ -262,6 +262,43 @@ ] } }, + "purposes": { + "142": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + }, + "1288": { + "purposes": [ + 1, + 4 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/medianetRtdProvider.json b/metadata/modules/medianetRtdProvider.json index 4a198feed0f..6e3c4d1d409 100644 --- a/metadata/modules/medianetRtdProvider.json +++ b/metadata/modules/medianetRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/mediasniperBidAdapter.json b/metadata/modules/mediasniperBidAdapter.json index 10e1fc2a2fa..0bbb2e7fade 100644 --- a/metadata/modules/mediasniperBidAdapter.json +++ b/metadata/modules/mediasniperBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mediasquareBidAdapter.json b/metadata/modules/mediasquareBidAdapter.json index f5d7b25ff81..37f5f3abb74 100644 --- a/metadata/modules/mediasquareBidAdapter.json +++ b/metadata/modules/mediasquareBidAdapter.json @@ -2,10 +2,21 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mediasquare.fr/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:08.777Z", + "timestamp": "2026-06-02T15:44:26.687Z", "disclosures": [] } }, + "purposes": { + "791": { + "purposes": [ + 1, + 2 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/merkleIdSystem.json b/metadata/modules/merkleIdSystem.json index cc32ff4c32c..d69f3a37301 100644 --- a/metadata/modules/merkleIdSystem.json +++ b/metadata/modules/merkleIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/mgidBidAdapter.json b/metadata/modules/mgidBidAdapter.json index c3bfa1b35e4..f21196b162a 100644 --- a/metadata/modules/mgidBidAdapter.json +++ b/metadata/modules/mgidBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-27T12:19:09.069Z", + "timestamp": "2026-06-02T15:44:27.364Z", "disclosures": [] } }, + "purposes": { + "358": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mgidRtdProvider.json b/metadata/modules/mgidRtdProvider.json index fe64f24e2c1..e2d52b9e919 100644 --- a/metadata/modules/mgidRtdProvider.json +++ b/metadata/modules/mgidRtdProvider.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-27T12:19:09.106Z", + "timestamp": "2026-06-02T15:44:27.667Z", "disclosures": [] } }, + "purposes": { + "358": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/mgidXBidAdapter.json b/metadata/modules/mgidXBidAdapter.json index 7ea804cd59e..6069c79ecfb 100644 --- a/metadata/modules/mgidXBidAdapter.json +++ b/metadata/modules/mgidXBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.mgid.com/assets/devicestorage.json": { - "timestamp": "2026-05-27T12:19:09.106Z", + "timestamp": "2026-06-02T15:44:27.667Z", "disclosures": [] } }, + "purposes": { + "358": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/michaoBidAdapter.json b/metadata/modules/michaoBidAdapter.json index ad4738bd330..b9548baf8d6 100644 --- a/metadata/modules/michaoBidAdapter.json +++ b/metadata/modules/michaoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/microadBidAdapter.json b/metadata/modules/microadBidAdapter.json index dadbbe5dfe4..15fb4590e0a 100644 --- a/metadata/modules/microadBidAdapter.json +++ b/metadata/modules/microadBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mileBidAdapter.json b/metadata/modules/mileBidAdapter.json index ba3e8b683fc..567f2a069a7 100644 --- a/metadata/modules/mileBidAdapter.json +++ b/metadata/modules/mileBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mileRtdProvider.json b/metadata/modules/mileRtdProvider.json index e4420a295c5..03d79c236a6 100644 --- a/metadata/modules/mileRtdProvider.json +++ b/metadata/modules/mileRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/minutemediaBidAdapter.json b/metadata/modules/minutemediaBidAdapter.json index 65fa27d6b93..de148cbbfa6 100644 --- a/metadata/modules/minutemediaBidAdapter.json +++ b/metadata/modules/minutemediaBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://disclosures.mmctsvc.com/device-storage.json": { - "timestamp": "2026-05-27T12:19:09.107Z", + "timestamp": "2026-06-02T15:44:27.667Z", "disclosures": [] } }, + "purposes": { + "918": { + "purposes": [ + 1, + 2, + 5, + 6 + ], + "legIntPurposes": [ + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/missenaBidAdapter.json b/metadata/modules/missenaBidAdapter.json index c2b83b1d83c..1246b011691 100644 --- a/metadata/modules/missenaBidAdapter.json +++ b/metadata/modules/missenaBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.missena.io/iab.json": { - "timestamp": "2026-05-27T12:19:09.224Z", + "timestamp": "2026-06-02T15:44:27.968Z", "disclosures": [] } }, + "purposes": { + "687": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mobfoxpbBidAdapter.json b/metadata/modules/mobfoxpbBidAdapter.json index 4c25483443b..b3a41a22c88 100644 --- a/metadata/modules/mobfoxpbBidAdapter.json +++ b/metadata/modules/mobfoxpbBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mobianRtdProvider.json b/metadata/modules/mobianRtdProvider.json index 77cb287c355..edf55d0c855 100644 --- a/metadata/modules/mobianRtdProvider.json +++ b/metadata/modules/mobianRtdProvider.json @@ -2,10 +2,20 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://js.outcomes.net/tcf.json": { - "timestamp": "2026-05-27T12:19:09.507Z", + "timestamp": "2026-06-02T15:44:28.386Z", "disclosures": [] } }, + "purposes": { + "1348": { + "purposes": [ + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/mobilefuseBidAdapter.json b/metadata/modules/mobilefuseBidAdapter.json index 5ad02f2fdbe..4fc69271645 100644 --- a/metadata/modules/mobilefuseBidAdapter.json +++ b/metadata/modules/mobilefuseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mobkoiAnalyticsAdapter.json b/metadata/modules/mobkoiAnalyticsAdapter.json index 41547550cbd..ca4f8b5f04f 100644 --- a/metadata/modules/mobkoiAnalyticsAdapter.json +++ b/metadata/modules/mobkoiAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/mobkoiBidAdapter.json b/metadata/modules/mobkoiBidAdapter.json index 4ffeca08c95..3dfa3897948 100644 --- a/metadata/modules/mobkoiBidAdapter.json +++ b/metadata/modules/mobkoiBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.maximus.mobkoi.com/tcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:09.662Z", + "timestamp": "2026-06-02T15:44:28.623Z", "disclosures": [] } }, + "purposes": { + "898": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mobkoiIdSystem.json b/metadata/modules/mobkoiIdSystem.json index 7a9ce3163de..1a06df61778 100644 --- a/metadata/modules/mobkoiIdSystem.json +++ b/metadata/modules/mobkoiIdSystem.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.maximus.mobkoi.com/tcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:09.801Z", + "timestamp": "2026-06-02T15:44:28.877Z", "disclosures": [] } }, + "purposes": { + "898": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/movingupBidAdapter.json b/metadata/modules/movingupBidAdapter.json index 8ad3fcc76f5..c9e84f204d1 100644 --- a/metadata/modules/movingupBidAdapter.json +++ b/metadata/modules/movingupBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/msftBidAdapter.json b/metadata/modules/msftBidAdapter.json index 365132aaafd..cb6e12b6616 100644 --- a/metadata/modules/msftBidAdapter.json +++ b/metadata/modules/msftBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json": { - "timestamp": "2026-05-27T12:19:09.801Z", + "timestamp": "2026-06-02T15:44:28.877Z", "disclosures": [] } }, + "purposes": { + "32": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", @@ -13,6 +35,13 @@ "aliasOf": null, "gvlid": 32, "disclosureURL": "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json" + }, + { + "componentType": "bidder", + "componentName": "oftmedia", + "aliasOf": "msft", + "gvlid": 32, + "disclosureURL": "https://acdn.adnxs.com/gvl/1d/xandrdevicestoragedisclosures.json" } ] } \ No newline at end of file diff --git a/metadata/modules/mtcBidAdapter.json b/metadata/modules/mtcBidAdapter.json index fb175544e63..90cad9ab5a0 100644 --- a/metadata/modules/mtcBidAdapter.json +++ b/metadata/modules/mtcBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mwOpenLinkIdSystem.json b/metadata/modules/mwOpenLinkIdSystem.json index d138e555c96..8cb80f2dba6 100644 --- a/metadata/modules/mwOpenLinkIdSystem.json +++ b/metadata/modules/mwOpenLinkIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/my6senseBidAdapter.json b/metadata/modules/my6senseBidAdapter.json index 25457451e98..da5ef18bda7 100644 --- a/metadata/modules/my6senseBidAdapter.json +++ b/metadata/modules/my6senseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mycodemediaBidAdapter.json b/metadata/modules/mycodemediaBidAdapter.json index 6fdf70e5b1f..4a1822c137d 100644 --- a/metadata/modules/mycodemediaBidAdapter.json +++ b/metadata/modules/mycodemediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/mygaruIdSystem.json b/metadata/modules/mygaruIdSystem.json index af8246c0ccc..2374f457890 100644 --- a/metadata/modules/mygaruIdSystem.json +++ b/metadata/modules/mygaruIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/mytargetBidAdapter.json b/metadata/modules/mytargetBidAdapter.json index abe7501341a..29c30ad7074 100644 --- a/metadata/modules/mytargetBidAdapter.json +++ b/metadata/modules/mytargetBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nativeryBidAdapter.json b/metadata/modules/nativeryBidAdapter.json index 0ef07c347c4..150a8dd65cd 100644 --- a/metadata/modules/nativeryBidAdapter.json +++ b/metadata/modules/nativeryBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdnimg.nativery.com/widget/js/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:09.802Z", + "timestamp": "2026-06-02T15:44:28.877Z", "disclosures": [] } }, + "purposes": { + "1133": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nativoBidAdapter.json b/metadata/modules/nativoBidAdapter.json index ddc69cf2d50..3a9c16cdb49 100644 --- a/metadata/modules/nativoBidAdapter.json +++ b/metadata/modules/nativoBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab.nativo.com/tcf-disclosures.json": { - "timestamp": "2026-05-27T12:19:10.190Z", + "timestamp": "2026-06-02T15:44:29.644Z", "disclosures": [] } }, + "purposes": { + "263": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/naveggIdSystem.json b/metadata/modules/naveggIdSystem.json index d3594beccf8..86ebcb35096 100644 --- a/metadata/modules/naveggIdSystem.json +++ b/metadata/modules/naveggIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/netIdSystem.json b/metadata/modules/netIdSystem.json index d0f489fa809..e07e244598a 100644 --- a/metadata/modules/netIdSystem.json +++ b/metadata/modules/netIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/neuwoRtdProvider.json b/metadata/modules/neuwoRtdProvider.json index 192b90186c2..b1845bede9b 100644 --- a/metadata/modules/neuwoRtdProvider.json +++ b/metadata/modules/neuwoRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/newspassidBidAdapter.json b/metadata/modules/newspassidBidAdapter.json index 8b2c5ed5e9b..a97f336223d 100644 --- a/metadata/modules/newspassidBidAdapter.json +++ b/metadata/modules/newspassidBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn-prod.aditude.com/storageaccess.json": { - "timestamp": "2026-05-27T12:19:10.247Z", + "timestamp": "2026-06-02T15:44:29.968Z", "disclosures": [] } }, + "purposes": { + "1317": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nextMillenniumBidAdapter.json b/metadata/modules/nextMillenniumBidAdapter.json index bbe2f6a0221..ca29536b4b8 100644 --- a/metadata/modules/nextMillenniumBidAdapter.json +++ b/metadata/modules/nextMillenniumBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://nextmillennium.io/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:10.247Z", + "timestamp": "2026-06-02T15:44:29.968Z", "disclosures": [] } }, + "purposes": { + "1060": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nextrollBidAdapter.json b/metadata/modules/nextrollBidAdapter.json index fb0b48c9ebf..f7d4d329cfc 100644 --- a/metadata/modules/nextrollBidAdapter.json +++ b/metadata/modules/nextrollBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.adroll.com/shares/device_storage.json": { - "timestamp": "2026-05-27T12:19:10.297Z", + "timestamp": "2026-06-02T15:44:30.651Z", "disclosures": [ { "identifier": "__adroll_fpc", @@ -92,6 +92,24 @@ ] } }, + "purposes": { + "130": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nexverseBidAdapter.json b/metadata/modules/nexverseBidAdapter.json index cf19ed74603..24a33ee5c98 100644 --- a/metadata/modules/nexverseBidAdapter.json +++ b/metadata/modules/nexverseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nexx360BidAdapter.json b/metadata/modules/nexx360BidAdapter.json index c40297df520..c41b743035f 100644 --- a/metadata/modules/nexx360BidAdapter.json +++ b/metadata/modules/nexx360BidAdapter.json @@ -2,19 +2,19 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://fast.nexx360.io/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:12.289Z", + "timestamp": "2026-06-02T15:44:33.911Z", "disclosures": [] }, "https://static.first-id.fr/tcf/cookie.json": { - "timestamp": "2026-05-27T12:19:10.635Z", + "timestamp": "2026-06-02T15:44:31.268Z", "disclosures": [] }, "https://i.plug.it/banners/js/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:11.177Z", + "timestamp": "2026-06-02T15:44:31.992Z", "disclosures": [] }, "https://player.glomex.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:11.864Z", + "timestamp": "2026-06-02T15:44:32.936Z", "disclosures": [ { "identifier": "glomexUser", @@ -55,7 +55,7 @@ ] }, "https://gdpr.pubx.ai/devicestoragedisclosure.json": { - "timestamp": "2026-05-27T12:19:11.864Z", + "timestamp": "2026-06-02T15:44:32.936Z", "disclosures": [ { "identifier": "pubx:defaults", @@ -70,7 +70,7 @@ ] }, "https://yieldbird.com/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:11.906Z", + "timestamp": "2026-06-02T15:44:33.184Z", "disclosures": [ { "identifier": "pm_utm_*", @@ -117,6 +117,101 @@ ] } }, + "purposes": { + "965": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 10 + ], + "specialFeatures": [] + }, + "967": { + "purposes": [ + 1, + 3, + 4, + 6, + 9 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "specialFeatures": [] + }, + "1068": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + }, + "1178": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + }, + "1253": { + "purposes": [ + 1, + 2 + ], + "legIntPurposes": [ + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + }, + "1485": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nobidAnalyticsAdapter.json b/metadata/modules/nobidAnalyticsAdapter.json index 53046516795..097eebb4c6b 100644 --- a/metadata/modules/nobidAnalyticsAdapter.json +++ b/metadata/modules/nobidAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/nobidBidAdapter.json b/metadata/modules/nobidBidAdapter.json index 31c8ca804c4..a4ea59c5d8f 100644 --- a/metadata/modules/nobidBidAdapter.json +++ b/metadata/modules/nobidBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://public.servenobid.com/gdpr_tcf/vendor_device_storage_operational_disclosures.json": { - "timestamp": "2026-05-27T12:19:12.290Z", + "timestamp": "2026-06-02T15:44:33.912Z", "disclosures": [] } }, + "purposes": { + "816": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nodalsAiRtdProvider.json b/metadata/modules/nodalsAiRtdProvider.json index 5ccb789150a..385796bf5bb 100644 --- a/metadata/modules/nodalsAiRtdProvider.json +++ b/metadata/modules/nodalsAiRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.nodals.ai/vendor.json": { - "timestamp": "2026-05-27T12:19:12.379Z", + "timestamp": "2026-06-02T15:44:34.109Z", "disclosures": [ { "identifier": "localStorage", @@ -19,6 +19,20 @@ ] } }, + "purposes": { + "1360": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/novatiqIdSystem.json b/metadata/modules/novatiqIdSystem.json index 3503a377a43..71c1aac3b35 100644 --- a/metadata/modules/novatiqIdSystem.json +++ b/metadata/modules/novatiqIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://novatiq.com/privacy/iab/novatiq.json": { - "timestamp": "2026-05-27T12:19:12.614Z", + "timestamp": "2026-06-02T15:44:34.407Z", "disclosures": [ { "identifier": "novatiq", @@ -18,6 +18,18 @@ ] } }, + "purposes": { + "1119": { + "purposes": [ + 1, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/ntvagentsBidAdapter.json b/metadata/modules/ntvagentsBidAdapter.json index dda35e32a9b..413db390fb5 100644 --- a/metadata/modules/ntvagentsBidAdapter.json +++ b/metadata/modules/ntvagentsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/nubaBidAdapter.json b/metadata/modules/nubaBidAdapter.json index 1ee19306146..08368d34fd5 100644 --- a/metadata/modules/nubaBidAdapter.json +++ b/metadata/modules/nubaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/oftmediaRtdProvider.json b/metadata/modules/oftmediaRtdProvider.json index 2fb8627ad60..461dae835f5 100644 --- a/metadata/modules/oftmediaRtdProvider.json +++ b/metadata/modules/oftmediaRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/oguryBidAdapter.json b/metadata/modules/oguryBidAdapter.json index fab898b5f9f..6f9eb369aff 100644 --- a/metadata/modules/oguryBidAdapter.json +++ b/metadata/modules/oguryBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://privacy.ogury.co/disclosure.json": { - "timestamp": "2026-05-27T12:19:12.963Z", + "timestamp": "2026-06-02T15:44:35.218Z", "disclosures": [] } }, + "purposes": { + "31": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/omnidexBidAdapter.json b/metadata/modules/omnidexBidAdapter.json index 06874b573c4..9405a0bb9c1 100644 --- a/metadata/modules/omnidexBidAdapter.json +++ b/metadata/modules/omnidexBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.omni-dex.io/devicestorage.json": { - "timestamp": "2026-05-27T12:19:13.102Z", + "timestamp": "2026-06-02T15:44:35.539Z", "disclosures": [ { "identifier": "ck48wz12sqj7", @@ -77,6 +77,25 @@ ] } }, + "purposes": { + "1463": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/omsBidAdapter.json b/metadata/modules/omsBidAdapter.json index 84b153fbcc9..3bf86441f60 100644 --- a/metadata/modules/omsBidAdapter.json +++ b/metadata/modules/omsBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.marphezis.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-27T12:19:13.168Z", + "timestamp": "2026-06-02T15:44:35.851Z", "disclosures": [] } }, + "purposes": { + "883": { + "purposes": [], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/oneKeyIdSystem.json b/metadata/modules/oneKeyIdSystem.json index 0ac005ca6c0..f318fec7b02 100644 --- a/metadata/modules/oneKeyIdSystem.json +++ b/metadata/modules/oneKeyIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/oneKeyRtdProvider.json b/metadata/modules/oneKeyRtdProvider.json index 437edfd3f43..67f054c7e13 100644 --- a/metadata/modules/oneKeyRtdProvider.json +++ b/metadata/modules/oneKeyRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/onetagBidAdapter.json b/metadata/modules/onetagBidAdapter.json index 119ca338c97..5277a7cc028 100644 --- a/metadata/modules/onetagBidAdapter.json +++ b/metadata/modules/onetagBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://onetag-cdn.com/privacy/tcf_storage.json": { - "timestamp": "2026-05-27T12:19:13.168Z", + "timestamp": "2026-06-02T15:44:35.851Z", "disclosures": [ { "identifier": "onetag_sid", @@ -20,6 +20,27 @@ ] } }, + "purposes": { + "241": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/onomagicBidAdapter.json b/metadata/modules/onomagicBidAdapter.json index 5d2f0c4cb31..86dd80eaf37 100644 --- a/metadata/modules/onomagicBidAdapter.json +++ b/metadata/modules/onomagicBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ooloAnalyticsAdapter.json b/metadata/modules/ooloAnalyticsAdapter.json index c4d5e7ac853..0ac4e531365 100644 --- a/metadata/modules/ooloAnalyticsAdapter.json +++ b/metadata/modules/ooloAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/opaMarketplaceBidAdapter.json b/metadata/modules/opaMarketplaceBidAdapter.json index ecf55c03f45..72ca57af3ed 100644 --- a/metadata/modules/opaMarketplaceBidAdapter.json +++ b/metadata/modules/opaMarketplaceBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/open8BidAdapter.json b/metadata/modules/open8BidAdapter.json index 90db84d2462..aeab9dffc2d 100644 --- a/metadata/modules/open8BidAdapter.json +++ b/metadata/modules/open8BidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/openPairIdSystem.json b/metadata/modules/openPairIdSystem.json index dfe5580badf..449136a36dd 100644 --- a/metadata/modules/openPairIdSystem.json +++ b/metadata/modules/openPairIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/openwebBidAdapter.json b/metadata/modules/openwebBidAdapter.json index c963896148b..96b51cd919b 100644 --- a/metadata/modules/openwebBidAdapter.json +++ b/metadata/modules/openwebBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://spotim-prd-static-assets.s3.amazonaws.com/iab/device-storage.json": { - "timestamp": "2026-05-27T12:19:13.508Z", + "timestamp": "2026-06-02T15:44:36.336Z", "disclosures": [] } }, + "purposes": { + "280": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/openxBidAdapter.json b/metadata/modules/openxBidAdapter.json index 1a51c3cec01..7307c650c4d 100644 --- a/metadata/modules/openxBidAdapter.json +++ b/metadata/modules/openxBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.openx.com/device-storage.json": { - "timestamp": "2026-05-27T12:19:13.641Z", + "timestamp": "2026-06-02T15:44:36.773Z", "disclosures": [] } }, + "purposes": { + "69": { + "purposes": [ + 1, + 3, + 4, + 7, + 10, + 11 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 7 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/operaadsBidAdapter.json b/metadata/modules/operaadsBidAdapter.json index 05b7cc6d854..c25e72170eb 100644 --- a/metadata/modules/operaadsBidAdapter.json +++ b/metadata/modules/operaadsBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://res.adx.opera.com/dsd.json": { - "timestamp": "2026-05-27T12:19:13.704Z", + "timestamp": "2026-06-02T15:44:37.117Z", "disclosures": [] } }, + "purposes": { + "1135": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 7, + 8 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/operaadsIdSystem.json b/metadata/modules/operaadsIdSystem.json index 0e1f4a3a4c5..cb2079257dc 100644 --- a/metadata/modules/operaadsIdSystem.json +++ b/metadata/modules/operaadsIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/oprxBidAdapter.json b/metadata/modules/oprxBidAdapter.json index 8131b520f88..1065a99e29b 100644 --- a/metadata/modules/oprxBidAdapter.json +++ b/metadata/modules/oprxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/opscoBidAdapter.json b/metadata/modules/opscoBidAdapter.json index 5a13b69035b..2a146f4e1d0 100644 --- a/metadata/modules/opscoBidAdapter.json +++ b/metadata/modules/opscoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/optableRtdProvider.json b/metadata/modules/optableRtdProvider.json index 34ee0f1b3cd..d3763e9faae 100644 --- a/metadata/modules/optableRtdProvider.json +++ b/metadata/modules/optableRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/optidigitalBidAdapter.json b/metadata/modules/optidigitalBidAdapter.json index 8623c711c5a..c6ac634fe8a 100644 --- a/metadata/modules/optidigitalBidAdapter.json +++ b/metadata/modules/optidigitalBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://scripts.opti-digital.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:13.770Z", + "timestamp": "2026-06-02T15:44:37.356Z", "disclosures": [] } }, + "purposes": { + "915": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/optimeraRtdProvider.json b/metadata/modules/optimeraRtdProvider.json index 62d5d1c3aa6..6ceb9011748 100644 --- a/metadata/modules/optimeraRtdProvider.json +++ b/metadata/modules/optimeraRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/optimonAnalyticsAdapter.json b/metadata/modules/optimonAnalyticsAdapter.json index b7cb643c969..331418ec184 100644 --- a/metadata/modules/optimonAnalyticsAdapter.json +++ b/metadata/modules/optimonAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/optoutBidAdapter.json b/metadata/modules/optoutBidAdapter.json index ac420f36e78..52c426eeebd 100644 --- a/metadata/modules/optoutBidAdapter.json +++ b/metadata/modules/optoutBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://adserving.optoutadvertising.com/dsd": { - "timestamp": "2026-05-27T12:19:13.809Z", + "timestamp": "2026-06-02T15:44:37.607Z", "disclosures": [] } }, + "purposes": { + "227": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/orakiBidAdapter.json b/metadata/modules/orakiBidAdapter.json index d013a2f0d16..83c5166febd 100644 --- a/metadata/modules/orakiBidAdapter.json +++ b/metadata/modules/orakiBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/orbidderBidAdapter.json b/metadata/modules/orbidderBidAdapter.json index f79f17ef56e..8f034d46109 100644 --- a/metadata/modules/orbidderBidAdapter.json +++ b/metadata/modules/orbidderBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://orbidder.otto.de/disclosure/dsd.json": { - "timestamp": "2026-05-27T12:19:14.155Z", + "timestamp": "2026-06-02T15:44:38.214Z", "disclosures": [] } }, + "purposes": { + "559": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/orbitsoftBidAdapter.json b/metadata/modules/orbitsoftBidAdapter.json index 4859ce12a99..31a8547a55c 100644 --- a/metadata/modules/orbitsoftBidAdapter.json +++ b/metadata/modules/orbitsoftBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/otmBidAdapter.json b/metadata/modules/otmBidAdapter.json index 0d280e1c6d4..f714f3ff4ba 100644 --- a/metadata/modules/otmBidAdapter.json +++ b/metadata/modules/otmBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/outbrainBidAdapter.json b/metadata/modules/outbrainBidAdapter.json index ac3d83cf583..3bd41d018cb 100644 --- a/metadata/modules/outbrainBidAdapter.json +++ b/metadata/modules/outbrainBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.outbrain.com/privacy/wp-json/privacy/v2/devicestorage.json": { - "timestamp": "2026-05-27T12:19:14.611Z", + "timestamp": "2026-06-02T15:44:38.910Z", "disclosures": [ { "identifier": "dicbo_id", @@ -19,6 +19,28 @@ ] } }, + "purposes": { + "164": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/overtoneRtdProvider.json b/metadata/modules/overtoneRtdProvider.json index 5f6f27c2d19..322345ca1fb 100644 --- a/metadata/modules/overtoneRtdProvider.json +++ b/metadata/modules/overtoneRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/ownadxBidAdapter.json b/metadata/modules/ownadxBidAdapter.json index 16987e2ba02..2cc18409f7c 100644 --- a/metadata/modules/ownadxBidAdapter.json +++ b/metadata/modules/ownadxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/oxxionAnalyticsAdapter.json b/metadata/modules/oxxionAnalyticsAdapter.json index d2e6bc3d692..5581165a81e 100644 --- a/metadata/modules/oxxionAnalyticsAdapter.json +++ b/metadata/modules/oxxionAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/oxxionRtdProvider.json b/metadata/modules/oxxionRtdProvider.json index 678dae3a7f0..8f1d86a8ded 100644 --- a/metadata/modules/oxxionRtdProvider.json +++ b/metadata/modules/oxxionRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/ozoneBidAdapter.json b/metadata/modules/ozoneBidAdapter.json index 1d3f05255c9..bfec1ce7dfa 100644 --- a/metadata/modules/ozoneBidAdapter.json +++ b/metadata/modules/ozoneBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://prebid.the-ozone-project.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:14.641Z", + "timestamp": "2026-06-02T15:44:39.205Z", "disclosures": [] } }, + "purposes": { + "524": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/padsquadBidAdapter.json b/metadata/modules/padsquadBidAdapter.json index 1f6cbb46357..e299a2ef0c3 100644 --- a/metadata/modules/padsquadBidAdapter.json +++ b/metadata/modules/padsquadBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pairIdSystem.json b/metadata/modules/pairIdSystem.json index 470d184870d..ffc59af0704 100644 --- a/metadata/modules/pairIdSystem.json +++ b/metadata/modules/pairIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.gstatic.com/iabtcf/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:14.895Z", + "timestamp": "2026-06-02T15:44:39.613Z", "disclosures": [ { "identifier": "__gads", @@ -410,6 +410,28 @@ ] } }, + "purposes": { + "755": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/pangleBidAdapter.json b/metadata/modules/pangleBidAdapter.json index 4de50503bb9..8a036bf9f50 100644 --- a/metadata/modules/pangleBidAdapter.json +++ b/metadata/modules/pangleBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/panxoBidAdapter.json b/metadata/modules/panxoBidAdapter.json index d2db1fc15e0..c0196ff8b73 100644 --- a/metadata/modules/panxoBidAdapter.json +++ b/metadata/modules/panxoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.panxo.ai/tcf/device-storage.json": { - "timestamp": "2026-05-27T12:19:14.953Z", + "timestamp": "2026-06-02T15:44:39.921Z", "disclosures": [ { "identifier": "panxo_uid", @@ -34,6 +34,31 @@ ] } }, + "purposes": { + "1527": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 8, + 11 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/panxoRtdProvider.json b/metadata/modules/panxoRtdProvider.json index 5ad682b104d..45252b3bf3b 100644 --- a/metadata/modules/panxoRtdProvider.json +++ b/metadata/modules/panxoRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/performaxBidAdapter.json b/metadata/modules/performaxBidAdapter.json index b39c0ec573c..eab44b94939 100644 --- a/metadata/modules/performaxBidAdapter.json +++ b/metadata/modules/performaxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.performax.cz/device_storage.json": { - "timestamp": "2026-05-27T12:19:15.128Z", + "timestamp": "2026-06-02T15:44:40.376Z", "disclosures": [ { "identifier": "px2uid", @@ -15,6 +15,23 @@ ] } }, + "purposes": { + "732": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/permutiveIdentityManagerIdSystem.json b/metadata/modules/permutiveIdentityManagerIdSystem.json index 10db8d396f5..10861463438 100644 --- a/metadata/modules/permutiveIdentityManagerIdSystem.json +++ b/metadata/modules/permutiveIdentityManagerIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.permutive.app/tcf/tcf.json": { - "timestamp": "2026-05-27T12:19:15.675Z", + "timestamp": "2026-06-02T15:44:41.381Z", "disclosures": [ { "identifier": "_pdfps", @@ -274,6 +274,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/permutiveRtdProvider.json b/metadata/modules/permutiveRtdProvider.json index 2795ac124e0..3f4b5f9e5af 100644 --- a/metadata/modules/permutiveRtdProvider.json +++ b/metadata/modules/permutiveRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.permutive.app/tcf/tcf.json": { - "timestamp": "2026-05-27T12:19:15.840Z", + "timestamp": "2026-06-02T15:44:41.863Z", "disclosures": [ { "identifier": "_pdfps", @@ -274,6 +274,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/pgamdirectAnalyticsAdapter.json b/metadata/modules/pgamdirectAnalyticsAdapter.json index c0842f59831..f39e7c2e62d 100644 --- a/metadata/modules/pgamdirectAnalyticsAdapter.json +++ b/metadata/modules/pgamdirectAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pgamdirectBidAdapter.json b/metadata/modules/pgamdirectBidAdapter.json index 3f5f695ce6a..c264cb6bcbb 100644 --- a/metadata/modules/pgamdirectBidAdapter.json +++ b/metadata/modules/pgamdirectBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.pgammedia.com/devicestorage.json": { - "timestamp": "2026-05-27T12:19:15.840Z", + "timestamp": "2026-06-02T15:44:41.863Z", "disclosures": [] } }, + "purposes": { + "1353": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pgamsspBidAdapter.json b/metadata/modules/pgamsspBidAdapter.json index 29237763d3b..320c7de7cfd 100644 --- a/metadata/modules/pgamsspBidAdapter.json +++ b/metadata/modules/pgamsspBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pianoDmpAnalyticsAdapter.json b/metadata/modules/pianoDmpAnalyticsAdapter.json index 85e3e12caa6..0ed8c3a0aa2 100644 --- a/metadata/modules/pianoDmpAnalyticsAdapter.json +++ b/metadata/modules/pianoDmpAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pigeoonBidAdapter.json b/metadata/modules/pigeoonBidAdapter.json index 99dda2a611b..e38eadb892f 100644 --- a/metadata/modules/pigeoonBidAdapter.json +++ b/metadata/modules/pigeoonBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pilotxBidAdapter.json b/metadata/modules/pilotxBidAdapter.json index eec144974b5..1990be30e86 100644 --- a/metadata/modules/pilotxBidAdapter.json +++ b/metadata/modules/pilotxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pinkLionBidAdapter.json b/metadata/modules/pinkLionBidAdapter.json index 64bab5cbeb2..7f16e4cc059 100644 --- a/metadata/modules/pinkLionBidAdapter.json +++ b/metadata/modules/pinkLionBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pixfutureBidAdapter.json b/metadata/modules/pixfutureBidAdapter.json index a9b422a77e8..a0a41f06766 100644 --- a/metadata/modules/pixfutureBidAdapter.json +++ b/metadata/modules/pixfutureBidAdapter.json @@ -6,6 +6,22 @@ "disclosures": [] } }, + "purposes": { + "839": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/playdigoBidAdapter.json b/metadata/modules/playdigoBidAdapter.json index f5beb0c0bfd..584aade1586 100644 --- a/metadata/modules/playdigoBidAdapter.json +++ b/metadata/modules/playdigoBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://playdigo.com/file.json": { - "timestamp": "2026-05-27T12:19:16.019Z", + "timestamp": "2026-06-02T15:44:42.495Z", "disclosures": [] } }, + "purposes": { + "1302": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/playstreamBidAdapter.json b/metadata/modules/playstreamBidAdapter.json index 67fd4f3c0e3..d6f112f6d29 100644 --- a/metadata/modules/playstreamBidAdapter.json +++ b/metadata/modules/playstreamBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/prebid-core.json b/metadata/modules/prebid-core.json index 107694e274c..36596d26810 100644 --- a/metadata/modules/prebid-core.json +++ b/metadata/modules/prebid-core.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/probes.json": { - "timestamp": "2026-05-27T12:17:29.210Z", + "timestamp": "2026-06-02T15:42:53.592Z", "disclosures": [ { "identifier": "_rdc*", @@ -23,7 +23,7 @@ ] }, "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/debugging.json": { - "timestamp": "2026-05-27T12:17:29.210Z", + "timestamp": "2026-06-02T15:42:53.592Z", "disclosures": [ { "identifier": "__*_debugging__", @@ -35,6 +35,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "prebid", diff --git a/metadata/modules/prebidServerBidAdapter.json b/metadata/modules/prebidServerBidAdapter.json index 0638d1c4501..da099a2144c 100644 --- a/metadata/modules/prebidServerBidAdapter.json +++ b/metadata/modules/prebidServerBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/precisoBidAdapter.json b/metadata/modules/precisoBidAdapter.json index 75c522790eb..490e911d23c 100644 --- a/metadata/modules/precisoBidAdapter.json +++ b/metadata/modules/precisoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://preciso.net/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:16.246Z", + "timestamp": "2026-06-02T15:44:42.960Z", "disclosures": [ { "identifier": "XXXXX_viewnew", @@ -110,6 +110,26 @@ ] } }, + "purposes": { + "874": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/prismaBidAdapter.json b/metadata/modules/prismaBidAdapter.json index db901ebc8f3..46753afba08 100644 --- a/metadata/modules/prismaBidAdapter.json +++ b/metadata/modules/prismaBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://fast.nexx360.io/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:16.520Z", + "timestamp": "2026-06-02T15:44:43.970Z", "disclosures": [] } }, + "purposes": { + "965": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/programmaticXBidAdapter.json b/metadata/modules/programmaticXBidAdapter.json index 3f93072b892..a3ac2d67751 100644 --- a/metadata/modules/programmaticXBidAdapter.json +++ b/metadata/modules/programmaticXBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://progrtb.com/tcf-vendor-disclosures.json": { - "timestamp": "2026-05-27T12:19:16.521Z", + "timestamp": "2026-06-02T15:44:43.970Z", "disclosures": [] } }, + "purposes": { + "1344": { + "purposes": [], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/programmaticaBidAdapter.json b/metadata/modules/programmaticaBidAdapter.json index 2226a89e03a..04448bc2dc4 100644 --- a/metadata/modules/programmaticaBidAdapter.json +++ b/metadata/modules/programmaticaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/proxistoreBidAdapter.json b/metadata/modules/proxistoreBidAdapter.json index 9a9991e3200..0299a3b8434 100644 --- a/metadata/modules/proxistoreBidAdapter.json +++ b/metadata/modules/proxistoreBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://abs.proxistore.com/assets/json/proxistore_device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:16.677Z", + "timestamp": "2026-06-02T15:44:44.542Z", "disclosures": [] } }, + "purposes": { + "418": { + "purposes": [ + 1, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pstudioBidAdapter.json b/metadata/modules/pstudioBidAdapter.json index 28f48b1054e..4d49cf72165 100644 --- a/metadata/modules/pstudioBidAdapter.json +++ b/metadata/modules/pstudioBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubCircleBidAdapter.json b/metadata/modules/pubCircleBidAdapter.json index 650099f73fa..6b84280c6f5 100644 --- a/metadata/modules/pubCircleBidAdapter.json +++ b/metadata/modules/pubCircleBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubProvidedIdSystem.json b/metadata/modules/pubProvidedIdSystem.json index 23a8f180280..9074b016680 100644 --- a/metadata/modules/pubProvidedIdSystem.json +++ b/metadata/modules/pubProvidedIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/pubgeniusBidAdapter.json b/metadata/modules/pubgeniusBidAdapter.json index a7e8d6fa90e..e785cec22ad 100644 --- a/metadata/modules/pubgeniusBidAdapter.json +++ b/metadata/modules/pubgeniusBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/publicGoodBidAdapter.json b/metadata/modules/publicGoodBidAdapter.json index a492629c705..f4a915cf8f7 100644 --- a/metadata/modules/publicGoodBidAdapter.json +++ b/metadata/modules/publicGoodBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/publinkIdSystem.json b/metadata/modules/publinkIdSystem.json index 7ec5191d077..d92f4f21083 100644 --- a/metadata/modules/publinkIdSystem.json +++ b/metadata/modules/publinkIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s-usweb.dotomi.com/assets/js/taggy-js/2.18.13/device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:17.215Z", + "timestamp": "2026-06-02T15:44:46.352Z", "disclosures": [ { "identifier": "dtm_status", @@ -579,6 +579,26 @@ ] } }, + "purposes": { + "24": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/publirBidAdapter.json b/metadata/modules/publirBidAdapter.json index 3647acc5629..ecf6ddc755d 100644 --- a/metadata/modules/publirBidAdapter.json +++ b/metadata/modules/publirBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubmaticAnalyticsAdapter.json b/metadata/modules/pubmaticAnalyticsAdapter.json index 47efb5b7317..bc95817a4aa 100644 --- a/metadata/modules/pubmaticAnalyticsAdapter.json +++ b/metadata/modules/pubmaticAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pubmaticBidAdapter.json b/metadata/modules/pubmaticBidAdapter.json index cea0023d8d9..130e9eabb5f 100644 --- a/metadata/modules/pubmaticBidAdapter.json +++ b/metadata/modules/pubmaticBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pubmatic.com/devicestorage.json": { - "timestamp": "2026-05-27T12:19:17.216Z", + "timestamp": "2026-06-02T15:44:46.353Z", "disclosures": [] } }, + "purposes": { + "76": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubmaticIdSystem.json b/metadata/modules/pubmaticIdSystem.json index b01a0031110..70338da5cb6 100644 --- a/metadata/modules/pubmaticIdSystem.json +++ b/metadata/modules/pubmaticIdSystem.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pubmatic.com/devicestorage.json": { - "timestamp": "2026-05-27T12:19:17.243Z", + "timestamp": "2026-06-02T15:44:46.935Z", "disclosures": [] } }, + "purposes": { + "76": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/pubmaticRtdProvider.json b/metadata/modules/pubmaticRtdProvider.json index a2042bad84a..31743cddf0c 100644 --- a/metadata/modules/pubmaticRtdProvider.json +++ b/metadata/modules/pubmaticRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/pubperfAnalyticsAdapter.json b/metadata/modules/pubperfAnalyticsAdapter.json index 43ed6768049..615079f15c9 100644 --- a/metadata/modules/pubperfAnalyticsAdapter.json +++ b/metadata/modules/pubperfAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pubriseBidAdapter.json b/metadata/modules/pubriseBidAdapter.json index b6c5ffdbbe8..33dd28cd459 100644 --- a/metadata/modules/pubriseBidAdapter.json +++ b/metadata/modules/pubriseBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubstackAnalyticsAdapter.json b/metadata/modules/pubstackAnalyticsAdapter.json index d34d4998cec..ab2db69e705 100644 --- a/metadata/modules/pubstackAnalyticsAdapter.json +++ b/metadata/modules/pubstackAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pubstackBidAdapter.json b/metadata/modules/pubstackBidAdapter.json index 60032712491..682861b91c2 100644 --- a/metadata/modules/pubstackBidAdapter.json +++ b/metadata/modules/pubstackBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.pbstck.com/privacy_policies/device_storage_disclosures.json": { - "timestamp": "2026-05-27T12:19:17.364Z", + "timestamp": "2026-06-02T15:44:47.685Z", "disclosures": [] } }, + "purposes": { + "1408": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubwiseAnalyticsAdapter.json b/metadata/modules/pubwiseAnalyticsAdapter.json index 7086bbf6173..1ba0e2837b6 100644 --- a/metadata/modules/pubwiseAnalyticsAdapter.json +++ b/metadata/modules/pubwiseAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pubxBidAdapter.json b/metadata/modules/pubxBidAdapter.json index fa73ef4e88c..69d4a6bb160 100644 --- a/metadata/modules/pubxBidAdapter.json +++ b/metadata/modules/pubxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pubxaiAnalyticsAdapter.json b/metadata/modules/pubxaiAnalyticsAdapter.json index dbc8f8c585a..9397db89009 100644 --- a/metadata/modules/pubxaiAnalyticsAdapter.json +++ b/metadata/modules/pubxaiAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pubxaiRtdProvider.json b/metadata/modules/pubxaiRtdProvider.json index ae85971baa5..4f7a3f67b20 100644 --- a/metadata/modules/pubxaiRtdProvider.json +++ b/metadata/modules/pubxaiRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/pulsepointAnalyticsAdapter.json b/metadata/modules/pulsepointAnalyticsAdapter.json index 95d0492a683..75185143ad8 100644 --- a/metadata/modules/pulsepointAnalyticsAdapter.json +++ b/metadata/modules/pulsepointAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/pulsepointBidAdapter.json b/metadata/modules/pulsepointBidAdapter.json index 000c1e9df7f..cb6343f8b1c 100644 --- a/metadata/modules/pulsepointBidAdapter.json +++ b/metadata/modules/pulsepointBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bh.contextweb.com/tcf/vendorInfo.json": { - "timestamp": "2026-05-27T12:19:17.365Z", + "timestamp": "2026-06-02T15:44:47.686Z", "disclosures": [] } }, + "purposes": { + "81": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pwbidBidAdapter.json b/metadata/modules/pwbidBidAdapter.json index 474e954a58c..d38f9c02782 100644 --- a/metadata/modules/pwbidBidAdapter.json +++ b/metadata/modules/pwbidBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/pxyzBidAdapter.json b/metadata/modules/pxyzBidAdapter.json index 3ebc8302485..81b15bcfa79 100644 --- a/metadata/modules/pxyzBidAdapter.json +++ b/metadata/modules/pxyzBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/qortexRtdProvider.json b/metadata/modules/qortexRtdProvider.json index 6cc4afcd3ea..c121e23c392 100644 --- a/metadata/modules/qortexRtdProvider.json +++ b/metadata/modules/qortexRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/qtBidAdapter.json b/metadata/modules/qtBidAdapter.json index c4ef3fd1146..b9d191c87fc 100644 --- a/metadata/modules/qtBidAdapter.json +++ b/metadata/modules/qtBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/qwarryBidAdapter.json b/metadata/modules/qwarryBidAdapter.json index fd1e946aef9..9b2b13d13f5 100644 --- a/metadata/modules/qwarryBidAdapter.json +++ b/metadata/modules/qwarryBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/r2b2AnalyticsAdapter.json b/metadata/modules/r2b2AnalyticsAdapter.json index ffdc1af383f..064dc4951fb 100644 --- a/metadata/modules/r2b2AnalyticsAdapter.json +++ b/metadata/modules/r2b2AnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/r2b2BidAdapter.json b/metadata/modules/r2b2BidAdapter.json index e04a28b7055..a3f85dbbd11 100644 --- a/metadata/modules/r2b2BidAdapter.json +++ b/metadata/modules/r2b2BidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://delivery.r2b2.io/cookie_disclosure": { - "timestamp": "2026-05-27T12:19:17.616Z", + "timestamp": "2026-06-02T15:44:48.112Z", "disclosures": [ { "identifier": "AdTrack-hide-*", @@ -222,6 +222,19 @@ ] } }, + "purposes": { + "1235": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rakutenBidAdapter.json b/metadata/modules/rakutenBidAdapter.json index 1443d0471c3..6cb7ff904a2 100644 --- a/metadata/modules/rakutenBidAdapter.json +++ b/metadata/modules/rakutenBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/raveltechRtdProvider.json b/metadata/modules/raveltechRtdProvider.json index e307bbf2adf..ae739456b1b 100644 --- a/metadata/modules/raveltechRtdProvider.json +++ b/metadata/modules/raveltechRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/raynRtdProvider.json b/metadata/modules/raynRtdProvider.json index da2b55ad69d..7472c8685d0 100644 --- a/metadata/modules/raynRtdProvider.json +++ b/metadata/modules/raynRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/readpeakBidAdapter.json b/metadata/modules/readpeakBidAdapter.json index 019b7830656..7f2d5995560 100644 --- a/metadata/modules/readpeakBidAdapter.json +++ b/metadata/modules/readpeakBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static.readpeak.com/tcf/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:18.087Z", + "timestamp": "2026-06-02T15:44:48.776Z", "disclosures": [ { "identifier": "rp_uidfp", @@ -24,6 +24,31 @@ ] } }, + "purposes": { + "290": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 11 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/reconciliationRtdProvider.json b/metadata/modules/reconciliationRtdProvider.json index 7d1863f855c..3e9d4978cc6 100644 --- a/metadata/modules/reconciliationRtdProvider.json +++ b/metadata/modules/reconciliationRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/rediadsBidAdapter.json b/metadata/modules/rediadsBidAdapter.json index d4b86f61b10..bab586cc5ce 100644 --- a/metadata/modules/rediadsBidAdapter.json +++ b/metadata/modules/rediadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rediadsIdSystem.json b/metadata/modules/rediadsIdSystem.json index b4918ddd890..c231b31e9f3 100644 --- a/metadata/modules/rediadsIdSystem.json +++ b/metadata/modules/rediadsIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/redtramBidAdapter.json b/metadata/modules/redtramBidAdapter.json index 199f99f042a..d5d97030381 100644 --- a/metadata/modules/redtramBidAdapter.json +++ b/metadata/modules/redtramBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/reklamupBidAdapter.json b/metadata/modules/reklamupBidAdapter.json index 1b59b509ecb..cbd089dbd27 100644 --- a/metadata/modules/reklamupBidAdapter.json +++ b/metadata/modules/reklamupBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/relaidoBidAdapter.json b/metadata/modules/relaidoBidAdapter.json index a878f021b24..0a5d9e152c6 100644 --- a/metadata/modules/relaidoBidAdapter.json +++ b/metadata/modules/relaidoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/relayBidAdapter.json b/metadata/modules/relayBidAdapter.json index 55e26007078..67c88ab7bb0 100644 --- a/metadata/modules/relayBidAdapter.json +++ b/metadata/modules/relayBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/relevadRtdProvider.json b/metadata/modules/relevadRtdProvider.json index acdbeaa8323..427884499c4 100644 --- a/metadata/modules/relevadRtdProvider.json +++ b/metadata/modules/relevadRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/relevantAnalyticsAdapter.json b/metadata/modules/relevantAnalyticsAdapter.json index 3b53e6f9320..fae5f9afe3b 100644 --- a/metadata/modules/relevantAnalyticsAdapter.json +++ b/metadata/modules/relevantAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/relevantdigitalBidAdapter.json b/metadata/modules/relevantdigitalBidAdapter.json index fcf455aacbd..07ff9d8c23e 100644 --- a/metadata/modules/relevantdigitalBidAdapter.json +++ b/metadata/modules/relevantdigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.relevant-digital.com/resources/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:18.420Z", + "timestamp": "2026-06-02T15:44:48.998Z", "disclosures": [ { "identifier": "_rlvData", @@ -22,6 +22,24 @@ ] } }, + "purposes": { + "1100": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/relevatehealthBidAdapter.json b/metadata/modules/relevatehealthBidAdapter.json index ff73f93c1af..0121266b05f 100644 --- a/metadata/modules/relevatehealthBidAdapter.json +++ b/metadata/modules/relevatehealthBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/resetdigitalBidAdapter.json b/metadata/modules/resetdigitalBidAdapter.json index 4a428cf625a..312c922a157 100644 --- a/metadata/modules/resetdigitalBidAdapter.json +++ b/metadata/modules/resetdigitalBidAdapter.json @@ -2,10 +2,39 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resetdigital.co/GDPR-TCF.json": { - "timestamp": "2026-05-27T12:19:18.587Z", + "timestamp": "2026-06-02T15:44:49.265Z", "disclosures": [] } }, + "purposes": { + "1162": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/responsiveAdsBidAdapter.json b/metadata/modules/responsiveAdsBidAdapter.json index 1d02742f472..7cd5c27201c 100644 --- a/metadata/modules/responsiveAdsBidAdapter.json +++ b/metadata/modules/responsiveAdsBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://publish.responsiveads.com/tcf/tcf-v2.json": { - "timestamp": "2026-05-27T12:19:18.630Z", + "timestamp": "2026-06-02T15:44:49.797Z", "disclosures": [] } }, + "purposes": { + "1189": { + "purposes": [ + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/retailspotBidAdapter.json b/metadata/modules/retailspotBidAdapter.json index 04f501e9b71..dfc42b92d79 100644 --- a/metadata/modules/retailspotBidAdapter.json +++ b/metadata/modules/retailspotBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/revantageBidAdapter.json b/metadata/modules/revantageBidAdapter.json index e66e5f9682f..ad2f4d6c2ec 100644 --- a/metadata/modules/revantageBidAdapter.json +++ b/metadata/modules/revantageBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://revantage.io/.well-known/tcf-device-storage.json": { - "timestamp": "2026-05-27T12:19:18.710Z", + "timestamp": "2026-06-02T15:44:50.098Z", "disclosures": [] } }, + "purposes": { + "1588": { + "purposes": [], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/revcontentBidAdapter.json b/metadata/modules/revcontentBidAdapter.json index 07db0fc40f4..c001c8060e0 100644 --- a/metadata/modules/revcontentBidAdapter.json +++ b/metadata/modules/revcontentBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sothebys.revcontent.com/static/device_storage.json": { - "timestamp": "2026-05-27T12:19:19.267Z", + "timestamp": "2026-06-02T15:44:50.972Z", "disclosures": [ { "identifier": "__ID", @@ -26,6 +26,26 @@ ] } }, + "purposes": { + "203": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/revealonBidAdapter.json b/metadata/modules/revealonBidAdapter.json index 10df5a3e8c2..83b404be30b 100644 --- a/metadata/modules/revealonBidAdapter.json +++ b/metadata/modules/revealonBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/revnewBidAdapter.json b/metadata/modules/revnewBidAdapter.json index 9046c85aaa1..cd93235bae8 100644 --- a/metadata/modules/revnewBidAdapter.json +++ b/metadata/modules/revnewBidAdapter.json @@ -2,10 +2,18 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mediafuse.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:22.571Z", + "timestamp": "2026-06-02T15:44:51.162Z", "disclosures": [] } }, + "purposes": { + "1468": { + "purposes": [], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rewardedInterestIdSystem.json b/metadata/modules/rewardedInterestIdSystem.json index 34198a66d6c..7ab3500d343 100644 --- a/metadata/modules/rewardedInterestIdSystem.json +++ b/metadata/modules/rewardedInterestIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/rhythmoneBidAdapter.json b/metadata/modules/rhythmoneBidAdapter.json index 5b4b4928e18..8147fefeb82 100644 --- a/metadata/modules/rhythmoneBidAdapter.json +++ b/metadata/modules/rhythmoneBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://video.unrulymedia.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:22.638Z", + "timestamp": "2026-06-02T15:44:51.653Z", "disclosures": [] } }, + "purposes": { + "36": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/richaudienceBidAdapter.json b/metadata/modules/richaudienceBidAdapter.json index c199208ca16..81cbfff5675 100644 --- a/metadata/modules/richaudienceBidAdapter.json +++ b/metadata/modules/richaudienceBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdnj.richaudience.com/52a26ab9400b2a9f5aabfa20acf3196g.json": { - "timestamp": "2026-05-27T12:19:22.928Z", + "timestamp": "2026-06-02T15:44:52.513Z", "disclosures": [] } }, + "purposes": { + "108": { + "purposes": [ + 1, + 2, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/riseBidAdapter.json b/metadata/modules/riseBidAdapter.json index 1b5f854ad79..403192a4ce4 100644 --- a/metadata/modules/riseBidAdapter.json +++ b/metadata/modules/riseBidAdapter.json @@ -2,14 +2,48 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://d2pm7iglz0b6eq.cloudfront.net/RiseDeviceStorage.json": { - "timestamp": "2026-05-27T12:19:23.059Z", + "timestamp": "2026-06-02T15:44:53.263Z", "disclosures": [] }, "https://spotim-prd-static-assets.s3.amazonaws.com/iab/device-storage.json": { - "timestamp": "2026-05-27T12:19:23.059Z", + "timestamp": "2026-06-02T15:44:53.263Z", "disclosures": [] } }, + "purposes": { + "280": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + }, + "1043": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2, + 10 + ], + "flexiblePurposes": [ + 2, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/risemediatechBidAdapter.json b/metadata/modules/risemediatechBidAdapter.json index 8aa3fd6a56d..5bcd0f60a51 100644 --- a/metadata/modules/risemediatechBidAdapter.json +++ b/metadata/modules/risemediatechBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rivrAnalyticsAdapter.json b/metadata/modules/rivrAnalyticsAdapter.json index e9727a46519..6b6247829aa 100644 --- a/metadata/modules/rivrAnalyticsAdapter.json +++ b/metadata/modules/rivrAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/rixengineBidAdapter.json b/metadata/modules/rixengineBidAdapter.json index 0ee40a30bbb..7a9563a6b01 100644 --- a/metadata/modules/rixengineBidAdapter.json +++ b/metadata/modules/rixengineBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.algorix.co/gdpr-disclosure.json": { - "timestamp": "2026-05-27T12:19:23.060Z", + "timestamp": "2026-06-02T15:44:53.264Z", "disclosures": [] } }, + "purposes": { + "1176": { + "purposes": [ + 1, + 7 + ], + "legIntPurposes": [ + 2, + 10 + ], + "flexiblePurposes": [ + 2, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/robustAppsBidAdapter.json b/metadata/modules/robustAppsBidAdapter.json index 4cccfc56713..c3ba1bb1beb 100644 --- a/metadata/modules/robustAppsBidAdapter.json +++ b/metadata/modules/robustAppsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/robustaBidAdapter.json b/metadata/modules/robustaBidAdapter.json index 0e01b2d0cc1..c51bf716a08 100644 --- a/metadata/modules/robustaBidAdapter.json +++ b/metadata/modules/robustaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rocketlabBidAdapter.json b/metadata/modules/rocketlabBidAdapter.json index dd981b4e3a2..f2ea7cb0598 100644 --- a/metadata/modules/rocketlabBidAdapter.json +++ b/metadata/modules/rocketlabBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/roxotAnalyticsAdapter.json b/metadata/modules/roxotAnalyticsAdapter.json index 51247479078..1ab8eff8b6d 100644 --- a/metadata/modules/roxotAnalyticsAdapter.json +++ b/metadata/modules/roxotAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/rtbhouseBidAdapter.json b/metadata/modules/rtbhouseBidAdapter.json index 726a04394cf..c3c1510a771 100644 --- a/metadata/modules/rtbhouseBidAdapter.json +++ b/metadata/modules/rtbhouseBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.rtbhouse.com/DeviceStorage.json": { - "timestamp": "2026-05-27T12:19:23.150Z", + "timestamp": "2026-06-02T15:44:53.537Z", "disclosures": [ { "identifier": "_rtbh.*", @@ -126,6 +126,22 @@ ] } }, + "purposes": { + "16": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rtbsapeBidAdapter.json b/metadata/modules/rtbsapeBidAdapter.json index 0d3dbf82bd1..2b4d791bae4 100644 --- a/metadata/modules/rtbsapeBidAdapter.json +++ b/metadata/modules/rtbsapeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rubiconBidAdapter.json b/metadata/modules/rubiconBidAdapter.json index 32911bad017..5269a2a11a1 100644 --- a/metadata/modules/rubiconBidAdapter.json +++ b/metadata/modules/rubiconBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.rubiconproject.com/dvplus/devicestoragedisclosure.json": { - "timestamp": "2026-05-27T12:19:23.495Z", + "timestamp": "2026-06-02T15:44:54.156Z", "disclosures": [] } }, + "purposes": { + "52": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/rumbleBidAdapter.json b/metadata/modules/rumbleBidAdapter.json index 05b1ed34730..47016a18ec9 100644 --- a/metadata/modules/rumbleBidAdapter.json +++ b/metadata/modules/rumbleBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/scaleableAnalyticsAdapter.json b/metadata/modules/scaleableAnalyticsAdapter.json index 893190ad6af..7e65e864ce1 100644 --- a/metadata/modules/scaleableAnalyticsAdapter.json +++ b/metadata/modules/scaleableAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/scaliburBidAdapter.json b/metadata/modules/scaliburBidAdapter.json index 3d73d8f6b97..2833824fd6e 100644 --- a/metadata/modules/scaliburBidAdapter.json +++ b/metadata/modules/scaliburBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://legal.overwolf.com/docs/overwolf/website/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:23.496Z", + "timestamp": "2026-06-02T15:44:54.156Z", "disclosures": [ { "identifier": "scluid", @@ -23,6 +23,31 @@ ] } }, + "purposes": { + "1471": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/scatteredBidAdapter.json b/metadata/modules/scatteredBidAdapter.json index ef05a8579df..bb5c5192feb 100644 --- a/metadata/modules/scatteredBidAdapter.json +++ b/metadata/modules/scatteredBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/scope3RtdProvider.json b/metadata/modules/scope3RtdProvider.json index bb50ae1b92b..6ccab58ccc8 100644 --- a/metadata/modules/scope3RtdProvider.json +++ b/metadata/modules/scope3RtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/screencoreBidAdapter.json b/metadata/modules/screencoreBidAdapter.json index 21075e60e2f..1a86da0c68f 100644 --- a/metadata/modules/screencoreBidAdapter.json +++ b/metadata/modules/screencoreBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://screencore.io/tcf.json": { - "timestamp": "2026-05-27T12:19:23.733Z", + "timestamp": "2026-06-02T15:44:54.442Z", "disclosures": [] } }, + "purposes": { + "1473": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/seedingAllianceBidAdapter.json b/metadata/modules/seedingAllianceBidAdapter.json index 5e2160c5c21..54a36d50eb2 100644 --- a/metadata/modules/seedingAllianceBidAdapter.json +++ b/metadata/modules/seedingAllianceBidAdapter.json @@ -2,10 +2,38 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s.nativendo.de/cdn/asset/tcf/purpose-specific-storage-and-access-information.json": { - "timestamp": "2026-05-27T12:19:23.947Z", + "timestamp": "2026-06-02T15:44:54.977Z", "disclosures": [] } }, + "purposes": { + "371": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/seedtagBidAdapter.json b/metadata/modules/seedtagBidAdapter.json index 8e1bd7fbde7..dd9b782b2b6 100644 --- a/metadata/modules/seedtagBidAdapter.json +++ b/metadata/modules/seedtagBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.seedtag.com/vendor.json": { - "timestamp": "2026-05-27T12:19:24.414Z", + "timestamp": "2026-06-02T15:44:55.531Z", "disclosures": [] } }, + "purposes": { + "157": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/selectmediaBidAdapter.json b/metadata/modules/selectmediaBidAdapter.json index 203c54f6dfc..286ca5b7ee6 100644 --- a/metadata/modules/selectmediaBidAdapter.json +++ b/metadata/modules/selectmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.selectmedia.asia/gdpr/devicestorage.json": { - "timestamp": "2026-05-27T12:19:24.414Z", + "timestamp": "2026-06-02T15:44:55.531Z", "disclosures": [ { "identifier": "waterFallCacheAnsKey_*", @@ -77,6 +77,17 @@ ] } }, + "purposes": { + "775": { + "purposes": [ + 1, + 2 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/semantiqRtdProvider.json b/metadata/modules/semantiqRtdProvider.json index ed4a11ef589..0e93a95499b 100644 --- a/metadata/modules/semantiqRtdProvider.json +++ b/metadata/modules/semantiqRtdProvider.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audienzz.com/device_storage_disclosure_vendor_783.json": { - "timestamp": "2026-05-27T12:19:25.581Z", + "timestamp": "2026-06-02T15:44:56.053Z", "disclosures": [] } }, + "purposes": { + "783": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/setupadBidAdapter.json b/metadata/modules/setupadBidAdapter.json index e3a67220cfa..d70a0484507 100644 --- a/metadata/modules/setupadBidAdapter.json +++ b/metadata/modules/setupadBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cookies.stpd.cloud/disclosures.json": { - "timestamp": "2026-05-27T12:19:25.811Z", + "timestamp": "2026-06-02T15:44:56.762Z", "disclosures": null } }, + "purposes": { + "1241": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sevioBidAdapter.json b/metadata/modules/sevioBidAdapter.json index 7cc82218307..43287a80535 100644 --- a/metadata/modules/sevioBidAdapter.json +++ b/metadata/modules/sevioBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sevio.com/tcf.json": { - "timestamp": "2026-05-27T12:19:25.885Z", + "timestamp": "2026-06-02T15:44:56.988Z", "disclosures": [] } }, + "purposes": { + "1393": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 11 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sharedIdSystem.json b/metadata/modules/sharedIdSystem.json index 6d935cede5d..b8cfb9ad149 100644 --- a/metadata/modules/sharedIdSystem.json +++ b/metadata/modules/sharedIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/sharedId-optout.json": { - "timestamp": "2026-05-27T12:19:26.042Z", + "timestamp": "2026-06-02T15:44:57.386Z", "disclosures": [ { "identifier": "_pubcid_optout", @@ -24,6 +24,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/sharethroughAnalyticsAdapter.json b/metadata/modules/sharethroughAnalyticsAdapter.json index 606d12abddb..f558625dd18 100644 --- a/metadata/modules/sharethroughAnalyticsAdapter.json +++ b/metadata/modules/sharethroughAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/sharethroughBidAdapter.json b/metadata/modules/sharethroughBidAdapter.json index e919c0ab184..317a35ab41f 100644 --- a/metadata/modules/sharethroughBidAdapter.json +++ b/metadata/modules/sharethroughBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://assets.sharethrough.com/gvl.json": { - "timestamp": "2026-05-27T12:19:26.043Z", + "timestamp": "2026-06-02T15:44:57.387Z", "disclosures": [] } }, + "purposes": { + "80": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/shinezBidAdapter.json b/metadata/modules/shinezBidAdapter.json index 90308ec5e97..daee44daf60 100644 --- a/metadata/modules/shinezBidAdapter.json +++ b/metadata/modules/shinezBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/shinezRtbBidAdapter.json b/metadata/modules/shinezRtbBidAdapter.json index 758b93fd8fe..0386e51e343 100644 --- a/metadata/modules/shinezRtbBidAdapter.json +++ b/metadata/modules/shinezRtbBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/showheroes-bsBidAdapter.json b/metadata/modules/showheroes-bsBidAdapter.json index de9e3f33375..469409b128f 100644 --- a/metadata/modules/showheroes-bsBidAdapter.json +++ b/metadata/modules/showheroes-bsBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static-origin.showheroes.com/gvl_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:26.160Z", + "timestamp": "2026-06-02T15:44:57.759Z", "disclosures": [] } }, + "purposes": { + "111": { + "purposes": [ + 1, + 3, + 4, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7, + 8 + ], + "flexiblePurposes": [ + 2, + 7, + 8 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/showheroesBidAdapter.json b/metadata/modules/showheroesBidAdapter.json index 382c0066e53..e3da952de71 100644 --- a/metadata/modules/showheroesBidAdapter.json +++ b/metadata/modules/showheroesBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://static-origin.showheroes.com/gvl_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:26.670Z", + "timestamp": "2026-06-02T15:44:58.610Z", "disclosures": [] } }, + "purposes": { + "111": { + "purposes": [ + 1, + 3, + 4, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7, + 8 + ], + "flexiblePurposes": [ + 2, + 7, + 8 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/silvermobBidAdapter.json b/metadata/modules/silvermobBidAdapter.json index f3e213cc830..f55a94b81e8 100644 --- a/metadata/modules/silvermobBidAdapter.json +++ b/metadata/modules/silvermobBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://silvermob.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:26.671Z", + "timestamp": "2026-06-02T15:44:58.610Z", "disclosures": [] } }, + "purposes": { + "1058": { + "purposes": [ + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/silverpushBidAdapter.json b/metadata/modules/silverpushBidAdapter.json index 9c122816564..560792f0018 100644 --- a/metadata/modules/silverpushBidAdapter.json +++ b/metadata/modules/silverpushBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sirdataRtdProvider.json b/metadata/modules/sirdataRtdProvider.json index 936dc312585..0c15c23e5ed 100644 --- a/metadata/modules/sirdataRtdProvider.json +++ b/metadata/modules/sirdataRtdProvider.json @@ -2,10 +2,36 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.sirdata.eu/sirdata_device_storage_disclosure.json": { - "timestamp": "2026-05-27T12:19:26.715Z", + "timestamp": "2026-06-02T15:44:59.094Z", "disclosures": [] } }, + "purposes": { + "53": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/slimcutBidAdapter.json b/metadata/modules/slimcutBidAdapter.json index 914f7829cea..eaa1557984e 100644 --- a/metadata/modules/slimcutBidAdapter.json +++ b/metadata/modules/slimcutBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smaatoBidAdapter.json b/metadata/modules/smaatoBidAdapter.json index 24699c6995e..4698ef546a2 100644 --- a/metadata/modules/smaatoBidAdapter.json +++ b/metadata/modules/smaatoBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://resources.smaato.com/hubfs/Smaato/IAB/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:27.362Z", + "timestamp": "2026-06-02T15:44:59.727Z", "disclosures": [] } }, + "purposes": { + "82": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smartadserverBidAdapter.json b/metadata/modules/smartadserverBidAdapter.json index 39b53daec84..a5bc29fca67 100644 --- a/metadata/modules/smartadserverBidAdapter.json +++ b/metadata/modules/smartadserverBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://apps.smartadserver.com/device-storage-disclosures/equativDeviceStorageDisclosures.json": { - "timestamp": "2026-05-27T12:19:27.589Z", + "timestamp": "2026-06-02T15:45:00.117Z", "disclosures": [] } }, + "purposes": { + "45": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smarthubBidAdapter.json b/metadata/modules/smarthubBidAdapter.json index 8dae767ac87..d55ddd1ce4a 100644 --- a/metadata/modules/smarthubBidAdapter.json +++ b/metadata/modules/smarthubBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smarticoBidAdapter.json b/metadata/modules/smarticoBidAdapter.json index 6890661e7dc..c2128962e57 100644 --- a/metadata/modules/smarticoBidAdapter.json +++ b/metadata/modules/smarticoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smartxBidAdapter.json b/metadata/modules/smartxBidAdapter.json index 7d5b15813a6..6a4e6f9bd71 100644 --- a/metadata/modules/smartxBidAdapter.json +++ b/metadata/modules/smartxBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.smartclip.net/iab/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:27.590Z", + "timestamp": "2026-06-02T15:45:00.117Z", "disclosures": [] } }, + "purposes": { + "115": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smartyadsAnalyticsAdapter.json b/metadata/modules/smartyadsAnalyticsAdapter.json index 610464707e6..e24ab19a5b5 100644 --- a/metadata/modules/smartyadsAnalyticsAdapter.json +++ b/metadata/modules/smartyadsAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/smartyadsBidAdapter.json b/metadata/modules/smartyadsBidAdapter.json index 13021760e73..f04ffeb7a8b 100644 --- a/metadata/modules/smartyadsBidAdapter.json +++ b/metadata/modules/smartyadsBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://smartyads.com/tcf.json": { - "timestamp": "2026-05-27T12:19:27.756Z", + "timestamp": "2026-06-02T15:45:00.417Z", "disclosures": [] } }, + "purposes": { + "534": { + "purposes": [ + 1, + 2, + 3, + 4, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smartytechBidAdapter.json b/metadata/modules/smartytechBidAdapter.json index 6bd5749a72b..e4c4b902688 100644 --- a/metadata/modules/smartytechBidAdapter.json +++ b/metadata/modules/smartytechBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smilewantedBidAdapter.json b/metadata/modules/smilewantedBidAdapter.json index 579f4e540d7..1c0cf21ba63 100644 --- a/metadata/modules/smilewantedBidAdapter.json +++ b/metadata/modules/smilewantedBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://smilewanted.com/vendor-device-storage-disclosures.json": { - "timestamp": "2026-05-27T12:19:27.877Z", + "timestamp": "2026-06-02T15:45:00.950Z", "disclosures": [] } }, + "purposes": { + "639": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/smootBidAdapter.json b/metadata/modules/smootBidAdapter.json index d065ad2c042..97bcd0b735e 100644 --- a/metadata/modules/smootBidAdapter.json +++ b/metadata/modules/smootBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/snigelBidAdapter.json b/metadata/modules/snigelBidAdapter.json index 958e955da2e..6846944d546 100644 --- a/metadata/modules/snigelBidAdapter.json +++ b/metadata/modules/snigelBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.snigelweb.com/gvl/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:28.327Z", + "timestamp": "2026-06-02T15:45:01.836Z", "disclosures": [] } }, + "purposes": { + "1076": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sonaradsBidAdapter.json b/metadata/modules/sonaradsBidAdapter.json index 2c71818e416..fe56f071850 100644 --- a/metadata/modules/sonaradsBidAdapter.json +++ b/metadata/modules/sonaradsBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bridgeupp.com/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:28.433Z", + "timestamp": "2026-06-02T15:45:02.300Z", "disclosures": [] } }, + "purposes": { + "1300": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sonobiBidAdapter.json b/metadata/modules/sonobiBidAdapter.json index 82dea214130..de55951d7bd 100644 --- a/metadata/modules/sonobiBidAdapter.json +++ b/metadata/modules/sonobiBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://sonobi.com/tcf2-device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:28.726Z", + "timestamp": "2026-06-02T15:45:02.943Z", "disclosures": [] } }, + "purposes": { + "104": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 8, + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sovrnBidAdapter.json b/metadata/modules/sovrnBidAdapter.json index c82ab825dd9..cd31aa7e7d8 100644 --- a/metadata/modules/sovrnBidAdapter.json +++ b/metadata/modules/sovrnBidAdapter.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.sovrn.com/tcf-cookie-disclosure/disclosure.json": { - "timestamp": "2026-05-27T12:19:28.960Z", + "timestamp": "2026-06-02T15:45:03.601Z", "disclosures": [] } }, + "purposes": { + "13": { + "purposes": [ + 1, + 2, + 3, + 5, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sparteoBidAdapter.json b/metadata/modules/sparteoBidAdapter.json index fe4d04e2d12..d0080b571b5 100644 --- a/metadata/modules/sparteoBidAdapter.json +++ b/metadata/modules/sparteoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.bricks-co.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:29.146Z", + "timestamp": "2026-06-02T15:45:03.846Z", "disclosures": [ { "identifier": "fastCMP-addtlConsent", @@ -28,6 +28,34 @@ ] } }, + "purposes": { + "1028": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ssmasBidAdapter.json b/metadata/modules/ssmasBidAdapter.json index 1882cdbae2a..2860bfcfd57 100644 --- a/metadata/modules/ssmasBidAdapter.json +++ b/metadata/modules/ssmasBidAdapter.json @@ -2,10 +2,23 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://semseoymas.com/iab.json": { - "timestamp": "2026-05-27T12:19:29.553Z", + "timestamp": "2026-06-02T15:45:04.685Z", "disclosures": null } }, + "purposes": { + "1183": { + "purposes": [ + 1, + 2, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sspBCBidAdapter.json b/metadata/modules/sspBCBidAdapter.json index 69d42236ad2..e536192fbe1 100644 --- a/metadata/modules/sspBCBidAdapter.json +++ b/metadata/modules/sspBCBidAdapter.json @@ -2,10 +2,36 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ssp.wp.pl/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:30.298Z", + "timestamp": "2026-06-02T15:45:05.912Z", "disclosures": [] } }, + "purposes": { + "676": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [ + 7, + 8, + 9 + ], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ssp_genieeBidAdapter.json b/metadata/modules/ssp_genieeBidAdapter.json index 084e90274da..1ed4e90685f 100644 --- a/metadata/modules/ssp_genieeBidAdapter.json +++ b/metadata/modules/ssp_genieeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/stackadaptBidAdapter.json b/metadata/modules/stackadaptBidAdapter.json index 566fe3760ff..b01ee28017d 100644 --- a/metadata/modules/stackadaptBidAdapter.json +++ b/metadata/modules/stackadaptBidAdapter.json @@ -2,46 +2,40 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://s3.amazonaws.com/stackadapt_public/disclosures.json": { - "timestamp": "2026-05-27T12:19:30.298Z", + "timestamp": "2026-06-02T15:45:05.913Z", "disclosures": [ { - "identifier": "sa-camp-*", - "type": "cookie", - "maxAgeSeconds": 7776000, - "cookieRefresh": false, - "purposes": [ - 1 - ] - }, - { - "identifier": "sa_aid_pv", - "type": "cookie", - "maxAgeSeconds": 3600, - "cookieRefresh": false, - "purposes": [ - 1 - ] - }, - { - "identifier": "sa_*_sid", + "identifier": "sa-user-id", "type": "cookie", - "maxAgeSeconds": 3600, + "maxAgeSeconds": 31536000, "cookieRefresh": false, "purposes": [ - 1 + 1, + 3, + 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { - "identifier": "sa_*_adurl", - "type": "cookie", - "maxAgeSeconds": 3600, + "identifier": "sa-user-id", + "type": "web", + "maxAgeSeconds": null, "cookieRefresh": false, "purposes": [ - 1 + 1, + 3, + 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { - "identifier": "sa-user-id", + "identifier": "sa-user-id-v2", "type": "cookie", "maxAgeSeconds": 31536000, "cookieRefresh": false, @@ -49,21 +43,29 @@ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { "identifier": "sa-user-id-v2", - "type": "cookie", - "maxAgeSeconds": 31536000, + "type": "web", + "maxAgeSeconds": null, "cookieRefresh": false, "purposes": [ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { - "identifier": "sa-user-id-v4", + "identifier": "sa-user-id-v3", "type": "cookie", "maxAgeSeconds": 31536000, "cookieRefresh": false, @@ -71,10 +73,14 @@ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { - "identifier": "sa-user-id", + "identifier": "sa-user-id-v3", "type": "web", "maxAgeSeconds": null, "cookieRefresh": false, @@ -82,17 +88,25 @@ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { - "identifier": "sa-user-id-v2", - "type": "web", - "maxAgeSeconds": null, + "identifier": "sa-user-id-v4", + "type": "cookie", + "maxAgeSeconds": 31536000, "cookieRefresh": false, "purposes": [ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, { @@ -104,8 +118,22 @@ 1, 3, 4 + ], + "specialPurposes": [ + 1, + 2 ] }, + { + "identifier": "sa-camp-*", + "type": "cookie", + "maxAgeSeconds": 7776000, + "cookieRefresh": false, + "purposes": [ + 1 + ], + "specialPurposes": [] + }, { "identifier": "sa-camp-*", "type": "web", @@ -113,33 +141,71 @@ "cookieRefresh": false, "purposes": [ 1 - ] + ], + "specialPurposes": [] }, { - "identifier": "sa-user-id-v3", + "identifier": "sa_aid_pv", "type": "cookie", - "maxAgeSeconds": 31536000, + "maxAgeSeconds": 3600, "cookieRefresh": false, "purposes": [ - 1, - 3, - 4 - ] + 1 + ], + "specialPurposes": [] }, { - "identifier": "sa-user-id-v3", - "type": "web", - "maxAgeSeconds": null, + "identifier": "sa_*_sid", + "type": "cookie", + "maxAgeSeconds": 3600, "cookieRefresh": false, "purposes": [ - 1, - 3, - 4 - ] + 1 + ], + "specialPurposes": [] + }, + { + "identifier": "sa_*_adurl", + "type": "cookie", + "maxAgeSeconds": 3600, + "cookieRefresh": false, + "purposes": [ + 1 + ], + "specialPurposes": [] } ] } }, + "purposes": { + "238": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 11 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/startioBidAdapter.json b/metadata/modules/startioBidAdapter.json index ac3c6b3d5c3..7742bc23247 100644 --- a/metadata/modules/startioBidAdapter.json +++ b/metadata/modules/startioBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://info.startappservice.com/tcf/start.io_domains.json": { - "timestamp": "2026-05-27T12:19:30.369Z", + "timestamp": "2026-06-02T15:45:06.326Z", "disclosures": [] } }, + "purposes": { + "1216": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/startioIdSystem.json b/metadata/modules/startioIdSystem.json index 6390d0b25fb..f9098d37086 100644 --- a/metadata/modules/startioIdSystem.json +++ b/metadata/modules/startioIdSystem.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://info.startappservice.com/tcf/start.io_domains.json": { - "timestamp": "2026-05-27T12:19:30.467Z", + "timestamp": "2026-06-02T15:45:06.534Z", "disclosures": [] } }, + "purposes": { + "1216": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/stnBidAdapter.json b/metadata/modules/stnBidAdapter.json index 9e02eb69a72..98a069984ca 100644 --- a/metadata/modules/stnBidAdapter.json +++ b/metadata/modules/stnBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/stroeerCoreBidAdapter.json b/metadata/modules/stroeerCoreBidAdapter.json index f3daa62d508..fd783f92198 100644 --- a/metadata/modules/stroeerCoreBidAdapter.json +++ b/metadata/modules/stroeerCoreBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.stroeer.de/StroeerSSP_deviceStorage.json": { - "timestamp": "2026-05-27T12:19:30.467Z", + "timestamp": "2026-06-02T15:45:06.534Z", "disclosures": [] } }, + "purposes": { + "136": { + "purposes": [ + 1, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/stvBidAdapter.json b/metadata/modules/stvBidAdapter.json index 877c2f3fc2a..75185a62449 100644 --- a/metadata/modules/stvBidAdapter.json +++ b/metadata/modules/stvBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.adtech.app/gen/deviceStorageDisclosure/stv.json": { - "timestamp": "2026-05-27T12:19:30.888Z", + "timestamp": "2026-06-02T15:45:07.296Z", "disclosures": [] } }, + "purposes": { + "134": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/sublimeBidAdapter.json b/metadata/modules/sublimeBidAdapter.json index 51cd4ff1c65..ed6b958a13d 100644 --- a/metadata/modules/sublimeBidAdapter.json +++ b/metadata/modules/sublimeBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://gdpr.ayads.co/cookiepolicy.json": { - "timestamp": "2026-05-27T12:19:31.560Z", + "timestamp": "2026-06-02T15:45:08.583Z", "disclosures": [ { "identifier": "dnt", @@ -82,6 +82,22 @@ ] } }, + "purposes": { + "114": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/suimBidAdapter.json b/metadata/modules/suimBidAdapter.json index f0f6a2e6aa0..6971c7921f5 100644 --- a/metadata/modules/suimBidAdapter.json +++ b/metadata/modules/suimBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/symitriAnalyticsAdapter.json b/metadata/modules/symitriAnalyticsAdapter.json index ff215d73bf8..f462128a4d5 100644 --- a/metadata/modules/symitriAnalyticsAdapter.json +++ b/metadata/modules/symitriAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/symitriDapRtdProvider.json b/metadata/modules/symitriDapRtdProvider.json index 2e78c2b534e..5416d4ed331 100644 --- a/metadata/modules/symitriDapRtdProvider.json +++ b/metadata/modules/symitriDapRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/taboolaBidAdapter.json b/metadata/modules/taboolaBidAdapter.json index 1476578b19f..94cb91de44b 100644 --- a/metadata/modules/taboolaBidAdapter.json +++ b/metadata/modules/taboolaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://accessrequest.taboola.com/iab-tcf-v2-disclosure.json": { - "timestamp": "2026-05-27T12:19:31.728Z", + "timestamp": "2026-06-02T15:45:09.331Z", "disclosures": [ { "identifier": "trc_cookie_storage", @@ -486,6 +486,33 @@ ] } }, + "purposes": { + "42": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 11 + ], + "legIntPurposes": [ + 9 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/taboolaIdSystem.json b/metadata/modules/taboolaIdSystem.json index 1f2b2d511a1..5f9d6be3b68 100644 --- a/metadata/modules/taboolaIdSystem.json +++ b/metadata/modules/taboolaIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://accessrequest.taboola.com/iab-tcf-v2-disclosure.json": { - "timestamp": "2026-05-27T12:19:32.420Z", + "timestamp": "2026-06-02T15:45:10.488Z", "disclosures": [ { "identifier": "trc_cookie_storage", @@ -486,6 +486,33 @@ ] } }, + "purposes": { + "42": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 10, + 11 + ], + "legIntPurposes": [ + 9 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/tadvertisingBidAdapter.json b/metadata/modules/tadvertisingBidAdapter.json index 908deb1ec67..6d6cfdc34e6 100644 --- a/metadata/modules/tadvertisingBidAdapter.json +++ b/metadata/modules/tadvertisingBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tcf.emetriq.de/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:32.421Z", + "timestamp": "2026-06-02T15:45:10.488Z", "disclosures": [] } }, + "purposes": { + "213": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/tagorasBidAdapter.json b/metadata/modules/tagorasBidAdapter.json index 21be6297b1f..32f55abb250 100644 --- a/metadata/modules/tagorasBidAdapter.json +++ b/metadata/modules/tagorasBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/talkadsBidAdapter.json b/metadata/modules/talkadsBidAdapter.json index 05988f3c23e..68730dffc02 100644 --- a/metadata/modules/talkadsBidAdapter.json +++ b/metadata/modules/talkadsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/tapadIdSystem.json b/metadata/modules/tapadIdSystem.json index 5e0e4464ed6..db7c1671509 100644 --- a/metadata/modules/tapadIdSystem.json +++ b/metadata/modules/tapadIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/tapnativeBidAdapter.json b/metadata/modules/tapnativeBidAdapter.json index 3aef210fc05..f9312c473c1 100644 --- a/metadata/modules/tapnativeBidAdapter.json +++ b/metadata/modules/tapnativeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/tappxBidAdapter.json b/metadata/modules/tappxBidAdapter.json index 725e73a5a08..0f61d29952c 100644 --- a/metadata/modules/tappxBidAdapter.json +++ b/metadata/modules/tappxBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://tappx.com/devicestorage.json": { - "timestamp": "2026-05-27T12:19:32.571Z", + "timestamp": "2026-06-02T15:45:10.943Z", "disclosures": [] } }, + "purposes": { + "628": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/targetVideoBidAdapter.json b/metadata/modules/targetVideoBidAdapter.json index 9258a4c2702..50ca487a8fe 100644 --- a/metadata/modules/targetVideoBidAdapter.json +++ b/metadata/modules/targetVideoBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://target-video.com/vendors-device-storage-and-operational-disclosures.json": { - "timestamp": "2026-05-27T12:19:32.611Z", + "timestamp": "2026-06-02T15:45:11.505Z", "disclosures": [ { "identifier": "brid_location", @@ -112,6 +112,21 @@ ] } }, + "purposes": { + "786": { + "purposes": [ + 1, + 2, + 4, + 7, + 8, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/teadsBidAdapter.json b/metadata/modules/teadsBidAdapter.json index 2b1fa85c782..4f5658716c3 100644 --- a/metadata/modules/teadsBidAdapter.json +++ b/metadata/modules/teadsBidAdapter.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab-cookie-disclosure.teads.tv/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:32.612Z", + "timestamp": "2026-06-02T15:45:11.506Z", "disclosures": [] } }, + "purposes": { + "132": { + "purposes": [ + 1, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/teadsIdSystem.json b/metadata/modules/teadsIdSystem.json index a661a0efff8..88d9aedacff 100644 --- a/metadata/modules/teadsIdSystem.json +++ b/metadata/modules/teadsIdSystem.json @@ -2,10 +2,29 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://iab-cookie-disclosure.teads.tv/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:32.645Z", + "timestamp": "2026-06-02T15:45:11.769Z", "disclosures": [] } }, + "purposes": { + "132": { + "purposes": [ + 1, + 3, + 4, + 7, + 9, + 10 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/tealBidAdapter.json b/metadata/modules/tealBidAdapter.json index 78e4e8e6eb6..13a1bac17f7 100644 --- a/metadata/modules/tealBidAdapter.json +++ b/metadata/modules/tealBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://c.bids.ws/iab/disclosures.json": { - "timestamp": "2026-05-27T12:19:32.645Z", + "timestamp": "2026-06-02T15:45:11.770Z", "disclosures": [] } }, + "purposes": { + "1378": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/temedyaBidAdapter.json b/metadata/modules/temedyaBidAdapter.json index 054d22d161a..c5bec77d1ad 100644 --- a/metadata/modules/temedyaBidAdapter.json +++ b/metadata/modules/temedyaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/teqBlazeDemoBidAdapter.json b/metadata/modules/teqBlazeDemoBidAdapter.json index 34065f3468f..8632eaf10cf 100644 --- a/metadata/modules/teqBlazeDemoBidAdapter.json +++ b/metadata/modules/teqBlazeDemoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/teqBlazeSalesAgentBidAdapter.json b/metadata/modules/teqBlazeSalesAgentBidAdapter.json index 2442df240d1..6eace824fbd 100644 --- a/metadata/modules/teqBlazeSalesAgentBidAdapter.json +++ b/metadata/modules/teqBlazeSalesAgentBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/terceptAnalyticsAdapter.json b/metadata/modules/terceptAnalyticsAdapter.json index 2255c515104..95adfa9c831 100644 --- a/metadata/modules/terceptAnalyticsAdapter.json +++ b/metadata/modules/terceptAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/theAdxBidAdapter.json b/metadata/modules/theAdxBidAdapter.json index 33d503c4f9d..e6c7efa0778 100644 --- a/metadata/modules/theAdxBidAdapter.json +++ b/metadata/modules/theAdxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/themoneytizerBidAdapter.json b/metadata/modules/themoneytizerBidAdapter.json index fac15fb8f1e..720edc4bbeb 100644 --- a/metadata/modules/themoneytizerBidAdapter.json +++ b/metadata/modules/themoneytizerBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/timeoutRtdProvider.json b/metadata/modules/timeoutRtdProvider.json index 4d8a1a63e65..86f10be976f 100644 --- a/metadata/modules/timeoutRtdProvider.json +++ b/metadata/modules/timeoutRtdProvider.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/tncIdSystem.json b/metadata/modules/tncIdSystem.json index 3437050ef69..8268d9dc87c 100644 --- a/metadata/modules/tncIdSystem.json +++ b/metadata/modules/tncIdSystem.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://js.tncid.app/iab-tcf-device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:32.679Z", + "timestamp": "2026-06-02T15:45:11.995Z", "disclosures": [] } }, + "purposes": { + "750": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/tne_catalystBidAdapter.json b/metadata/modules/tne_catalystBidAdapter.json index 15de06c4a66..d0c846f4fee 100644 --- a/metadata/modules/tne_catalystBidAdapter.json +++ b/metadata/modules/tne_catalystBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ads.thenexusengine.com/tcf-disclosure.json": { - "timestamp": "2026-05-27T12:19:32.856Z", + "timestamp": "2026-06-02T15:45:12.275Z", "disclosures": [] } }, + "purposes": { + "1494": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 11 + ], + "legIntPurposes": [ + 10 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/topicsFpdModule.json b/metadata/modules/topicsFpdModule.json index 01fa7e16765..195c6a01c74 100644 --- a/metadata/modules/topicsFpdModule.json +++ b/metadata/modules/topicsFpdModule.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/topicsFpdModule.json": { - "timestamp": "2026-05-27T12:17:29.211Z", + "timestamp": "2026-06-02T15:42:53.593Z", "disclosures": [ { "identifier": "prebid:topics", @@ -18,6 +18,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "prebid", diff --git a/metadata/modules/toponBidAdapter.json b/metadata/modules/toponBidAdapter.json index 7fefb5a76dc..d05d71ab577 100644 --- a/metadata/modules/toponBidAdapter.json +++ b/metadata/modules/toponBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://mores.toponad.net/tcf/toponads_tcf_disclosure.json": { - "timestamp": "2026-05-27T12:19:32.953Z", + "timestamp": "2026-06-02T15:45:12.575Z", "disclosures": [] } }, + "purposes": { + "1305": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 11 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/tpmnBidAdapter.json b/metadata/modules/tpmnBidAdapter.json index a0dbc82b406..4de6a9de649 100644 --- a/metadata/modules/tpmnBidAdapter.json +++ b/metadata/modules/tpmnBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/trafficgateBidAdapter.json b/metadata/modules/trafficgateBidAdapter.json index e63478cede3..05f0ccc67d3 100644 --- a/metadata/modules/trafficgateBidAdapter.json +++ b/metadata/modules/trafficgateBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/trionBidAdapter.json b/metadata/modules/trionBidAdapter.json index 9d5d4f7b393..09b155cc62f 100644 --- a/metadata/modules/trionBidAdapter.json +++ b/metadata/modules/trionBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/tripleliftBidAdapter.json b/metadata/modules/tripleliftBidAdapter.json index 9c459d0bc5d..ac500027b90 100644 --- a/metadata/modules/tripleliftBidAdapter.json +++ b/metadata/modules/tripleliftBidAdapter.json @@ -2,10 +2,34 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://triplelift.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:33.151Z", + "timestamp": "2026-06-02T15:45:13.077Z", "disclosures": [] } }, + "purposes": { + "28": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/truereachBidAdapter.json b/metadata/modules/truereachBidAdapter.json index ce7067bea6a..7e89c9c1d09 100644 --- a/metadata/modules/truereachBidAdapter.json +++ b/metadata/modules/truereachBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/trustxBidAdapter.json b/metadata/modules/trustxBidAdapter.json index 5f4821f2f56..f595fdaa59f 100644 --- a/metadata/modules/trustxBidAdapter.json +++ b/metadata/modules/trustxBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ttdBidAdapter.json b/metadata/modules/ttdBidAdapter.json index 8e96a6abed5..859aed199b9 100644 --- a/metadata/modules/ttdBidAdapter.json +++ b/metadata/modules/ttdBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-27T12:19:33.328Z", + "timestamp": "2026-06-02T15:45:13.806Z", "disclosures": [] } }, + "purposes": { + "21": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/twistDigitalBidAdapter.json b/metadata/modules/twistDigitalBidAdapter.json index 51701d1d073..2509186f2ff 100644 --- a/metadata/modules/twistDigitalBidAdapter.json +++ b/metadata/modules/twistDigitalBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://twistdigital.net/iab.json": { - "timestamp": "2026-05-27T12:19:33.328Z", + "timestamp": "2026-06-02T15:45:13.806Z", "disclosures": [ { "identifier": "vdzj1_{id}", @@ -31,6 +31,28 @@ ] } }, + "purposes": { + "1292": { + "purposes": [ + 1, + 2, + 3, + 4, + 9 + ], + "legIntPurposes": [ + 7, + 10 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ucfunnelAnalyticsAdapter.json b/metadata/modules/ucfunnelAnalyticsAdapter.json index b6c4106bc8e..1dd4c41e018 100644 --- a/metadata/modules/ucfunnelAnalyticsAdapter.json +++ b/metadata/modules/ucfunnelAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/ucfunnelBidAdapter.json b/metadata/modules/ucfunnelBidAdapter.json index 940a8d8b81f..97df92e9a1f 100644 --- a/metadata/modules/ucfunnelBidAdapter.json +++ b/metadata/modules/ucfunnelBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/uid2IdSystem.json b/metadata/modules/uid2IdSystem.json index eda901ff5f1..8310f2824ea 100644 --- a/metadata/modules/uid2IdSystem.json +++ b/metadata/modules/uid2IdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/underdogmediaBidAdapter.json b/metadata/modules/underdogmediaBidAdapter.json index ed15fc865b5..3b6f3ddc748 100644 --- a/metadata/modules/underdogmediaBidAdapter.json +++ b/metadata/modules/underdogmediaBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.underdog.media/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:33.447Z", + "timestamp": "2026-06-02T15:45:14.244Z", "disclosures": [ { "identifier": "udm_edge_floater_fcap", @@ -57,6 +57,18 @@ ] } }, + "purposes": { + "159": { + "purposes": [ + 1, + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/undertoneBidAdapter.json b/metadata/modules/undertoneBidAdapter.json index 100fec75ded..d26e904d092 100644 --- a/metadata/modules/undertoneBidAdapter.json +++ b/metadata/modules/undertoneBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.undertone.com/js/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:33.526Z", + "timestamp": "2026-06-02T15:45:14.443Z", "disclosures": [] } }, + "purposes": { + "677": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/unicornBidAdapter.json b/metadata/modules/unicornBidAdapter.json index c330896ba3a..979b493c732 100644 --- a/metadata/modules/unicornBidAdapter.json +++ b/metadata/modules/unicornBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/unifiedIdSystem.json b/metadata/modules/unifiedIdSystem.json index 4d75d606770..a1f432bcaeb 100644 --- a/metadata/modules/unifiedIdSystem.json +++ b/metadata/modules/unifiedIdSystem.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ttd-misc-public-assets.s3.us-west-2.amazonaws.com/deviceStorageDisclosureURL.json": { - "timestamp": "2026-05-27T12:19:33.710Z", + "timestamp": "2026-06-02T15:45:14.627Z", "disclosures": [] } }, + "purposes": { + "21": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/uniquestAnalyticsAdapter.json b/metadata/modules/uniquestAnalyticsAdapter.json index 49fb7687644..239042ba0a3 100644 --- a/metadata/modules/uniquestAnalyticsAdapter.json +++ b/metadata/modules/uniquestAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/uniquestBidAdapter.json b/metadata/modules/uniquestBidAdapter.json index 606f3a8e02a..07450fbe333 100644 --- a/metadata/modules/uniquestBidAdapter.json +++ b/metadata/modules/uniquestBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/uniquest_widgetBidAdapter.json b/metadata/modules/uniquest_widgetBidAdapter.json index 6caf1c1516d..083fc2adcc5 100644 --- a/metadata/modules/uniquest_widgetBidAdapter.json +++ b/metadata/modules/uniquest_widgetBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/unrulyBidAdapter.json b/metadata/modules/unrulyBidAdapter.json index 6424edd1a10..f34ddc4e025 100644 --- a/metadata/modules/unrulyBidAdapter.json +++ b/metadata/modules/unrulyBidAdapter.json @@ -2,10 +2,31 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://video.unrulymedia.com/deviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:33.711Z", + "timestamp": "2026-06-02T15:45:14.627Z", "disclosures": [] } }, + "purposes": { + "36": { + "purposes": [ + 1, + 2, + 3, + 4 + ], + "legIntPurposes": [ + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/userId.json b/metadata/modules/userId.json index 03eba774c59..5829c8d6f9b 100644 --- a/metadata/modules/userId.json +++ b/metadata/modules/userId.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/userId-optout.json": { - "timestamp": "2026-05-27T12:17:29.212Z", + "timestamp": "2026-06-02T15:42:53.594Z", "disclosures": [ { "identifier": "_pbjs_id_optout", @@ -19,6 +19,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "prebid", diff --git a/metadata/modules/utiqIdSystem.json b/metadata/modules/utiqIdSystem.json index 6b7f5f55747..1e9fbfeed3a 100644 --- a/metadata/modules/utiqIdSystem.json +++ b/metadata/modules/utiqIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/utiqDeviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:33.711Z", + "timestamp": "2026-06-02T15:45:14.627Z", "disclosures": [ { "identifier": "utiqPass", @@ -21,6 +21,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/utiqMtpIdSystem.json b/metadata/modules/utiqMtpIdSystem.json index 5fd83f3b3eb..9adb313b3cd 100644 --- a/metadata/modules/utiqMtpIdSystem.json +++ b/metadata/modules/utiqMtpIdSystem.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/utiqDeviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:33.712Z", + "timestamp": "2026-06-02T15:45:14.641Z", "disclosures": [ { "identifier": "utiqPass", @@ -21,6 +21,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/validationFpdModule.json b/metadata/modules/validationFpdModule.json index 572de202651..ce41a217a5d 100644 --- a/metadata/modules/validationFpdModule.json +++ b/metadata/modules/validationFpdModule.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/prebid/sharedId-optout.json": { - "timestamp": "2026-05-27T12:17:29.212Z", + "timestamp": "2026-06-02T15:42:53.593Z", "disclosures": [ { "identifier": "_pubcid_optout", @@ -24,6 +24,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "prebid", diff --git a/metadata/modules/valuadBidAdapter.json b/metadata/modules/valuadBidAdapter.json index 16577199043..cf86e3573da 100644 --- a/metadata/modules/valuadBidAdapter.json +++ b/metadata/modules/valuadBidAdapter.json @@ -2,10 +2,21 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.valuad.cloud/tcfdevice.json": { - "timestamp": "2026-05-27T12:19:33.712Z", + "timestamp": "2026-06-02T15:45:14.641Z", "disclosures": [] } }, + "purposes": { + "1478": { + "purposes": [ + 1, + 2 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vdoaiBidAdapter.json b/metadata/modules/vdoaiBidAdapter.json index bd923c9d36e..e5e92e9920b 100644 --- a/metadata/modules/vdoaiBidAdapter.json +++ b/metadata/modules/vdoaiBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/ventesBidAdapter.json b/metadata/modules/ventesBidAdapter.json index 9f4d8112fb2..687005ead5b 100644 --- a/metadata/modules/ventesBidAdapter.json +++ b/metadata/modules/ventesBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/verbenBidAdapter.json b/metadata/modules/verbenBidAdapter.json index 47a939ac97a..593e62d6381 100644 --- a/metadata/modules/verbenBidAdapter.json +++ b/metadata/modules/verbenBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/viantBidAdapter.json b/metadata/modules/viantBidAdapter.json index a593d3a248c..21677236ee0 100644 --- a/metadata/modules/viantBidAdapter.json +++ b/metadata/modules/viantBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vibrantmediaBidAdapter.json b/metadata/modules/vibrantmediaBidAdapter.json index 44294fc8f60..180306f4204 100644 --- a/metadata/modules/vibrantmediaBidAdapter.json +++ b/metadata/modules/vibrantmediaBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vidazooBidAdapter.json b/metadata/modules/vidazooBidAdapter.json index 17217d4820a..beabcf40ea8 100644 --- a/metadata/modules/vidazooBidAdapter.json +++ b/metadata/modules/vidazooBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vidazoo.com/gdpr-tcf/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:33.984Z", + "timestamp": "2026-06-02T15:45:15.048Z", "disclosures": [ { "identifier": "ck48wz12sqj7", @@ -77,6 +77,27 @@ ] } }, + "purposes": { + "744": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/videobyteBidAdapter.json b/metadata/modules/videobyteBidAdapter.json index 7d8e661e20c..a4ffde0133e 100644 --- a/metadata/modules/videobyteBidAdapter.json +++ b/metadata/modules/videobyteBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/videoheroesBidAdapter.json b/metadata/modules/videoheroesBidAdapter.json index 7b43e0bb728..2be2d419731 100644 --- a/metadata/modules/videoheroesBidAdapter.json +++ b/metadata/modules/videoheroesBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/videonowBidAdapter.json b/metadata/modules/videonowBidAdapter.json index dbc945a7e04..bcca6ba819c 100644 --- a/metadata/modules/videonowBidAdapter.json +++ b/metadata/modules/videonowBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/videoreachBidAdapter.json b/metadata/modules/videoreachBidAdapter.json index f36b4a92037..5f9e5fd9065 100644 --- a/metadata/modules/videoreachBidAdapter.json +++ b/metadata/modules/videoreachBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vidoomyBidAdapter.json b/metadata/modules/vidoomyBidAdapter.json index 733b15c5f1a..8ea27fcbaf0 100644 --- a/metadata/modules/vidoomyBidAdapter.json +++ b/metadata/modules/vidoomyBidAdapter.json @@ -2,10 +2,28 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vidoomy.com/storageurl/devicestoragediscurl.json": { - "timestamp": "2026-05-27T12:19:34.095Z", + "timestamp": "2026-06-02T15:45:15.963Z", "disclosures": [] } }, + "purposes": { + "380": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/viewdeosDXBidAdapter.json b/metadata/modules/viewdeosDXBidAdapter.json index 18aff1f272c..dd4ffc66ff9 100644 --- a/metadata/modules/viewdeosDXBidAdapter.json +++ b/metadata/modules/viewdeosDXBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/viouslyBidAdapter.json b/metadata/modules/viouslyBidAdapter.json index ebda39a1e53..ad2248596a4 100644 --- a/metadata/modules/viouslyBidAdapter.json +++ b/metadata/modules/viouslyBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://bid.bricks-co.com/.well-known/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:34.576Z", + "timestamp": "2026-06-02T15:45:20.367Z", "disclosures": [ { "identifier": "fastCMP-addtlConsent", @@ -28,6 +28,34 @@ ] } }, + "purposes": { + "1028": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/viqeoBidAdapter.json b/metadata/modules/viqeoBidAdapter.json index 40b57b80b65..59610e271ea 100644 --- a/metadata/modules/viqeoBidAdapter.json +++ b/metadata/modules/viqeoBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/visiblemeasuresBidAdapter.json b/metadata/modules/visiblemeasuresBidAdapter.json index c64248bc05e..f9454a6dfba 100644 --- a/metadata/modules/visiblemeasuresBidAdapter.json +++ b/metadata/modules/visiblemeasuresBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vistarsBidAdapter.json b/metadata/modules/vistarsBidAdapter.json index 29a78ec3165..484a825d608 100644 --- a/metadata/modules/vistarsBidAdapter.json +++ b/metadata/modules/vistarsBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/visxBidAdapter.json b/metadata/modules/visxBidAdapter.json index 81629003db9..f405cc95901 100644 --- a/metadata/modules/visxBidAdapter.json +++ b/metadata/modules/visxBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.yoc.com/visx/sellers/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:34.577Z", + "timestamp": "2026-06-02T15:45:20.367Z", "disclosures": [ { "identifier": "__vads", @@ -85,6 +85,28 @@ ] } }, + "purposes": { + "154": { + "purposes": [ + 1, + 3, + 4, + 9, + 10 + ], + "legIntPurposes": [ + 2, + 7 + ], + "flexiblePurposes": [ + 2, + 7 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vlybyBidAdapter.json b/metadata/modules/vlybyBidAdapter.json index 59270ebfd82..d702cb394f8 100644 --- a/metadata/modules/vlybyBidAdapter.json +++ b/metadata/modules/vlybyBidAdapter.json @@ -2,10 +2,21 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.vlyby.com/conf/iab/gvl.json": { - "timestamp": "2026-05-27T12:19:34.794Z", + "timestamp": "2026-06-02T15:45:21.299Z", "disclosures": [] } }, + "purposes": { + "1009": { + "purposes": [ + 2, + 7 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/voxBidAdapter.json b/metadata/modules/voxBidAdapter.json index d78305696c6..51e25d54077 100644 --- a/metadata/modules/voxBidAdapter.json +++ b/metadata/modules/voxBidAdapter.json @@ -2,10 +2,33 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://st.hybrid.ai/policy/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:35.222Z", + "timestamp": "2026-06-02T15:45:21.971Z", "disclosures": [] } }, + "purposes": { + "206": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vrtcalBidAdapter.json b/metadata/modules/vrtcalBidAdapter.json index c7940b0f81f..85caf8da32f 100644 --- a/metadata/modules/vrtcalBidAdapter.json +++ b/metadata/modules/vrtcalBidAdapter.json @@ -2,10 +2,22 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://vrtcal.com/docs/gdpr-tcf-disclosures.json": { - "timestamp": "2026-05-27T12:19:35.222Z", + "timestamp": "2026-06-02T15:45:21.971Z", "disclosures": [] } }, + "purposes": { + "706": { + "purposes": [], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/vuukleBidAdapter.json b/metadata/modules/vuukleBidAdapter.json index ac44c2e379d..43f0b5372ce 100644 --- a/metadata/modules/vuukleBidAdapter.json +++ b/metadata/modules/vuukleBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.vuukle.com/data-privacy/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:35.269Z", + "timestamp": "2026-06-02T15:45:22.388Z", "disclosures": [ { "identifier": "vuukle_token", @@ -408,6 +408,34 @@ ] } }, + "purposes": { + "1004": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10 + ], + "specialFeatures": [ + 1, + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/waardexBidAdapter.json b/metadata/modules/waardexBidAdapter.json index 740b3001807..a98776819e7 100644 --- a/metadata/modules/waardexBidAdapter.json +++ b/metadata/modules/waardexBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/weboramaRtdProvider.json b/metadata/modules/weboramaRtdProvider.json index 4f3de9ad17e..df30ba022db 100644 --- a/metadata/modules/weboramaRtdProvider.json +++ b/metadata/modules/weboramaRtdProvider.json @@ -2,10 +2,40 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cstatic.weborama.fr/tcf/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:35.561Z", + "timestamp": "2026-06-02T15:45:22.883Z", "disclosures": [] } }, + "purposes": { + "284": { + "purposes": [ + 1, + 3, + 4, + 5, + 6 + ], + "legIntPurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "flexiblePurposes": [ + 2, + 7, + 8, + 9, + 10, + 11 + ], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/welectBidAdapter.json b/metadata/modules/welectBidAdapter.json index 4d250b7280b..28050c886e2 100644 --- a/metadata/modules/welectBidAdapter.json +++ b/metadata/modules/welectBidAdapter.json @@ -2,10 +2,24 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://www.welect.de/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:36.049Z", + "timestamp": "2026-06-02T15:45:23.158Z", "disclosures": [] } }, + "purposes": { + "282": { + "purposes": [ + 1 + ], + "legIntPurposes": [ + 2 + ], + "flexiblePurposes": [ + 2 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/widespaceBidAdapter.json b/metadata/modules/widespaceBidAdapter.json index f757d58fe94..12a7e3c1b75 100644 --- a/metadata/modules/widespaceBidAdapter.json +++ b/metadata/modules/widespaceBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/winrBidAdapter.json b/metadata/modules/winrBidAdapter.json index e36f51fbf6b..9bcf706460d 100644 --- a/metadata/modules/winrBidAdapter.json +++ b/metadata/modules/winrBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/wipesBidAdapter.json b/metadata/modules/wipesBidAdapter.json index 2442394bbbe..30184dc1620 100644 --- a/metadata/modules/wipesBidAdapter.json +++ b/metadata/modules/wipesBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/wurflRtdProvider.json b/metadata/modules/wurflRtdProvider.json index 6bc8cc0bfab..a3fcd0bea7b 100644 --- a/metadata/modules/wurflRtdProvider.json +++ b/metadata/modules/wurflRtdProvider.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn.jsdelivr.net/gh/prebid/Prebid.js/metadata/disclosures/modules/wurflRtdProvider.json": { - "timestamp": "2026-05-27T12:19:36.517Z", + "timestamp": "2026-06-02T15:45:23.966Z", "disclosures": [ { "identifier": "wurflrtd", @@ -12,6 +12,7 @@ ] } }, + "purposes": {}, "components": [ { "componentType": "rtd", diff --git a/metadata/modules/xeBidAdapter.json b/metadata/modules/xeBidAdapter.json index a76d9ac9a06..5f77857ed03 100644 --- a/metadata/modules/xeBidAdapter.json +++ b/metadata/modules/xeBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yahooAdsBidAdapter.json b/metadata/modules/yahooAdsBidAdapter.json index 87c29234312..33593c7f683 100644 --- a/metadata/modules/yahooAdsBidAdapter.json +++ b/metadata/modules/yahooAdsBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://meta.legal.yahoo.com/iab-tcf/v2/device-storage-disclosure.json": { - "timestamp": "2026-05-27T12:19:36.518Z", + "timestamp": "2026-06-02T15:45:23.980Z", "disclosures": [ { "identifier": "vmcid", @@ -57,6 +57,28 @@ ] } }, + "purposes": { + "25": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yaleoBidAdapter.json b/metadata/modules/yaleoBidAdapter.json index 0c17f04d691..29d64938ad1 100644 --- a/metadata/modules/yaleoBidAdapter.json +++ b/metadata/modules/yaleoBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://audienzz.com/device_storage_disclosure_vendor_783.json": { - "timestamp": "2026-05-27T12:19:36.518Z", + "timestamp": "2026-06-02T15:45:23.980Z", "disclosures": [] } }, + "purposes": { + "783": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 2 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yandexAnalyticsAdapter.json b/metadata/modules/yandexAnalyticsAdapter.json index 702fa61b188..ef7ca454e3b 100644 --- a/metadata/modules/yandexAnalyticsAdapter.json +++ b/metadata/modules/yandexAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/yandexBidAdapter.json b/metadata/modules/yandexBidAdapter.json index 2f0c7028889..39d407f204c 100644 --- a/metadata/modules/yandexBidAdapter.json +++ b/metadata/modules/yandexBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yandexIdSystem.json b/metadata/modules/yandexIdSystem.json index 615f95581b8..ec4a33246e3 100644 --- a/metadata/modules/yandexIdSystem.json +++ b/metadata/modules/yandexIdSystem.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "userId", diff --git a/metadata/modules/yieldlabBidAdapter.json b/metadata/modules/yieldlabBidAdapter.json index 1bb78349ef1..7f9f5f2c8c1 100644 --- a/metadata/modules/yieldlabBidAdapter.json +++ b/metadata/modules/yieldlabBidAdapter.json @@ -2,10 +2,27 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://ad.yieldlab.net/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:36.519Z", + "timestamp": "2026-06-02T15:45:23.980Z", "disclosures": [] } }, + "purposes": { + "70": { + "purposes": [ + 1, + 2, + 3, + 4, + 7, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [ + 1 + ] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yieldliftBidAdapter.json b/metadata/modules/yieldliftBidAdapter.json index 4d2fb03b69f..dc4e8608ddb 100644 --- a/metadata/modules/yieldliftBidAdapter.json +++ b/metadata/modules/yieldliftBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yieldloveBidAdapter.json b/metadata/modules/yieldloveBidAdapter.json index 68b6265be4e..557a3fd4837 100644 --- a/metadata/modules/yieldloveBidAdapter.json +++ b/metadata/modules/yieldloveBidAdapter.json @@ -2,7 +2,7 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://cdn-a.yieldlove.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:36.642Z", + "timestamp": "2026-06-02T15:45:24.459Z", "disclosures": [ { "identifier": "session_id", @@ -35,6 +35,26 @@ ] } }, + "purposes": { + "251": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yieldmoBidAdapter.json b/metadata/modules/yieldmoBidAdapter.json index 3a56012f282..08b064c9265 100644 --- a/metadata/modules/yieldmoBidAdapter.json +++ b/metadata/modules/yieldmoBidAdapter.json @@ -2,10 +2,32 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://devicestoragedisclosureurl.yieldmo.com/deviceStorage.json": { - "timestamp": "2026-05-27T12:19:36.952Z", + "timestamp": "2026-06-02T15:45:24.814Z", "disclosures": [] } }, + "purposes": { + "173": { + "purposes": [ + 1, + 3, + 4 + ], + "legIntPurposes": [ + 2, + 7, + 9, + 10 + ], + "flexiblePurposes": [ + 2, + 7, + 9, + 10 + ], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yieldoneAnalyticsAdapter.json b/metadata/modules/yieldoneAnalyticsAdapter.json index 520f78be9d1..671c82d462d 100644 --- a/metadata/modules/yieldoneAnalyticsAdapter.json +++ b/metadata/modules/yieldoneAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/yieldoneBidAdapter.json b/metadata/modules/yieldoneBidAdapter.json index 7f8be417705..d6620d813dc 100644 --- a/metadata/modules/yieldoneBidAdapter.json +++ b/metadata/modules/yieldoneBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/yuktamediaAnalyticsAdapter.json b/metadata/modules/yuktamediaAnalyticsAdapter.json index 6f15568aeb1..88a9cbd5268 100644 --- a/metadata/modules/yuktamediaAnalyticsAdapter.json +++ b/metadata/modules/yuktamediaAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/zeotapIdPlusIdSystem.json b/metadata/modules/zeotapIdPlusIdSystem.json index 22aba93cf38..7514e1c3b14 100644 --- a/metadata/modules/zeotapIdPlusIdSystem.json +++ b/metadata/modules/zeotapIdPlusIdSystem.json @@ -2,10 +2,26 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zd.rqtrk.eu/assets/iab-disclosure.json": { - "timestamp": "2026-05-27T12:19:37.212Z", + "timestamp": "2026-06-02T15:45:25.198Z", "disclosures": [] } }, + "purposes": { + "301": { + "purposes": [ + 1, + 3, + 4, + 5, + 6, + 9, + 10 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "userId", diff --git a/metadata/modules/zeta_globalBidAdapter.json b/metadata/modules/zeta_globalBidAdapter.json index 4a8b2734d29..9d7d77870e2 100644 --- a/metadata/modules/zeta_globalBidAdapter.json +++ b/metadata/modules/zeta_globalBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zetaglobal.com/ZetaDeviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:37.529Z", + "timestamp": "2026-06-02T15:45:26.300Z", "disclosures": [] } }, + "purposes": { + "469": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/zeta_global_sspAnalyticsAdapter.json b/metadata/modules/zeta_global_sspAnalyticsAdapter.json index 6a200be3dfc..6cf5e8aa7c0 100644 --- a/metadata/modules/zeta_global_sspAnalyticsAdapter.json +++ b/metadata/modules/zeta_global_sspAnalyticsAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "analytics", diff --git a/metadata/modules/zeta_global_sspBidAdapter.json b/metadata/modules/zeta_global_sspBidAdapter.json index 9c178d89835..cd1e7111f80 100644 --- a/metadata/modules/zeta_global_sspBidAdapter.json +++ b/metadata/modules/zeta_global_sspBidAdapter.json @@ -2,10 +2,30 @@ "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": { "https://zetaglobal.com/ZetaDeviceStorageDisclosure.json": { - "timestamp": "2026-05-27T12:19:37.667Z", + "timestamp": "2026-06-02T15:45:26.635Z", "disclosures": [] } }, + "purposes": { + "469": { + "purposes": [ + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11 + ], + "legIntPurposes": [], + "flexiblePurposes": [], + "specialFeatures": [] + } + }, "components": [ { "componentType": "bidder", diff --git a/metadata/modules/zmaticooBidAdapter.json b/metadata/modules/zmaticooBidAdapter.json index 15f3e19f325..2959e4ec994 100644 --- a/metadata/modules/zmaticooBidAdapter.json +++ b/metadata/modules/zmaticooBidAdapter.json @@ -1,6 +1,7 @@ { "NOTICE": "do not edit - this file is autogenerated by `gulp update-metadata`", "disclosures": {}, + "purposes": {}, "components": [ { "componentType": "bidder", diff --git a/metadata/storageDisclosure.mjs b/metadata/storageDisclosure.mjs index 7568dfec351..c36535b53fa 100644 --- a/metadata/storageDisclosure.mjs +++ b/metadata/storageDisclosure.mjs @@ -87,14 +87,15 @@ export function logErrorSummary() { }) } +export function getPublicURL(url) { + return LOCAL_DISCLOSURE_PATTERN.test(url) ? url.replace(LOCAL_DISCLOSURE_PATTERN, LOCAL_DISCLOSURES_URL) : url; +} + export const fetchDisclosure = (() => { const disclosures = {}; return function (metadata) { const url = metadata.disclosureURL; const isLocal = LOCAL_DISCLOSURE_PATTERN.test(url); - if (isLocal) { - metadata.disclosureURL = url.replace(LOCAL_DISCLOSURE_PATTERN, LOCAL_DISCLOSURES_URL); - } if (!disclosures.hasOwnProperty(url)) { console.info(`Fetching disclosure for "${metadata.componentType}.${metadata.componentName}" (gvl ID: ${metadata.gvlid}) from "${url}"...`); let disclosure; diff --git a/modules/tcfControl.ts b/modules/tcfControl.ts index 64e6ae5eb24..2f75063d81d 100644 --- a/modules/tcfControl.ts +++ b/modules/tcfControl.ts @@ -7,7 +7,7 @@ import { config } from '../src/config.js'; import adapterManager, { gdprDataHandler } from '../src/adapterManager.js'; import * as events from '../src/events.js'; import { EVENTS } from '../src/constants.js'; -import { GDPR_GVLIDS, VENDORLESS_GVLID } from '../src/consentHandler.js'; +import { GDPR_GVLIDS, GVL_PURPOSES, VENDORLESS_GVLID } from '../src/consentHandler.js'; import { MODULE_TYPE_ANALYTICS, MODULE_TYPE_BIDDER, @@ -33,6 +33,8 @@ import { ACTIVITY_TRANSMIT_PRECISE_GEO, ACTIVITY_TRANSMIT_UFPD } from '../src/activities/activities.js'; +// @ts-expect-error the ts compiler is confused by build-time renaming of validate.mjs to validate.js +import { validatePurposeDeclarations } from '../libraries/purposeDeclarations/validate.js'; import type { TCFConsentData } from "./consentManagementTcf.ts"; export const STRICT_STORAGE_ENFORCEMENT = 'strictStorageEnforcement'; @@ -121,11 +123,27 @@ const GVLID_LOOKUP_PRIORITY = [ const RULE_NAME = 'TCF2'; const RULE_HANDLES = []; - -// in JS we do not have access to the GVL; assume that everyone declares legitimate interest for basic ads -const LI_PURPOSES = [2]; const PUBLISHER_LI_PURPOSES = [2, 7, 9, 10]; +export type PurposeDeclarations = { + /** + * Special feature IDs declared as performed on the legal basis of consent. + */ + specialFeatures?: number[]; + /** + * Purpose IDs declared as performed on the legal basis of consent. IDs included here must not also be in `legIntPurposes`. + */ + purposes?: number[]; + /** + * Purpose IDs declared as performed on the legal basis of legitimate interest. IDs included here must not also be in `purposes`. + */ + legIntPurposes?: number[]; + /** + * Purpose IDs where the legal basis is flexible - can be performed either using consent or legitimate interest. * Each purpose ID listed here must also be present one of `purposes` or `legIntPurposes`. + */ + flexiblePurposes?: number[]; +} + declare module '../src/config' { interface Config { /** @@ -133,8 +151,16 @@ declare module '../src/config' { * by the modules themselves. */ gvlMapping?: { [moduleName: string]: number } + /** + * Map from GVL ID to an object describing the legal basis (consent or legitimate interest) that applies to each purpose or feature. This follows the same format as the GVL - + * see https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20Consent%20string%20and%20vendor%20list%20formats%20v2.md - + * and by default is taken from it, for those GVL IDs that are known to Prebid (i.e. declared by adapters, not set through gvlMapping). + * When the GVL ID is not known, the default is {purposes: [1,2,4,7], flexiblePurposes: [2], legIntPurposes: [], specialFeatures: [1]}. + */ + gvlPurposeMapping?: { [gvlId: number]: PurposeDeclarations } } } + /** * Retrieve a module's GVL ID. */ @@ -199,14 +225,62 @@ export function shouldEnforce(consentData, purpose, name) { return consentData && consentData.gdprApplies; } -export function getAcceptableFlags(consentData: TCFConsentData, purpose: number, gvlid: number): { acceptConsent: boolean, acceptLI: boolean } { +export const DEFAULT_PURPOSE_DECLARATION: PurposeDeclarations = { + purposes: [1, 2, 4, 7], + legIntPurposes: [], + flexiblePurposes: [2], + specialFeatures: [1] +} +export const NO_PURPOSE_DECLARATION: PurposeDeclarations = { + purposes: [], + legIntPurposes: [], + flexiblePurposes: [], + specialFeatures: [] +} + +let gvlPurposeMapping = {}; + +config.getConfig('gvlPurposeMapping', (cfg) => { + // validate now to give warnings regardless of whether the mapping will actually be used + gvlPurposeMapping = cfg.gvlPurposeMapping ?? {}; + Object.entries(gvlPurposeMapping).forEach(([key, value]) => { + value = Object.assign({}, NO_PURPOSE_DECLARATION, value); + const errorMessage = validatePurposeDeclarations(value); + if (errorMessage != null) { + logWarn(`gvlPurposeMapping for GVL ID ${key} is invalid: ${errorMessage}; assuming no legal basis for any purpose`, value); + value = NO_PURPOSE_DECLARATION; + } + gvlPurposeMapping[key] = value; + }) +}) + +export function getPurposeDeclarations(gvlId) { + let declaration = gvlPurposeMapping?.[gvlId] ?? GVL_PURPOSES[gvlId]; + if (declaration == null) { + logWarn(`No purpose declarations found for GVL ID ${gvlId}. You may set one using setConfig({gvlPurposeMapping}). Falling back to ${JSON.stringify(DEFAULT_PURPOSE_DECLARATION)}`); + return DEFAULT_PURPOSE_DECLARATION; + } + return declaration; +} + +export function getAcceptableFlags(consentData: TCFConsentData, type: 'purpose' | 'feature', purpose: number, gvlid: number, purposeDeclarations = getPurposeDeclarations): { + acceptConsent: boolean, + acceptLI: boolean +} { + let acceptConsent, acceptLI; + if (gvlid === VENDORLESS_GVLID) { + acceptConsent = true; + acceptLI = type === 'feature' ? false : PUBLISHER_LI_PURPOSES.includes(purpose) + } else { + const { purposes, legIntPurposes, flexiblePurposes, specialFeatures } = purposeDeclarations(gvlid); + acceptLI = type === 'feature' ? false : legIntPurposes.includes(purpose) || flexiblePurposes.includes(purpose); + acceptConsent = type === 'feature' ? specialFeatures.includes(purpose) : acceptLI || purposes.includes(purpose); + } // https://github.com/InteractiveAdvertisingBureau/GDPR-Transparency-and-Consent-Framework/blob/master/TCFv2/IAB%20Tech%20Lab%20-%20CMP%20API%20v2.md#tcdata // 0 - Not Allowed // 1 - Require Consent // 2 - Require Legitimate Interest - const restriction = consentData.vendorData?.publisher?.restrictions?.[purpose]?.[gvlid]; - let acceptConsent = true; - let acceptLI = LI_PURPOSES.includes(purpose); + const restriction = type === 'feature' ? null : consentData.vendorData?.publisher?.restrictions?.[purpose]?.[gvlid]; if (restriction === 0) { acceptConsent = acceptLI = false; } else if (restriction === 1) { @@ -223,16 +297,13 @@ function getConsentOrLI(consentData, path, id, acceptConsent, acceptLI) { } function getConsent(consentData, type, purposeNo, gvlId) { + const { acceptConsent, acceptLI } = getAcceptableFlags(consentData, type, purposeNo, gvlId); let purpose; if (CONSENT_PATHS[type] !== false) { - purpose = !!deepAccess(consentData, `vendorData.${CONSENT_PATHS[type]}.${purposeNo}`); + purpose = acceptConsent && !!deepAccess(consentData, `vendorData.${CONSENT_PATHS[type]}.${purposeNo}`); } else { - const [path, liPurposes] = gvlId === VENDORLESS_GVLID - ? ['publisher', PUBLISHER_LI_PURPOSES] - : ['purpose', LI_PURPOSES]; - purpose = getConsentOrLI(consentData, path, purposeNo, true, liPurposes.includes(purposeNo)); + purpose = getConsentOrLI(consentData, gvlId === VENDORLESS_GVLID ? 'publisher' : 'purpose', purposeNo, acceptConsent, acceptLI); } - const { acceptConsent, acceptLI } = getAcceptableFlags(consentData, purposeNo, gvlId); return { purpose, vendor: getConsentOrLI(consentData, 'vendor', gvlId, acceptConsent, acceptLI) diff --git a/plugins/callerContext.js b/plugins/callerContext.js index 4df6de5b9ca..1b9e50d7f87 100644 --- a/plugins/callerContext.js +++ b/plugins/callerContext.js @@ -1,6 +1,5 @@ -const {relPath, isInDirectory, TEST_DIR, getFreeName, getModuleName, PREBID_ROOT } = require('./utils.js'); +const {relPath, isInDirectory, TEST_DIR, getFreeName, getModuleName, getMetadata, PREBID_ROOT } = require('./utils.js'); const t = require('@babel/core').types; -const fs = require('fs'); const osPath = require('path'); const NAMES = { @@ -15,16 +14,15 @@ const getCallers = (() => { return function (filename, message) { if (!cache.hasOwnProperty(filename)) { const moduleName = getModuleName(osPath.resolve(PREBID_ROOT, filename)); - const metadataFile = osPath.resolve(__dirname, `../metadata/modules/${moduleName}.json`); - if (moduleName != null && fs.existsSync(metadataFile)) { - const metadata = JSON.parse(fs.readFileSync(metadataFile).toString()); + const metadata = getMetadata(moduleName); + if (moduleName != null && metadata != null) { const callers = metadata.components.reduce((summary, {gvlid, componentName, componentType}) => { summary.gvlids.add(gvlid) summary.callers.push([componentType, componentName]) return summary; }, {gvlids: new Set(), callers: []}); if (!callers.callers.length) { - throw new Error(`Unexpected empty component list from metadata file ${metadataFile}`); + throw new Error(`Unexpected empty component list from metadata for '${moduleName}'`); } if (callers.gvlids.size > 1) { console.warn(`WARNING: more than one GVL ID is associated with '${filename}'. ${message}`) diff --git a/plugins/gvlPurposes.js b/plugins/gvlPurposes.js new file mode 100644 index 00000000000..7925fe854ea --- /dev/null +++ b/plugins/gvlPurposes.js @@ -0,0 +1,29 @@ +const { + relPath, + getFreeName, + getModuleName, + getMetadata +} = require('./utils.js'); +const { types: t } = require('@babel/core'); + +function getPurposes(filename) { + const metadata = getMetadata(getModuleName(filename)); + return Object.keys(metadata?.purposes ?? {}).length > 0 ? metadata.purposes : null; +} + +module.exports = function (api, options) { + return { + visitor: { + Program(path, state) { + // register purposes, legIntPurposes, and flexiblePurposes from the GVL into consentHandler/GVL_PURPOSES + const purposes = getPurposes(state.filename); + if (purposes != null) { + const gvlPurposes = getFreeName(path, '__gvl_purposes'); + path.node.body.unshift(...api.parse(`import {GVL_PURPOSES as ${gvlPurposes}} from '${relPath(state.filename, 'src/consentHandler.js')}';`, { filename: state.filename }).program.body); + path.node.body.push(...api.parse(`Object.assign(${gvlPurposes}, ${JSON.stringify(getPurposes(state.filename))});`, { filename: state.filename }).program.body); + } + } + } + }; +}; + diff --git a/plugins/utils.js b/plugins/utils.js index 7f8a9644679..103d84d98fe 100644 --- a/plugins/utils.js +++ b/plugins/utils.js @@ -1,4 +1,5 @@ const path = require('path'); +const fs = require('fs'); const PREBID_ROOT = path.resolve(__dirname, '..'); const TEST_DIR = path.resolve(__dirname, '../test'); @@ -18,6 +19,22 @@ function getModuleName(filename) { return null; } +const getMetadata = (() => { + const cache = {}; + return function(moduleName) { + if (!moduleName) return null; + if (!cache.hasOwnProperty(moduleName)) { + const metadataFile = path.resolve(__dirname, `../metadata/modules/${moduleName}.json`); + if (fs.existsSync(metadataFile)) { + cache[moduleName] = JSON.parse(fs.readFileSync(metadataFile).toString()) + } else { + cache[moduleName] = null; + } + } + return cache[moduleName]; + } +})(); + // on Windows, require paths are not filesystem paths const SEP_PAT = new RegExp(path.sep.replace(/\\/g, '\\\\'), 'g') @@ -47,6 +64,7 @@ module.exports = { PREBID_ROOT, TEST_DIR, getModuleName, + getMetadata, relPath, isInDirectory, getFreeName diff --git a/src/consentHandler.ts b/src/consentHandler.ts index 22c0c476279..9941bc1b57b 100644 --- a/src/consentHandler.ts +++ b/src/consentHandler.ts @@ -353,3 +353,4 @@ export function multiHandler(handlers = ALL_HANDLERS): MultiHandler { } export const allConsent = multiHandler(); +export const GVL_PURPOSES = {}; // this is populated by plugins/gvlPurposes.js diff --git a/test/build-logic/gvl_spec.mjs b/test/build-logic/gvl_spec.mjs index 666dd3f2513..ba4d057b943 100644 --- a/test/build-logic/gvl_spec.mjs +++ b/test/build-logic/gvl_spec.mjs @@ -1,6 +1,7 @@ import { expect } from 'chai'; import { describe, it } from 'mocha'; -import { isValidGvlId } from '../../metadata/gvl.mjs'; +import { getPurposes, isValidGvlId } from '../../metadata/gvl.mjs'; +import { validatePurposeDeclarations } from '../../libraries/purposeDeclarations/validate.mjs'; describe('gvl build time checks', () => { let gvl; @@ -28,5 +29,43 @@ describe('gvl build time checks', () => { expect(await isValidGvlId(123, getGvl)).to.be.false; }) }) + }); + + describe('getPurposes', () => { + it('should return purposes from gvl', async () => { + const purposes = { + purposes: [1], + legIntPurposes: [2], + flexiblePurposes: [3], + specialFeatures: [4] + }; + gvl = { + vendors: { + 123: { + ...purposes + } + } + } + expect(await getPurposes(123, getGvl)).to.eql(purposes); + }) + }) + + describe('validatePurposeDeclarations', () => { + Object.entries({ + 'flexiblePurpose without corresponding purpose / LI': { + flexiblePurposes: [1], + purposes: [], + legIntPurposes: [], + }, + 'both consent as LI as legal basis': { + purposes: [1], + legIntPurposes: [1], + flexiblePurposes: [], + } + }).forEach(([t, purposes]) => { + it(`should fail on ${t}`, () => { + expect(validatePurposeDeclarations(purposes)).to.be.a('string'); + }) + }) }) }) diff --git a/test/spec/modules/tcfControl_spec.js b/test/spec/modules/tcfControl_spec.js index a1835e0f3e3..54db2881573 100644 --- a/test/spec/modules/tcfControl_spec.js +++ b/test/spec/modules/tcfControl_spec.js @@ -1,11 +1,15 @@ import { - accessDeviceRule, accessRequestCredentialsRule, + accessDeviceRule, + accessRequestCredentialsRule, ACTIVE_RULES, + DEFAULT_PURPOSE_DECLARATION, enrichEidsRule, fetchBidsRule, getAcceptableFlags, getGvlid, getGvlidFromAnalyticsAdapter, + getPurposeDeclarations, + NO_PURPOSE_DECLARATION, reportAnalyticsRule, setEnforcementConfig, STRICT_STORAGE_ENFORCEMENT, @@ -28,7 +32,7 @@ import * as events from 'src/events.js'; import 'modules/appnexusBidAdapter.js'; // some tests expect this to be in the adapter registry import { requestBids } from 'src/prebid.js'; import { hook } from '../../../src/hook.js'; -import { GDPR_GVLIDS, VENDORLESS_GVLID } from '../../../src/consentHandler.js'; +import { GDPR_GVLIDS, GVL_PURPOSES, VENDORLESS_GVLID } from '../../../src/consentHandler.js'; import { activityParams } from '../../../src/activities/activityParams.js'; describe('gdpr enforcement', function () { @@ -150,8 +154,75 @@ describe('gdpr enforcement', function () { sandbox.restore(); }) + describe('getPurposeDeclarations', () => { + const GVL_ID = 123; + let origDecl, decl; + beforeEach(() => { + origDecl = GVL_PURPOSES[GVL_ID]; + delete GVL_PURPOSES[GVL_ID]; + decl = { + purposes: [1], + legIntPurposes: [2], + flexiblePurposes: [2], + specialFeatures: [3] + }; + }) + afterEach(() => { + GVL_PURPOSES[GVL_ID] = origDecl; + config.resetConfig(); + }) + it('should use data from GVL_PURPOSES', () => { + GVL_PURPOSES[GVL_ID] = decl; + expect(getPurposeDeclarations(GVL_ID)).to.eql(decl); + }); + it('should give precedence to gvlPurposeMapping', () => { + GVL_PURPOSES[GVL_ID] = decl; + config.setConfig({ + gvlPurposeMapping: { + [GVL_ID]: { + ...decl, + purposes: [1, 3] + } + } + }); + expect(getPurposeDeclarations(GVL_ID)).to.eql({ + ...decl, + purposes: [1, 3] + }) + }); + it('should provide defaults for gvlPurposeMapping', () => { + config.setConfig({ + gvlPurposeMapping: { + [GVL_ID]: { + purposes: [1] + } + } + }); + expect(getPurposeDeclarations(GVL_ID)).to.eql({ + purposes: [1], + legIntPurposes: [], + flexiblePurposes: [], + specialFeatures: [] + }) + }); + it('should fall back to allow (almost) anything when no declaration is available', () => { + expect(getPurposeDeclarations(GVL_ID)).to.eql(DEFAULT_PURPOSE_DECLARATION); + }); + it('should fall back to allow nothing when the declaration is invalid', () => { + config.setConfig({ + gvlPurposeMapping: { + [GVL_ID]: { + flexiblePurposes: [2] + } + } + }); + expect(getPurposeDeclarations(GVL_ID)).to.eql(NO_PURPOSE_DECLARATION) + }) + }); + describe('getAcceptableFlags', () => { let consentData; + beforeEach(() => { consentData = { vendorData: { @@ -162,66 +233,185 @@ describe('gdpr enforcement', function () { }; }); - describe('with no restrictions', () => { - it('should allow both consent and LI for purpose 2', () => { - expect(getAcceptableFlags({}, 2, 123)).to.eql({ + Object.entries({ + 'purpose accepts consent': { + type: 'purpose', + gvlid: 123, + purpose: 2, + declaration: { + purposes: [2], + legIntPurposes: [], + flexiblePurposes: [], + }, + expectation: { acceptConsent: true, - acceptLI: true - }) - }); - it('should allow only consent for other purposes', () => { - expect(getAcceptableFlags({}, 4, 123)).to.eql({ + acceptLI: false + } + }, + 'purpose accepts LI': { + type: 'purpose', + gvlid: 123, + purpose: 2, + declaration: { + purposes: [], + legIntPurposes: [2], + flexiblePurposes: [] + }, + expectation: { + acceptConsent: true, + acceptLI: true, + } + }, + 'purpose is flexible (default consent)': { + type: 'purpose', + gvlid: 123, + purpose: 2, + declaration: { + purposes: [2], + legIntPurposes: [], + flexiblePurposes: [2], + }, + expectation: { + acceptConsent: true, + acceptLI: true, + } + }, + 'purpose is flexible (default LI)': { + type: 'purpose', + gvlid: 123, + purpose: 2, + declaration: { + purposes: [], + legIntPurposes: [2], + flexiblePurposes: [2], + }, + expectation: { acceptConsent: true, + acceptLI: true, + } + }, + 'special feature is declared': { + type: 'feature', + gvlid: 123, + purpose: 2, + declaration: { + specialFeatures: [2] + }, + expectation: { + acceptConsent: true, + acceptLI: false, + } + }, + 'special feature is not declared': { + type: 'feature', + gvlid: 123, + purpose: 2, + declaration: { + specialFeatures: [] + }, + expectation: { + acceptConsent: false, acceptLI: false - }) - }) - }); - describe('with restrictions', () => { - [ - { - purpose: 2, - restriction: 0, - expectation: { - acceptConsent: false, - acceptLI: false - } + } + }, + 'vendorless gvlid, LI purpose': { + type: 'purpose', + gvlid: VENDORLESS_GVLID, + purpose: 2, + declaration: { + // should be ignored + legIntPurposes: [], + purposes: [], + flexiblePurposes: [] }, - { - purpose: 2, - restriction: 1, - expectation: { - acceptConsent: true, - acceptLI: false - } + expectation: { + acceptLI: true, + acceptConsent: true + } + }, + 'vendorless gvlid, non-LI purpose': { + type: 'purpose', + gvlid: VENDORLESS_GVLID, + purpose: 4, + declaration: { + // should be ignored + legIntPurposes: [], + purposes: [], + flexiblePurposes: [] }, - { - purpose: 2, - restriction: 2, - expectation: { - acceptConsent: false, - acceptLI: true - } + expectation: { + acceptLI: false, + acceptConsent: true + } + }, + 'vendorless gvlid, special feature': { + type: 'feature', + gvlid: VENDORLESS_GVLID, + purpose: 1, + declaration: { + // should be ignored + legIntPurposes: [], + purposes: [], + flexiblePurposes: [] }, - { - // require LI for a purpose where we don't allow LI - purpose: 4, - restriction: 2, - expectation: { - acceptConsent: false, - acceptLI: false - } + expectation: { + acceptLI: false, + acceptConsent: true } - ].forEach(({ purpose, restriction, expectation }) => { - it(`shold return ${JSON.stringify(expectation)} for purpose ${purpose} when restriction is ${restriction}`, () => { - consentData.vendorData.publisher.restrictions = { - [purpose]: { - 123: restriction - } - }; - expect(getAcceptableFlags(consentData, purpose, 123)).to.eql(expectation); - }) - }) - }) + } + }).forEach(([t, { gvlid, purpose, type, declaration, expectation }]) => { + describe(t, () => { + function getPurposes(id) { + if (id === gvlid) return declaration; + } + describe('with no restrictions', () => { + it(`should return acceptConsent=${expectation.acceptConsent}, acceptLI=${expectation.acceptLI}`, () => { + expect(getAcceptableFlags({}, type, purpose, gvlid, getPurposes)).to.eql({ + acceptConsent: expectation.acceptConsent, + acceptLI: expectation.acceptLI + }) + }); + }); + describe('with restrictions', () => { + [ + { + restriction: 0, + expectation: { + acceptConsent: false, + acceptLI: false, + } + }, + { + restriction: 1, + expectation: { + acceptConsent: expectation.acceptConsent, + acceptLI: false + } + }, + { + restriction: 2, + expectation: { + acceptConsent: false, + acceptLI: expectation.acceptLI + } + }, + ].forEach(({ restriction, expectation: newExpectation }) => { + describe(`restriction is ${restriction}`, () => { + const restrictedExpectation = type === 'feature' ? expectation : newExpectation; + + it(`shold return ${JSON.stringify(restrictedExpectation)}`, () => { + consentData.vendorData.publisher.restrictions = { + [purpose]: { + [gvlid]: restriction + } + }; + expect(getAcceptableFlags(consentData, type, purpose, gvlid, getPurposes)).to.eql(restrictedExpectation); + }); + }); + }); + }); + }); + }); }); Object.entries({ @@ -654,6 +844,20 @@ describe('gdpr enforcement', function () { const LI_PURPOSES = [2]; const CONSENT_TYPES = ['consents', 'legitimateInterests']; + beforeEach(() => { + config.setConfig({ + gvlPurposeMapping: { + [GVL_ID]: { + purposes: LI_PURPOSES.concat(CS_PURPOSES), + flexiblePurposes: LI_PURPOSES + } + } + }) + }) + afterEach(() => { + config.resetConfig(); + }) + describe('should deny if', () => { describe('config is default', () => { beforeEach(() => { From f9ee3c5e70242c3e301f224f9d8513f326fbb481 Mon Sep 17 00:00:00 2001 From: Vuukle Date: Wed, 3 Jun 2026 14:51:06 +0100 Subject: [PATCH 036/124] New Adapter: Vuukle Bid Adapter (banner, video, native) (#14981) --- modules/vuukleBidAdapter.d.ts | 20 ++ modules/vuukleBidAdapter.js | 224 +++++++----- modules/vuukleBidAdapter.md | 100 +++++- test/spec/modules/vuukleBidAdapter_spec.js | 383 ++++++++++++++------- 4 files changed, 509 insertions(+), 218 deletions(-) create mode 100644 modules/vuukleBidAdapter.d.ts diff --git a/modules/vuukleBidAdapter.d.ts b/modules/vuukleBidAdapter.d.ts new file mode 100644 index 00000000000..9ce3e083832 --- /dev/null +++ b/modules/vuukleBidAdapter.d.ts @@ -0,0 +1,20 @@ +export interface VuukleBidderParams { + /** + * Your Vuukle seller ID, as listed in https://vuukle.com/sellers.json. Required. + */ + sid: string; + /** + * Optional named placement / tag ID. Falls back to the ad unit code when omitted. + */ + placementId?: string; + /** + * Optional static hard floor in USD. The priceFloors module is preferred when configured. + */ + bidfloor?: number; +} + +declare module '../src/adUnits' { + interface BidderParams { + vuukle: VuukleBidderParams; + } +} diff --git a/modules/vuukleBidAdapter.js b/modules/vuukleBidAdapter.js index 371cf002473..d90078956be 100644 --- a/modules/vuukleBidAdapter.js +++ b/modules/vuukleBidAdapter.js @@ -1,98 +1,162 @@ -import { parseSizesInput, deepAccess } from '../src/utils.js'; import { registerBidder } from '../src/adapters/bidderFactory.js'; -import { BANNER } from '../src/mediaTypes.js'; -import { config } from '../src/config.js'; +import { BANNER, VIDEO, NATIVE } from '../src/mediaTypes.js'; +import { ortbConverter } from '../libraries/ortbConverter/converter.js'; +import { Renderer } from '../src/Renderer.js'; +import { deepAccess, deepSetValue, logError, logWarn } from '../src/utils.js'; + +/** + * @typedef {import('../src/adapters/bidderFactory.js').BidRequest} BidRequest + * @typedef {import('./vuukleBidAdapter.d.ts').VuukleBidderParams} VuukleBidderParams + * @typedef {BidRequest & { params: VuukleBidderParams }} VuukleBidRequest + */ const BIDDER_CODE = 'vuukle'; -const URL = 'https://pb.vuukle.com/adapter'; -const TIME_TO_LIVE = 360; -const VENDOR_ID = 1004; +const GVLID = 1004; +const ENDPOINT = 'https://rtb.vuukle.com/openrtb2/web'; +const SYNC_URL = 'https://rtb.vuukle.com/cookie-sync'; +const DEFAULT_TTL = 300; +// Hosted outstream renderer (Vuukle-served). Publishers may override by +// supplying their own renderer on the ad unit. +const OUTSTREAM_RENDERER_URL = 'https://rtb.vuukle.com/static/outstream.js'; -export const spec = { - code: BIDDER_CODE, - gvlid: VENDOR_ID, - supportedMediaTypes: [BANNER], +const converter = ortbConverter({ + context: { netRevenue: true, ttl: DEFAULT_TTL, currency: 'USD' }, - isBidRequestValid: function(bid) { - return true + imp(buildImp, bidRequest, context) { + const imp = buildImp(bidRequest, context); + // tagid: explicit placement, else the ad unit code. + imp.tagid = bidRequest.params.placementId || bidRequest.adUnitCode; + // GPID passthrough (helps DSP targeting / dedup). + const gpid = deepAccess(bidRequest, 'ortb2Imp.ext.gpid'); + if (gpid) deepSetValue(imp, 'ext.gpid', gpid); + // priceFloors (getFloor) is wired by ortbConverter automatically; if it + // didn't set a floor, fall back to the static params.bidfloor (USD). + if (imp.bidfloor == null && bidRequest.params.bidfloor != null) { + const f = parseFloat(bidRequest.params.bidfloor); + if (!isNaN(f)) { + imp.bidfloor = f; + imp.bidfloorcur = imp.bidfloorcur || 'USD'; + } + } + return imp; }, - buildRequests: function(bidRequests, bidderRequest) { - bidderRequest = bidderRequest || {}; - const requests = bidRequests.map(function (bid) { - const parseSized = parseSizesInput(bid.sizes); - const arrSize = parseSized[0].split('x'); - const params = { - url: encodeURIComponent(window.location.href), - sizes: JSON.stringify(parseSized), - width: arrSize[0], - height: arrSize[1], - params: JSON.stringify(bid.params), - rnd: Math.random(), - bidId: bid.bidId, - source: 'pbjs', - schain: JSON.stringify(bid?.ortb2?.source?.ext?.schain), - requestId: bid.bidderRequestId, - tmax: bidderRequest.timeout, - gdpr: (bidderRequest.gdprConsent && bidderRequest.gdprConsent.gdprApplies) ? 1 : 0, - consentGiven: vuukleGetConsentGiven(bidderRequest.gdprConsent), - version: '$prebid.version$', - v: 2, - }; + request(buildRequest, imps, bidderRequest, context) { + const req = buildRequest(imps, bidderRequest, context); + // sellers.json seller_id is our universal publisher key — set it as the + // oRTB site.publisher.id so demand can verify the supply chain. + const sid = context.bidRequests && context.bidRequests[0] && context.bidRequests[0].params.sid; + if (sid) deepSetValue(req, 'site.publisher.id', String(sid)); + deepSetValue(req, 'ext.prebid.channel', { name: 'pbjs', version: '$prebid.version$' }); + // ortbConverter already populates: imp.banner/imp.video, sizes, floors, + // user.eids, source.schain, regs (gdpr/usp/gpp/coppa), site/device/user + // first-party data from ortb2 — so we keep this thin on purpose. + return req; + }, - if (bidderRequest.uspConsent) { - params.uspConsent = bidderRequest.uspConsent; - } + bidResponse(buildBidResponse, bid, context) { + const bidResponse = buildBidResponse(bid, context); + const req = context.bidRequest; + // Attach our outstream renderer only for outstream video when the + // publisher hasn't supplied their own. + if ( + bidResponse.mediaType === VIDEO && + deepAccess(req, 'mediaTypes.video.context') === 'outstream' && + !deepAccess(req, 'renderer') && + !deepAccess(req, 'mediaTypes.video.renderer') + ) { + const rUrl = deepAccess(bid, 'ext.renderer_url') || deepAccess(bid, 'ext.prebid.cache.vastXml.renderer') || OUTSTREAM_RENDERER_URL; + bidResponse.renderer = createRenderer(bidResponse, rUrl); + } + return bidResponse; + }, +}); - if (config.getConfig('coppa') === true) { - params.coppa = 1; - } +function createRenderer(bid, rendererUrl) { + const renderer = Renderer.install({ + id: bid.requestId, + url: rendererUrl || OUTSTREAM_RENDERER_URL, + adUnitCode: bid.adUnitCode, + }); + try { + renderer.setRender((b) => { + b.renderer.push(() => { + if (window.vuukleOutstream && typeof window.vuukleOutstream.render === 'function') { + window.vuukleOutstream.render({ + adUnitCode: b.adUnitCode, + vastXml: b.vastXml, + vastUrl: b.vastUrl, + width: b.width, + height: b.height, + }); + } else { + logWarn('vuukle: outstream renderer not loaded'); + } + }); + }); + } catch (e) { + logWarn('vuukle: failed to set renderer', e); + } + return renderer; +} - if (bidderRequest.gdprConsent && bidderRequest.gdprConsent.consentString) { - params.consent = bidderRequest.gdprConsent.consentString; - } +export const spec = { + code: BIDDER_CODE, + gvlid: GVLID, + supportedMediaTypes: [BANNER, VIDEO, NATIVE], - return { - method: 'GET', - url: URL, - data: params, - options: { withCredentials: false } + isBidRequestValid(bid) { + if (!bid || !bid.params || !bid.params.sid) { + logError('vuukle: params.sid (your sellers.json seller_id) is required'); + return false; + } + const video = deepAccess(bid, 'mediaTypes.video'); + if (video) { + if (!Array.isArray(video.mimes) || video.mimes.length === 0) { + logError('vuukle: mediaTypes.video.mimes is required for video'); + return false; } - }); - - return requests; + if (!video.playerSize && !bid.sizes) { + logError('vuukle: video playerSize is required'); + return false; + } + } + return true; }, - interpretResponse: function(serverResponse, bidRequest) { - if (!serverResponse || !serverResponse.body || !serverResponse.body.ad) { - return []; - } + buildRequests(bidRequests, bidderRequest) { + const data = converter.toORTB({ bidRequests, bidderRequest }); + return [{ + method: 'POST', + url: ENDPOINT, + data, + options: { withCredentials: true }, + }]; + }, - const res = serverResponse.body; - const bidResponse = { - requestId: bidRequest.data.bidId, - cpm: res.cpm, - width: res.width, - height: res.height, - creativeId: res.creative_id, - currency: res.currency || 'USD', - netRevenue: true, - ttl: TIME_TO_LIVE, - ad: res.ad, - meta: { - advertiserDomains: Array.isArray(res.adomain) ? res.adomain : [] - } - }; + interpretResponse(response, request) { + if (!response || !response.body || !response.body.seatbid) return []; + return converter.fromORTB({ response: response.body, request: request.data }).bids; + }, - return [bidResponse]; + getUserSyncs(syncOptions, serverResponses, gdprConsent, uspConsent, gppConsent) { + if (!syncOptions.iframeEnabled && !syncOptions.pixelEnabled) return []; + const params = []; + if (gdprConsent) { + params.push('gdpr=' + (gdprConsent.gdprApplies ? 1 : 0)); + params.push('gdpr_consent=' + encodeURIComponent(gdprConsent.consentString || '')); + } + if (uspConsent) params.push('us_privacy=' + encodeURIComponent(uspConsent)); + if (gppConsent && gppConsent.gppString) { + params.push('gpp=' + encodeURIComponent(gppConsent.gppString)); + params.push('gpp_sid=' + encodeURIComponent((gppConsent.applicableSections || []).join(','))); + } + const qs = params.length ? ('?' + params.join('&')) : ''; + if (syncOptions.iframeEnabled) { + return [{ type: 'iframe', url: SYNC_URL + '/iframe' + qs }]; + } + return [{ type: 'image', url: SYNC_URL + '/pixel' + qs }]; }, -} -registerBidder(spec); +}; -function vuukleGetConsentGiven(gdprConsent) { - let consentGiven = 0; - if (typeof gdprConsent !== 'undefined') { - consentGiven = deepAccess(gdprConsent, `vendorData.vendor.consents.${VENDOR_ID}`) ? 1 : 0; - } - return consentGiven; -} +registerBidder(spec); diff --git a/modules/vuukleBidAdapter.md b/modules/vuukleBidAdapter.md index ee7b54c6262..305802d5cff 100644 --- a/modules/vuukleBidAdapter.md +++ b/modules/vuukleBidAdapter.md @@ -1,26 +1,92 @@ -# Overview +--- +layout: bidder +title: Vuukle +description: Prebid Vuukle Bidder Adapter +biddercode: vuukle +tcfeu_supported: true +usp_supported: true +gpp_supported: true +schain_supported: true +userId: all +media_types: banner, video, native +gvl_id: 1004 +safeframes_ok: true +floors_supported: true +pbjs: true +pbs: false +--- + +### Overview + ``` Module Name: Vuukle Bid Adapter Module Type: Bidder Adapter Maintainer: support@vuukle.com ``` -# Description -Module that connects to Vuukle's server for bids. -Currently module supports only banner mediaType. +### Description + +The Vuukle Bid Adapter connects Prebid.js to the Vuukle SSP for **banner**, **native** and +**video** (instream and outstream) demand. It is built on Prebid's +`ortbConverter`, so it automatically forwards standard OpenRTB signals — sizes, +price floors (priceFloors module), user IDs (`eids`), supply chain (`schain`), +and consent (TCF EU, US Privacy, GPP, COPPA, DSA) — derived from the ad unit and +`ortb2`. For outstream video, the adapter installs a Vuukle-hosted renderer +unless the publisher supplies their own. + +### Bid Params + +{: .table .table-bordered .table-striped } +| Name | Scope | Description | Example | Type | +|---------------|----------|-----------------------------------------------------------------------------|------------------------|----------| +| `sid` | required | Your Vuukle seller ID, as listed in [vuukle.com/sellers.json](https://vuukle.com/sellers.json). | `'vuukle-12345'` | `string` | +| `placementId` | optional | A named placement/tag ID. Falls back to the ad unit code if omitted. | `'homepage-atf'` | `string` | +| `bidfloor` | optional | Hard floor (USD). The priceFloors module is preferred when configured. | `1.50` | `number` | + +**Required:** `sid` is required on every request. For **video**, `mediaTypes.video` must include `context`, `playerSize`, and `mimes`. -# Test Parameters +### Test Parameters — Banner + +```javascript +var adUnits = [{ + code: 'test-banner', + mediaTypes: { + banner: { sizes: [[300, 250], [728, 90]] } + }, + bids: [{ + bidder: 'vuukle', + params: { sid: 'vuukle-test' } + }] +}]; ``` - var adUnits = [{ - code: '/test/div', - mediaTypes: { - banner: { - sizes: [[300, 250]] - } - }, - bids: [{ - bidder: 'vuukle', - params: {} - }] - }]; + +### Test Parameters — Video (outstream) + +```javascript +var adUnits = [{ + code: 'test-video', + mediaTypes: { + video: { + context: 'outstream', + playerSize: [640, 480], + mimes: ['video/mp4'], + protocols: [2, 3, 5, 6], + api: [2], + plcmt: 4 + } + }, + bids: [{ + bidder: 'vuukle', + params: { sid: 'vuukle-test' } + }] +}]; ``` + +### Notes + +- **First-party data, floors, eids, schain and consent** are handled by + `ortbConverter` automatically from the ad unit and `ortb2` — no extra params + required. +- **User sync**: the adapter supports both iframe and image (pixel) syncs, + gated by the publisher's `userSync` configuration and forwarded consent. +- Bid responses are net revenue; default TTL is 300s. diff --git a/test/spec/modules/vuukleBidAdapter_spec.js b/test/spec/modules/vuukleBidAdapter_spec.js index fe081becc09..b6b7f2d0aa9 100644 --- a/test/spec/modules/vuukleBidAdapter_spec.js +++ b/test/spec/modules/vuukleBidAdapter_spec.js @@ -1,148 +1,289 @@ import { expect } from 'chai'; import { spec } from 'modules/vuukleBidAdapter.js'; -import { config } from '../../../src/config.js'; - -describe('vuukleBidAdapterTests', function() { - const bidRequestData = { - bids: [ - { - bidId: 'testbid', - bidder: 'vuukle', - params: { - test: 1 - }, - sizes: [[300, 250]] - } - ] +import { BANNER, VIDEO, NATIVE } from 'src/mediaTypes.js'; +import { config } from 'src/config.js'; + +const ENDPOINT = 'https://rtb.vuukle.com/openrtb2/web'; + +function bannerBid(params = { sid: 'vuukle-test' }) { + return { + bidder: 'vuukle', + bidId: 'bid-banner-1', + adUnitCode: 'div-banner', + transactionId: 'tx-1', + auctionId: 'auc-1', + params, + mediaTypes: { banner: { sizes: [[300, 250], [728, 90]] } }, + ortb2Imp: { ext: { gpid: '/1234/home#div-banner' } }, }; - let request = []; - - it('validate_pub_params', function() { - expect( - spec.isBidRequestValid({ - bidder: 'vuukle', - params: { - test: 1 - } - }) - ).to.equal(true); - }); +} - it('validate_generated_params', function() { - request = spec.buildRequests(bidRequestData.bids); - const req_data = request[0].data; +function videoBid(context = 'outstream', params = { sid: 'vuukle-test' }) { + return { + bidder: 'vuukle', + bidId: 'bid-video-1', + adUnitCode: 'div-video', + transactionId: 'tx-2', + auctionId: 'auc-1', + params, + mediaTypes: { + video: { + context, + playerSize: [[640, 480]], + mimes: ['video/mp4'], + protocols: [2, 3, 5, 6], + api: [2], + plcmt: context === 'instream' ? 1 : 4, + }, + }, + }; +} - expect(req_data.bidId).to.equal('testbid'); - }); +function nativeBid(params = { sid: 'vuukle-test' }) { + return { + bidder: 'vuukle', + bidId: 'bid-native-1', + adUnitCode: 'div-native', + transactionId: 'tx-3', + auctionId: 'auc-1', + params, + mediaTypes: { + native: { + ortb: { + assets: [ + { id: 1, required: 1, title: { len: 80 } }, + { id: 2, required: 1, img: { type: 3, w: 300, h: 250 } }, + ], + }, + }, + }, + }; +} - it('validate_generated_params_tmax', function() { - request = spec.buildRequests(bidRequestData.bids, { timeout: 1234 }); - const req_data = request[0].data; +function bidderRequest(bids) { + return { + bidderCode: 'vuukle', + bidderRequestId: 'breq-1', + auctionId: 'auc-1', + timeout: 1000, + refererInfo: { page: 'https://example.com/article', domain: 'example.com', ref: '' }, + ortb2: { site: { domain: 'example.com', page: 'https://example.com/article' } }, + bids, + }; +} - expect(req_data.tmax).to.equal(1234); +describe('vuukleBidAdapter', function () { + describe('isBidRequestValid', function () { + it('accepts a valid banner bid', function () { + expect(spec.isBidRequestValid(bannerBid())).to.equal(true); + }); + it('rejects when params missing', function () { + const b = bannerBid(); delete b.params; + expect(spec.isBidRequestValid(b)).to.equal(false); + }); + it('rejects when sid missing', function () { + expect(spec.isBidRequestValid(bannerBid({}))).to.equal(false); + }); + it('accepts a valid video bid', function () { + expect(spec.isBidRequestValid(videoBid())).to.equal(true); + }); + it('rejects video without mimes', function () { + const b = videoBid(); b.mediaTypes.video.mimes = []; + expect(spec.isBidRequestValid(b)).to.equal(false); + }); + it('rejects video without playerSize', function () { + const b = videoBid(); delete b.mediaTypes.video.playerSize; delete b.sizes; + expect(spec.isBidRequestValid(b)).to.equal(false); + }); + it('accepts a valid native bid', function () { + expect(spec.isBidRequestValid(nativeBid())).to.equal(true); + }); }); - it('validate_response_params', function() { - const serverResponse = { - body: { - 'cpm': 0.01, - 'width': 300, - 'height': 250, - 'creative_id': '12345', - 'ad': 'test ad', - 'adomain': ['example.com'] - } - }; - - request = spec.buildRequests(bidRequestData.bids); - const bids = spec.interpretResponse(serverResponse, request[0]); - expect(bids).to.have.lengthOf(1); - - const bid = bids[0]; - expect(bid.ad).to.equal('test ad'); - expect(bid.cpm).to.equal(0.01); - expect(bid.width).to.equal(300); - expect(bid.height).to.equal(250); - expect(bid.creativeId).to.equal('12345'); - expect(bid.meta.advertiserDomains).to.deep.equal(['example.com']); + describe('spec metadata', function () { + it('has the right code, gvlid and media types', function () { + expect(spec.code).to.equal('vuukle'); + expect(spec.gvlid).to.equal(1004); + expect(spec.supportedMediaTypes).to.include.members([BANNER, VIDEO, NATIVE]); + }); }); - describe('consent handling', function() { - const bidderRequest = { - gdprConsent: { - consentString: 'COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw', - gdprApplies: 1, - vendorData: { - vendor: { - consents: { - 1004: 1 - } - } - } - } - } - - it('must handle consent 1/1', function() { - request = spec.buildRequests(bidRequestData.bids, bidderRequest); - const req_data = request[0].data; + describe('buildRequests', function () { + it('builds a single POST request to the endpoint with credentials', function () { + const bids = [bannerBid()]; + const reqs = spec.buildRequests(bids, bidderRequest(bids)); + expect(reqs).to.have.lengthOf(1); + expect(reqs[0].method).to.equal('POST'); + expect(reqs[0].url).to.equal(ENDPOINT); + expect(reqs[0].options.withCredentials).to.equal(true); + }); - expect(req_data.gdpr).to.equal(1); - expect(req_data.consentGiven).to.equal(1); - expect(req_data.consent).to.equal('COvFyGBOvFyGBAbAAAENAPCAAOAAAAAAAAAAAEEUACCKAAA.IFoEUQQgAIQwgIwQABAEAAAAOIAACAIAAAAQAIAgEAACEAAAAAgAQBAAAAAAAGBAAgAAAAAAAFAAECAAAgAAQARAEQAAAAAJAAIAAgAAAYQEAAAQmAgBC3ZAYzUw'); - }) + it('produces a valid oRTB body with imp + site.publisher.id = sid', function () { + const bids = [bannerBid({ sid: 'vuukle-abc' })]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data).to.be.an('object'); + expect(data.imp).to.be.an('array').with.lengthOf(1); + expect(data.site.publisher.id).to.equal('vuukle-abc'); + }); - it('must handle consent 0/1', function() { - bidderRequest.gdprConsent.gdprApplies = 0; - request = spec.buildRequests(bidRequestData.bids, bidderRequest); - const req_data = request[0].data; + it('sets a banner imp with format and tagid from adUnitCode', function () { + const bids = [bannerBid()]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data.imp[0].banner).to.exist; + expect(data.imp[0].banner.format).to.be.an('array'); + expect(data.imp[0].tagid).to.equal('div-banner'); + expect(data.imp[0].ext.gpid).to.equal('/1234/home#div-banner'); + }); - expect(req_data.gdpr).to.equal(0); - expect(req_data.consentGiven).to.equal(1); - }) + it('uses placementId as tagid when provided', function () { + const bids = [bannerBid({ sid: 'vuukle-test', placementId: 'home-atf' })]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data.imp[0].tagid).to.equal('home-atf'); + }); - it('must handle consent 0/0', function() { - bidderRequest.gdprConsent.gdprApplies = 0; - bidderRequest.gdprConsent.vendorData = undefined; - request = spec.buildRequests(bidRequestData.bids, bidderRequest); - const req_data = request[0].data; + it('forwards params.bidfloor to imp.bidfloor', function () { + const bids = [bannerBid({ sid: 'vuukle-test', bidfloor: 1.75 })]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data.imp[0].bidfloor).to.equal(1.75); + expect(data.imp[0].bidfloorcur).to.equal('USD'); + }); - expect(req_data.gdpr).to.equal(0); - expect(req_data.consentGiven).to.equal(0); - }) + it('builds a request for a video bid', function () { + const bids = [videoBid('instream')]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data.imp).to.have.lengthOf(1); + }); - it('must handle consent undef', function() { - request = spec.buildRequests(bidRequestData.bids, {}); - const req_data = request[0].data; + it('builds a request for a native bid', function () { + const bids = [nativeBid()]; + const { data } = spec.buildRequests(bids, bidderRequest(bids))[0]; + expect(data.imp).to.have.lengthOf(1); + }); - expect(req_data.gdpr).to.equal(0); - expect(req_data.consentGiven).to.equal(0); - }) - }) + it('forwards user eids', function () { + const bid = bannerBid(); + const eids = [{ source: 'id5.io', uids: [{ id: 'ID5-1', atype: 1 }] }]; + bid.userIdAsEids = eids; + const bids = [bid]; + const breq = bidderRequest(bids); + breq.ortb2 = { ...breq.ortb2, user: { ext: { eids } } }; + const { data } = spec.buildRequests(bids, breq)[0]; + expect(data.user.ext.eids).to.deep.equal(eids); + }); - it('must handle usp consent', function() { - request = spec.buildRequests(bidRequestData.bids, { uspConsent: '1YNN' }); - const req_data = request[0].data; + it('forwards supply chain (schain)', function () { + const schain = { complete: 1, ver: '1.0', nodes: [{ asi: 'vuukle.com', sid: 'vuukle-test', hp: 1 }] }; + const bids = [bannerBid()]; + const breq = bidderRequest(bids); + breq.ortb2 = { ...breq.ortb2, source: { ext: { schain } } }; + const { data } = spec.buildRequests(bids, breq)[0]; + const sc = (data.source && (data.source.schain || (data.source.ext && data.source.ext.schain))); + expect(sc).to.deep.equal(schain); + }); + }); - expect(req_data.uspConsent).to.equal('1YNN'); - }) + describe('interpretResponse', function () { + function build(bids) { + return spec.buildRequests(bids, bidderRequest(bids))[0]; + } - it('must handle undefined usp consent', function() { - request = spec.buildRequests(bidRequestData.bids, {}); - const req_data = request[0].data; + it('returns [] on empty body', function () { + expect(spec.interpretResponse({ body: null }, {})).to.deep.equal([]); + }); - expect(req_data.uspConsent).to.equal(undefined); - }) + it('returns [] when no seatbid', function () { + expect(spec.interpretResponse({ body: { id: 'x' } }, {})).to.deep.equal([]); + }); - it('must handle coppa flag', function() { - sinon.stub(config, 'getConfig') - .withArgs('coppa') - .returns(true); + it('parses a banner bid', function () { + const bids = [bannerBid()]; + const request = build(bids); + const response = { + body: { + id: 'breq-1', + cur: 'USD', + seatbid: [{ + seat: 'pubmatic', + bid: [{ + impid: 'bid-banner-1', + price: 3.21, + crid: 'cr-9', + adomain: ['acme.com'], + w: 300, + h: 250, + adm: '

ad
', + mtype: 1 + }] + }] + } + }; + const out = spec.interpretResponse(response, request); + expect(out).to.have.lengthOf(1); + expect(out[0].cpm).to.equal(3.21); + expect(out[0].creativeId).to.equal('cr-9'); + expect(out[0].width).to.equal(300); + expect(out[0].height).to.equal(250); + expect(out[0].mediaType).to.equal(BANNER); + expect(out[0].meta.advertiserDomains).to.deep.equal(['acme.com']); + }); - request = spec.buildRequests(bidRequestData.bids); - const req_data = request[0].data; + it('parses an outstream video bid and attaches a renderer', function () { + const bids = [videoBid('outstream')]; + const request = build(bids); + const response = { + body: { + id: 'breq-1', + cur: 'USD', + seatbid: [{ + seat: 'unruly', + bid: [{ + impid: 'bid-video-1', + price: 8.5, + crid: 'v-1', + adomain: ['brand.com'], + w: 640, + h: 480, + adm: '', + mtype: 2 + }] + }] + } + }; + const out = spec.interpretResponse(response, request); + expect(out).to.have.lengthOf(1); + expect(out[0].mediaType).to.equal(VIDEO); + expect(out[0].renderer).to.exist; + }); + }); - expect(req_data.coppa).to.equal(1); + describe('getUserSyncs', function () { + it('returns [] when neither iframe nor pixel is enabled', function () { + expect(spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: false }, [])).to.deep.equal([]); + }); + it('returns an iframe sync when iframe is enabled', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: true, pixelEnabled: true }, []); + expect(syncs).to.have.lengthOf(1); + expect(syncs[0].type).to.equal('iframe'); + }); + it('returns a pixel sync when only pixel is enabled', function () { + const syncs = spec.getUserSyncs({ iframeEnabled: false, pixelEnabled: true }, []); + expect(syncs[0].type).to.equal('image'); + }); + it('forwards consent params (gdpr, usp, gpp)', function () { + const syncs = spec.getUserSyncs( + { iframeEnabled: true }, + [], + { gdprApplies: true, consentString: 'CONSENT' }, + '1YNN', + { gppString: 'GPP', applicableSections: [7, 8] }, + ); + expect(syncs[0].url).to.contain('gdpr=1'); + expect(syncs[0].url).to.contain('gdpr_consent=CONSENT'); + expect(syncs[0].url).to.contain('us_privacy=1YNN'); + expect(syncs[0].url).to.contain('gpp=GPP'); + expect(syncs[0].url).to.contain('gpp_sid=7%2C8'); + }); + }); - config.getConfig.restore(); - }) + afterEach(function () { config.resetConfig(); }); }); From 17c6d602679baa358696694df9a7cc6b67ef91a7 Mon Sep 17 00:00:00 2001 From: Patrick McCann Date: Wed, 3 Jun 2026 09:51:41 -0400 Subject: [PATCH 037/124] Build: remove unused @wdio/concise-reporter dev dependency (#14956) --- package-lock.json | 86 ----------------------------------------------- package.json | 1 - 2 files changed, 87 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5abe85300f5..84797c7521b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -35,7 +35,6 @@ "@types/google-publisher-tag": "^1.20250210.0", "@wdio/browserstack-service": "^9.19.1", "@wdio/cli": "^9.19.1", - "@wdio/concise-reporter": "^8.29.0", "@wdio/local-runner": "^9.15.0", "@wdio/mocha-framework": "^9.12.6", "@wdio/spec-reporter": "^8.43.0", @@ -5730,31 +5729,6 @@ "node": ">=12" } }, - "node_modules/@wdio/concise-reporter": { - "version": "8.38.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@wdio/reporter": "8.38.2", - "@wdio/types": "8.38.2", - "chalk": "^5.0.1", - "pretty-ms": "^7.0.1" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, - "node_modules/@wdio/concise-reporter/node_modules/chalk": { - "version": "5.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/@wdio/config": { "version": "9.15.0", "dev": true, @@ -6720,21 +6694,6 @@ "node": ">=18.20.0" } }, - "node_modules/@wdio/reporter": { - "version": "8.38.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^20.1.0", - "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "diff": "^5.0.0", - "object-inspect": "^1.12.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, "node_modules/@wdio/runner": { "version": "9.15.0", "dev": true, @@ -7070,17 +7029,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@wdio/types": { - "version": "8.38.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "^20.1.0" - }, - "engines": { - "node": "^16.13 || >=18" - } - }, "node_modules/@wdio/utils": { "version": "9.12.6", "dev": true, @@ -26561,22 +26509,6 @@ } } }, - "@wdio/concise-reporter": { - "version": "8.38.2", - "dev": true, - "requires": { - "@wdio/reporter": "8.38.2", - "@wdio/types": "8.38.2", - "chalk": "^5.0.1", - "pretty-ms": "^7.0.1" - }, - "dependencies": { - "chalk": { - "version": "5.3.0", - "dev": true - } - } - }, "@wdio/config": { "version": "9.15.0", "dev": true, @@ -27227,17 +27159,6 @@ "@types/node": "^20.1.0" } }, - "@wdio/reporter": { - "version": "8.38.2", - "dev": true, - "requires": { - "@types/node": "^20.1.0", - "@wdio/logger": "8.38.0", - "@wdio/types": "8.38.2", - "diff": "^5.0.0", - "object-inspect": "^1.12.0" - } - }, "@wdio/runner": { "version": "9.15.0", "dev": true, @@ -27465,13 +27386,6 @@ } } }, - "@wdio/types": { - "version": "8.38.2", - "dev": true, - "requires": { - "@types/node": "^20.1.0" - } - }, "@wdio/utils": { "version": "9.12.6", "dev": true, diff --git a/package.json b/package.json index 57a30f5d0ae..2456e3a4c79 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,6 @@ "@types/google-publisher-tag": "^1.20250210.0", "@wdio/browserstack-service": "^9.19.1", "@wdio/cli": "^9.19.1", - "@wdio/concise-reporter": "^8.29.0", "@wdio/local-runner": "^9.15.0", "@wdio/mocha-framework": "^9.12.6", "@wdio/spec-reporter": "^8.43.0", From 522f7ed66d8a48ad14609fcff02b7985b6d0da6f Mon Sep 17 00:00:00 2001 From: oleksandrhn-code Date: Wed, 3 Jun 2026 16:53:39 +0300 Subject: [PATCH 038/124] IntentIq ID Module & Analytical Adapter: A/B percentage passing, CMP consent improvements (#14936) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * AGT-817 Group change for module (#70) Co-authored-by: Alex * AGT-843 Module documentation (#71) Co-authored-by: Alex * AGT-751 AB% passing * Merge master into 0.36 (#75) * Remove gvlid from movingup bid adapter (#14749) * billow_rtb25: New adapter (#14690) * New adapter: billow_rtb25 * delete options * add public interface * Change the adapter type to a ts file --------- Co-authored-by: zepeng.yin * Prebid 11.7.0 release * Increment version to 11.8.0-pre * Showheroes Bid Adapter: rename showheroes bid adapter (#14644) * rename showheroes bid adapter * Showheroes: bring back old adapter * Impactify Bid Adapter: ensure compatible mediaType mapping (#14748) * Updated bid adapter to log errors * Remove onBidderError function and LOGGER_JS_URI Removed unused onBidderError function and LOGGER_JS_URI constant. * Apply suggestion from @Copilot Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Fix mediatypes * Add banner test * Add mediaType fallbacks --------- Co-authored-by: Filipe Neves Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * CriteoBidAdapter: Fix outstream video (#14753) * Update: Adding Device hardware version (hwv) in the adapter (#14757) * wurfl rtd: collect SUA via src/fpd/sua.js for high-entropy hints (#14758) Switch the SUA source from the bid request to direct calls to getHighEntropySUA from src/fpd/sua.js. This ensures wurfl.js and the analytics beacon receive high-entropy User-Agent Client Hints. Falls back to low-entropy SUA when high-entropy is unavailable (non-Chromium browsers, restrictive Permissions Policy). Refs prebid/Prebid.js#14574 * Msft Bid Adapter - Native request example in md updated to include eventtrackers (#14760) * Update msftBidAdapter.md * Minor update to the keyword format * Minor update to the keyword format * Update msftBidAdapter.md --------- Co-authored-by: Jason Crane * Intenze Adapter: Europe support (#14658) * Intenze Adapter: Europe support * fix lint problem in intenzeBidAdapter.js * Bid Filter Module: Add option for bidResponseFilter handling for in-banner video on multi-format (#14542) * Add option for bidResponseFilter handling for in-banner video on multi-format * Format code for consistency in bidResponseFilter_spec.js --------- Co-authored-by: Patrick McCann Co-authored-by: Patrick McCann * Core: fix typos in reducers comments (#14768) * IntimateMerger Analytics Adapter : initial release (#14726) * IntimateMerger Analytics Adapter : initial release * IntimateMerger Analytics Adapter : fix event overlap * IntimateMerger Analytics Adapter : refactoring * IntimateMerger Analytics Adapter : Update modules/imAnalyticsAdapter.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * IntimateMerger Analytics Adapter : Update waitTimeout Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * IntimateMerger Analytics Adapter : Update modules/imAnalyticsAdapter.js docs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * IntimateMerger Analytics Adapter : Update docs * IntimateMerger Analytics Adapter : cid optional --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Adquery Bid Adapter: userID usage refactor (#14692) * adquery_video_work9 * adquery_video_work9 * adquery_video_work9 * update onBidWon --------- Co-authored-by: Adrian Dzida * New Bidder: PGAM Direct (#14763) * Add PGAM Direct bid adapter New SSP bidder (server-to-server, canonical OpenRTB 2.6) operated by PGAM Media LLC. Distinct from pgamssp (our legacy TeqBlaze-hosted adapter); we plan to migrate publishers from pgamssp to pgamdirect over 2026 and will submit a deprecation PR for pgamssp once migration completes. Both are actively maintained. GVL ID: 1353 Endpoint: https://rtb.pgammedia.com/rtb/v1/auction Media types: banner, video, native Supports: schain, TCF v2, USP, GPP, COPPA, EIDs, GPID, floors module, deals, first-party data 37 spec cases covering isBidRequestValid, buildRequests across banner video and native, multi-imp, consent forwarding for GDPR/USP/GPP/COPPA, EIDs and schain passthrough, interpretResponse across all media types including VAST XML/URL variants and native JSON parsing, malformed- input rejection, ext.meta merge, and metadata assertions. Coverage: 100% functions, 100% lines, 82% branches. * pgamdirect: address Codex review Three P1s from the Codex automated review: 1. Floors module integration — imp.bidfloor now comes from bid.getFloor() when the Floors module is enabled, falling back to params.bidfloor and then 0. Currency is carried from the Floors-returned currency, not hard-coded to USD. Resolves the regression where publishers on floor rules were silently sending their static params.bidfloor. 2. schain lookup precedence — buildSource() now reads ortb2.source.ext.schain first (the modern FPD path), falling back to the legacy bid.schain. Resolves the drop for publishers who configure schain through FPD rather than per-bidder params. 3. CORS preflight — removed the x-openrtb-version custom header. The request is now CORS-simple enough to avoid a browser preflight on every auction, reducing perceived auction latency by one RTT. Server accepts OpenRTB 2.6 as default regardless. Tests updated: 6 new cases covering the two P1 behaviour changes (getFloor used, fallback to params, fallback when getFloor throws, fallback to 0, currency preserved, ortb2 schain wins over bid.schain, bid.schain fallback when ortb2 empty). The removed "forwards schain from first bid" test is covered by the new "falls back to bid.schain" case. Existing CORS assertion updated to expect absent customHeaders. 43/43 tests green in Karma/ChromeHeadless. Lint clean. * pgamdirect: convert to TypeScript, use ortbConverter Addresses patmmccann review on #14763: - Convert pgamdirectBidAdapter.js → .ts with typed public interface. - Replace the hand-rolled imp/device/user/source builders with libraries/ortbConverter, keeping only the pgam-specific fields (imp.ext.pgam.orgId, imp.tagid from params.placementId, meta.networkName from seatbid.seat) as converter hooks. - Drop the contentType: 'application/json' header entirely — JSON is NOT a CORS-simple content-type, so setting it forces a browser preflight on every auction. Omitting it keeps the POST preflight-free (saves one RTT per request). The converter inherits Prebid's standard handling of: - priceFloors module (imp.bidfloor / bidfloorcur via bid.getFloor) - schain via FPD normalisation (source.ext.schain) - source.tid, user.eids, site/device/regs (GDPR, USP, GPP, COPPA) - media types (banner sizes → format[], video player size passthrough, native request serialisation) - bidResponse cpm/currency/ttl/netRevenue/mediaType/advertiserDomains So this change: - Removes ~200 lines of custom plumbing. - Means future ORTB spec updates (2.7, new privacy fields) flow through automatically when Prebid updates the converter. Also: - Register GVL ID 1353 on spec (PGAM Media LLC, registered with IAB). - Keep params.bidfloor as a legacy fallback when the priceFloors module has not populated imp.bidfloor. - Force at=1 (first-price) and cur=['USD'] via a request hook. Spec tests: trimmed to cover only the adapter-owned behaviour (isBidRequestValid, CORS-simple options, imp hook custom fields, request hook, bidResponse.meta.networkName, onBidWon). Library-owned behaviour (floors / schain / GDPR / media types / VAST parsing) is not re-asserted here; those are covered by ortbConverter's own specs and by every other adapter that uses it. 26/26 pass locally. * Core: remove deprecated wretry usage (#14772) * CI: replace wretry artifact flow with cache save/restore * CI: use artifact handoff without deprecated retry wrapper * Core: reduce allocations in metrics.getMetrics (#14769) * Core: cleanup adloader callback/listener references (#14767) * Core: tighten apntag shim typing (#14766) * Core: tighten apntag shim typing * Core: tighten apntag shim typing ### Motivation - TypeScript compilation failed when core code accessed `window.apntag.getTag().keywords` because `window.apntag` was typed as `any` and `getTag` returned `unknown` properties. - Provide a focused, maintainable shim for the `apntag` global so core targeting logic can rely on well-typed properties without losing runtime extensibility. ### Description - Added an `ApnTag` interface in `src/types/local/shim.d.ts` with explicit method signatures for `getTag`, `modifyTag`, `setKeywords`, `anq`, and `onEvent` and preserved an index signature for extra runtime fields (see `src/types/local/shim.d.ts` 【F:src/types/local/shim.d.ts†L7-L18】). - Typed `getTag` to return an object that may include `keywords` (`{ keywords?: Record } | undefined`) so property access like `.keywords` is accepted by the TypeScript compiler. - Made the global `Window.apntag` optional (`apntag?: ApnTag`) to reflect pages where the integration is absent. ### Testing - Ran `npx eslint src/types/local/shim.d.ts --cache --cache-strategy content` which completed successfully. - Ran `npx gulp test --nolint --file test/spec/unit/core/targeting_spec.js` which completed successfully (all relevant tests passed). - Ran `npx tsc --noEmit` which completed successfully with no type errors. * Core: use window crypto reference for UUID random data (#14764) * Permutive RTD: iterate bidders configured via params.bidders (#14774) * Permutive RTD: iterate bidders configured via params.bidders Previously setBidderRtb only wrote ortb2 for the union of acBidders and Permutive's SSP list. A bidder declared under params.bidders with a customCohorts mapping was iterated only if it was also present in one of those lists, leaving publishers' configuration silently inert. Include Object.keys(params.bidders) in the iterated set so an explicit per-bidder customCohorts mapping is always honored. Co-Authored-By: Claude Opus 4.7 (1M context) * Permutive RTD: type the public params interface Add a `.d.ts` declaring `PermutiveRtdProviderParams` / `PermutiveRtdProviderConfig` and wire them into the module via JSDoc typedef imports (follows the pattern from prebid/Prebid.js#14773). Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Claude Opus 4.7 (1M context) * 51Degrees RTD: use highEntropySUAAccessor for HEV retrieval (#14746) * CI: add manual retry for artifact downloads (#14776) * Prebid 11.8.0 release * Increment version to 11.9.0-pre * Bump @xmldom/xmldom from 0.8.12 to 0.8.13 (#14779) Bumps [@xmldom/xmldom](https://github.com/xmldom/xmldom) from 0.8.12 to 0.8.13. - [Release notes](https://github.com/xmldom/xmldom/releases) - [Changelog](https://github.com/xmldom/xmldom/blob/master/CHANGELOG.md) - [Commits](https://github.com/xmldom/xmldom/compare/0.8.12...0.8.13) --- updated-dependencies: - dependency-name: "@xmldom/xmldom" dependency-version: 0.8.13 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump fast-xml-parser from 5.5.7 to 5.7.1 (#14780) Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) from 5.5.7 to 5.7.1. - [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases) - [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md) - [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v5.5.7...v5.7.1) --- updated-dependencies: - dependency-name: fast-xml-parser dependency-version: 5.7.1 dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * aceex and yandex bidders: type the public interface (#14773) * Aceex Adapter: type public params via d.ts * Aceex/Yandex Adapter: refine bidder params typing * GPP control modules: add option to restrict more activities (#14762) * Core: add TCF 2.3 tcData coverage to consent tests (#14788) * New Bid Adapter: tne_catalyst (#14738) * New Bid Adapter: tne_catalyst * tne_catalyst: normalize video playerSize to handle flat [w,h] and nested [[w,h]] forms * tne_catalyst: use getFloor() for dynamic floors with currency passthrough, fallback to params.bidfloor * tne_catalystBidAdapter: convert to TypeScript and switch request to text/plain - Migrate adapter from JS to TS with typed BidderParams (per repo TS migration guidance). - Change request contentType from application/json to text/plain to avoid the CORS preflight that was flagged by CodeQL and noted in review. --------- Co-authored-by: StreetsDigital <45595449+StreetsDigital@users.noreply.github.com> Co-authored-by: Patrick McCann * pgamdirect: add getUserSyncs for cookie-sync pixel support (#14777) * pgamdirect: add getUserSyncs for cookie-based retargeting DSPs Follow-up to #14763. Our bid adapter previously declared no user- sync pixels, which blocked cookie-based retargeting DSPs from matching our users to their own — they need the browser-side sync step to correlate, and without it their bids come back heavily suppressed for "user not matched." Implementation routes sync URLs through the OpenRTB response from our bidder at `response.ext.cookies[]`. Each entry carries: { type: 'image' | 'iframe', url: string } The per-DSP sync URL list lives server-side (one entry per downstream DSP we integrate), so this adapter stays stable even as we add / rotate DSPs. Behaviour: - Empty serverResponses or no ext.cookies → return [] - Respects syncOptions.iframeEnabled / pixelEnabled (publisher- controlled — some publishers disallow iframe syncs) - Drops malformed entries (missing url or unknown type) - Caps at 5 pixels per response to avoid cookie floods Consent note: Prebid passes parsed GDPR / USP / GPP state, but we don't filter server-side. Each DSP's sync URL already encodes its own consent handling (appending ?gdpr=1&gdpr_consent=... as each requires). Future revision can add per-DSP consent framework declarations + server-side suppression if a DSP fails to register handling for the caller's framework. Tests: +6 spec cases covering empty, malformed, caps, and consent- driven filtering. 32/32 pass (was 26). * pgamdirect: remove in-adapter sync cap (address Codex review) Codex pointed out on #14777 that the hard-cap at 5 pixels bypassed Prebid's `userSync.syncsPerBidder` control in src/userSync.ts. Core already enforces the per-bidder sync limit based on publisher configuration; an additional cap inside the adapter silently drops valid sync URLs when a publisher raises the limit (or sets 0 = unlimited), reducing match coverage for downstream DSPs. Fix: remove the break on length >= 5 so getUserSyncs returns the full filtered list. Prebid core does the right thing from here. Updated the corresponding test to assert the full list comes back with a comment pointing to where the authoritative cap lives. 32/32 tests still pass. --------- Co-authored-by: Patrick McCann * Nexx360 Utils Library: add shared getGzipSetting helper (#14781) * Nexx360 Utils Library: add shared getGzipSetting helper Co-Authored-By: Claude Opus 4.7 (1M context) * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Gabriel Chicoye Co-authored-by: Claude Opus 4.7 (1M context) Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * Rename agenticAudienceAdapter to agenticAudienceRtdProvider (#14729) * Core: fix additional typo occurrences (#14770) * new alias nuclion (#14783) Co-authored-by: mderevyanko * enable compression and remove callbacks (#14643) * Add pgamdirect Analytics Adapter (#14778) * Add pgamdirect Analytics Adapter Companion to modules/pgamdirectBidAdapter.ts (merged #14763). Publishers install this alongside the bid adapter to forward auction telemetry to the PGAM Direct SSP backend. Forwards four Prebid events, deliberately narrow: AUCTION_END — competitor CPMs seen in the auction BID_WON — Prebid-layer winner + price AD_RENDER_SUCCEEDED — client-confirmed impression AD_RENDER_FAILED — with reason (exception / timeout / etc) The value add over a server-side-only ledger: client-confirmed render vs. "RTB said we won", plus visibility into what other bidders priced the same auction at (we own server-side data for our own DSP calls, but not for the ones other SSPs made through the same Prebid wrapper). Payload is normalised into a small fixed shape before POST — we deliberately drop the raw Prebid event args, which carry full FPD / user.eids / custom bidder params that we don't need and shouldn't exfiltrate. Sink: https://app.pgammedia.com/api/analytics-events (one POST per event; content-type text/plain to keep CORS simple). Config: pbjs.enableAnalytics({ provider: 'pgamdirect', options: { orgId: '', // required endpoint: 'https://...' // optional override } }); GVL ID 1353 (PGAM Media LLC, same as the bid adapter). Tests: 12 covering registration, orgId validation, and the pure normalise transform across all 4 forwarded event types (including the 20-entry bidders_seen cap and filter-out of bidders with no code). Event-emission path is not covered in this spec because the sinon mock + AnalyticsAdapter async queue interact oddly in the test harness — we export normalise() directly so the transform is verifiable without the full event pipeline. The ajax call itself is covered by upstream AnalyticsAdapter base-class tests. * pgamdirectAnalytics: address Codex review on #14778 Two P1s flagged by Codex on the initial commit: 1. ad_unit_code semantic inconsistency Original code pulled ad_unit_code from args.adUnitCode on BID_WON but from args.adId on AD_RENDER_*, so the same field represented different identifiers across event types. In auctions with multiple ad units (or repeated wins from the same bidder), this prevented reliable win → render reconciliation and could misattribute render outcomes. Fix: render events now read ad_unit_code from args.bid.adUnitCode (stable across the BID_WON ↔ AD_RENDER_* join for the same slot). adId moves to its own field `ad_id` so per-bid traceability is preserved. Type definition updated with a comment explaining the split so future contributors don't re-conflate them. 2. Missing fetch keepalive Prebid AGENTS.md §71 requires low-priority telemetry calls to set fetch keepalive. Without it, BID_WON + AD_RENDER_* events emitted near page unload get dropped before reaching the endpoint — and those are exactly the events that fire in that window. Added `keepalive: true` to the ajax call. Prebid's ajax helper already supports the flag (src/ajax.ts option); no adapter-side polyfill needed. Tests: +1 spec case covering "missing bid object on AD_RENDER_* still captures ad_id cleanly." Existing render-event assertions updated to verify the ad_unit_code-vs-ad_id split explicitly. 13/13 pass (was 12). * fix: add upstream_partner KV to GAM (#14743) Co-authored-by: Shashank <=> * Vidazoo adapter: support host bidder param (#14784) * align spec on all adapters that we manage; add coverage to libraries/vidazooUtils/bidderUtils.js; changes are backward-compatible * more coverage * more coverage for vidazoo bidder utilities * more coverage; utils function full coverage * remove comments * fix tests after the code removal in new master code: check of bidderRequest.paapi.enabled * fixing get headers * fixing single request * adding burl to createInterpretResponseFn * adding more tests for coverage * fixing latest changes to support the right data * fixing tests * fix missing map of a host param * fix missing map of a host param * adding test for the new data params map * adding type files for adapter to define params in bid object * code imp --------- Co-authored-by: Anna Yablonsky * Build System: replace source-map-loader with webpack native source-map loading (#14797) * Mtc Bid Adapter: initial release (#14782) * Nexx360 Utils Library: add shared getGzipSetting helper Co-Authored-By: Claude Opus 4.7 (1M context) * Mtc Bid Adapter: initial release Co-Authored-By: Claude Opus 4.7 (1M context) * Update mtcBidAdapter.ts Bid Params guard fix * Update mtcBidAdapter.md * Nexx360 Bid Adapter: make requestCounter assertion order-independent The shared module-level requestCounter in libraries/nexx360Utils is incremented by every consuming adapter, so when mtcBidAdapter tests run in the same chunk before nexx360 tests, the counter is no longer 0. Co-Authored-By: Claude Opus 4.7 (1M context) --------- Co-authored-by: Gabriel Chicoye Co-authored-by: Claude Opus 4.7 (1M context) * New Bid Adapter - goadserver (#14701) * New Bid Adapter - goadserver Multi-tenant Prebid.js adapter for the goadserver platform. One bidder code ("goadserver") serves every deployment — publishers pass the deployment-specific host + SSP campaign token per ad unit via params.host and params.token. The adapter POSTs to https://{host}/openrtb2/auction (goadserver's Prebid Server-compatible endpoint) and supports banner, video, and native via ortbConverter. GVL ID is not yet registered with IAB Europe and is commented out in the adapter for now; will be populated once the TCF registration lands. Co-Authored-By: Claude Opus 4.6 (1M context) * goadserverBidAdapter: use real maintainer email Co-Authored-By: Claude Opus 4.6 (1M context) * goadserverBidAdapter: support params.subid Emits an optional per-impression subid in imp.ext.goadserver.subid so goadserver can attribute bids to a sub-identifier (page section, article bucket, A/B test group, etc.) without requiring a separate HB campaign per variation. Server-side normalization strips unsafe characters and caps the length at 1024. Test coverage: 22 → 24 tests (adds "emits params.subid" and "omits imp.ext.goadserver.subid when no subid is set" cases). Co-Authored-By: Claude Opus 4.6 (1M context) * goadserverBidAdapter: getUserSyncs from ext.goadserver.usersync Implements the getUserSyncs hook so publishers using this adapter drop the goadserver persistent cookie after each auction. The sync URL is published per-deployment at response.body.ext.goadserver.usersync by the server (/openrtb2/auction), so the same adapter picks up the right pixel for every goadserver system without hardcoding hosts. Returns image or iframe syncs per syncOptions; falls back to empty when either the response has no sync entry or the publisher has disabled sync types globally. Test coverage: 24 → 29 tests (5 new getUserSyncs cases covering empty responses, missing ext, type filtering, and iframe path). Co-Authored-By: Claude Opus 4.6 (1M context) * goadserverBidAdapter: params.deals[] + outstream video docs Two Tier 2 additions: 1. params.deals[] support. Publishers can now attach private marketplace deal objects per ad unit; the adapter's ortbConverter imp hook translates them into imp.pmp.deals[] in the outgoing BidRequest. Each deal object accepts id (required), bidfloor, bidfloorcur, at, wseat[], wadomain[] — matching the OpenRTB 2.5 imp.pmp.deals spec. 2. Outstream video documentation. The adapter already forwards video imps untouched via ortbConverter (including context='outstream') so no code change is needed on the request side. Added an .md section showing the standard Prebid.js ad-unit-level renderer pattern for publishers who want outstream. Test coverage: 29 → 32 tests (emits deals, omits when unset, outstream video imp shape preserved). Co-Authored-By: Claude Opus 4.6 (1M context) * goadserverBidAdapter: outstream video renderer + cached VAST URL Attaches a Prebid.js Renderer for video bids whose ad unit requested mediaTypes.video.context = 'outstream'. The renderer loads the deployment-hosted player at https://{params.host}/prebid-outstream.js which parses the VAST XML and injects a muted autoplay