prebid.js 9.53.2 → 9.53.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/33acrossAnalyticsAdapter.js +1 -1
- package/dist/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/BTBidAdapter.js +1 -1
- package/dist/adagioAnalyticsAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adagioRtdProvider.js +1 -1
- package/dist/adagioUtils.js +1 -1
- package/dist/addefendBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adlooxRtdProvider.js +1 -1
- package/dist/adqueryBidAdapter.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adstirBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgAnalyticsAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adyoulikeBidAdapter.js +1 -1
- package/dist/agmaAnalyticsAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/aniviewBidAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/beopBidAdapter.js +1 -1
- package/dist/bidderTimeoutUtils.js +1 -0
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bitmediaBidAdapter.js +1 -1
- package/dist/bridBidAdapter.js +1 -1
- package/dist/bridgeuppBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/chtnwBidAdapter.js +1 -1
- package/dist/chunk-core.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/contxtfulBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -1
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/cwireBidAdapter.js +1 -1
- package/dist/dailymotionBidAdapter.js +1 -1
- package/dist/debugging-standalone.js +1 -1
- package/dist/dependencies.json +10 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/dxkultureBidAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/equativBidAdapter.js +1 -1
- package/dist/eskimiBidAdapter.js +1 -1
- package/dist/euidIdSystem.js +1 -1
- package/dist/exadsBidAdapter.js +1 -1
- package/dist/excoBidAdapter.js +1 -1
- package/dist/feedadBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/freewheel-sspBidAdapter.js +1 -1
- package/dist/fwsspBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/greenbidsAnalyticsAdapter.js +1 -1
- package/dist/greenbidsBidAdapter.js +1 -1
- package/dist/greenbidsRtdProvider.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/hypelabBidAdapter.js +1 -1
- package/dist/id5AnalyticsAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/imdsBidAdapter.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmobiBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/intentIqAnalyticsAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/jixieBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoBidAdapter.js +1 -1
- package/dist/kimberliteBidAdapter.js +1 -1
- package/dist/konduitAnalyticsAdapter.js +1 -1
- package/dist/kueezBidAdapter.js +1 -1
- package/dist/lassoBidAdapter.js +1 -1
- package/dist/lifestreetBidAdapter.js +1 -1
- package/dist/liveIntentId.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/luceadBidAdapter.js +1 -1
- package/dist/mabidderBidAdapter.js +1 -1
- package/dist/madsenseBidAdapter.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -1
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/medianetBidAdapter.js +1 -1
- package/dist/medianetUtils.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/missenaBidAdapter.js +1 -1
- package/dist/mobilefuseBidAdapter.js +1 -1
- package/dist/nextMillenniumBidAdapter.js +1 -1
- package/dist/nexx360Utils.js +1 -1
- package/dist/nobidAnalyticsAdapter.js +1 -1
- package/dist/nobidBidAdapter.js +1 -1
- package/dist/nodalsAiRtdProvider.js +1 -1
- package/dist/not-for-prod/prebid.js +178 -175
- package/dist/objectGuard.js +1 -1
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/openxBidAdapter.js +1 -1
- package/dist/optableRtdProvider.js +1 -1
- package/dist/optidigitalBidAdapter.js +1 -1
- package/dist/orbidderBidAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticAnalyticsAdapter.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubmaticIdSystem.js +1 -1
- package/dist/pubmaticRtdProvider.js +1 -1
- package/dist/pubmaticUtils.js +1 -0
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pubxaiAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/retailspotBidAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseUtils.js +1 -1
- package/dist/rtdModule.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sevioBidAdapter.js +1 -0
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/showheroes-bsBidAdapter.js +1 -1
- package/dist/smaatoBidAdapter.js +1 -1
- package/dist/smartadserverBidAdapter.js +1 -1
- package/dist/smartxBidAdapter.js +1 -1
- package/dist/smilewantedBidAdapter.js +1 -1
- package/dist/snigelBidAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sparteoBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/stvBidAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/taboolaBidAdapter.js +1 -1
- package/dist/tappxBidAdapter.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/terceptAnalyticsAdapter.js +1 -1
- package/dist/themoneytizerBidAdapter.js +1 -1
- package/dist/timeoutRtdProvider.js +1 -1
- package/dist/trionBidAdapter.js +1 -1
- package/dist/tripleliftBidAdapter.js +1 -1
- package/dist/ttdBidAdapter.js +1 -1
- package/dist/ucfunnelAnalyticsAdapter.js +1 -1
- package/dist/uid2IdSystem.js +1 -1
- package/dist/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/unrulyBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooUtils.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahooAdsBidAdapter.js +1 -1
- package/dist/yandexBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/integrationExamples/gpt/pubmaticRtdProvider_Example.html +161 -0
- package/libraries/bidderTimeoutUtils/bidderTimeoutUtils.js +119 -0
- package/libraries/objectGuard/objectGuard.js +170 -48
- package/libraries/objectGuard/ortbGuard.js +33 -43
- package/libraries/pubmaticUtils/plugins/dynamicTimeout.js +209 -0
- package/libraries/pubmaticUtils/plugins/floorProvider.js +168 -0
- package/libraries/pubmaticUtils/plugins/pluginManager.js +106 -0
- package/libraries/pubmaticUtils/plugins/unifiedPricingRule.js +375 -0
- package/libraries/pubmaticUtils/pubmaticUtils.js +76 -0
- package/modules/adagioAnalyticsAdapter.js +6 -1
- package/modules/adagioBidAdapter.js +12 -5
- package/modules/adagioRtdProvider.js +41 -35
- package/modules/fwsspBidAdapter.js +134 -69
- package/modules/fwsspBidAdapter.md +121 -26
- package/modules/optableRtdProvider.js +33 -12
- package/modules/pubmaticAnalyticsAdapter.js +315 -587
- package/modules/pubmaticBidAdapter.js +71 -8
- package/modules/pubmaticIdSystem.js +4 -4
- package/modules/pubmaticRtdProvider.js +105 -613
- package/modules/rtdModule/index.js +23 -6
- package/modules/sevioBidAdapter.js +413 -0
- package/modules/sevioBidAdapter.md +29 -0
- package/modules/sparteoBidAdapter.js +122 -10
- package/modules/timeoutRtdProvider.js +2 -105
- package/modules/ttdBidAdapter.js +0 -5
- package/modules/userId/eids.js +1 -1
- package/modules/userId/index.js +32 -1
- package/package.json +1 -1
- package/src/auction.js +3 -0
- package/test/spec/activities/objectGuard_spec.js +189 -32
- package/test/spec/activities/ortbGuard_spec.js +10 -15
- package/test/spec/libraries/bidderTimeoutUtils/bidderTimeoutUtils_spec.js +213 -0
- package/test/spec/libraries/pubmaticUtils/plugins/dynamicTimeout_spec.js +746 -0
- package/test/spec/libraries/pubmaticUtils/plugins/floorProvider_spec.js +184 -0
- package/test/spec/libraries/pubmaticUtils/plugins/pluginManager_spec.js +489 -0
- package/test/spec/libraries/pubmaticUtils/plugins/unifiedPricingRule_spec.js +359 -0
- package/test/spec/libraries/pubmaticUtils/pubmaticUtils_spec.js +236 -0
- package/test/spec/modules/adagioAnalyticsAdapter_spec.js +94 -24
- package/test/spec/modules/adagioRtdProvider_spec.js +17 -17
- package/test/spec/modules/fwsspBidAdapter_spec.js +513 -78
- package/test/spec/modules/optableRtdProvider_spec.js +55 -5
- package/test/spec/modules/pubmaticAnalyticsAdapter_spec.js +634 -916
- package/test/spec/modules/pubmaticBidAdapter_spec.js +260 -1
- package/test/spec/modules/pubmaticRtdProvider_spec.js +252 -1505
- package/test/spec/modules/realTimeDataModule_spec.js +58 -8
- package/test/spec/modules/sevioBidAdapter_spec.js +513 -0
- package/test/spec/modules/sparteoBidAdapter_spec.js +528 -43
- package/test/spec/modules/timeoutRtdProvider_spec.js +1 -201
- package/test/spec/modules/ttdBidAdapter_spec.js +0 -33
- package/test/spec/modules/userId_spec.js +115 -1
|
@@ -0,0 +1,375 @@
|
|
|
1
|
+
// plugins/unifiedPricingRule.js
|
|
2
|
+
import { logError, logInfo } from '../../../src/utils.js';
|
|
3
|
+
import { getGlobal } from '../../../src/prebidGlobal.js';
|
|
4
|
+
import { REJECTION_REASON } from '../../../src/constants.js';
|
|
5
|
+
|
|
6
|
+
const CONSTANTS = Object.freeze({
|
|
7
|
+
LOG_PRE_FIX: 'PubMatic-Unified-Pricing-Rule: ',
|
|
8
|
+
BID_STATUS: {
|
|
9
|
+
NOBID: 0,
|
|
10
|
+
WON: 1,
|
|
11
|
+
FLOORED: 2
|
|
12
|
+
},
|
|
13
|
+
MULTIPLIERS: {
|
|
14
|
+
WIN: 1.0,
|
|
15
|
+
FLOORED: 1.0,
|
|
16
|
+
NOBID: 1.0
|
|
17
|
+
},
|
|
18
|
+
TARGETING_KEYS: {
|
|
19
|
+
PM_YM_FLRS: 'pm_ym_flrs', // Whether RTD floor was applied
|
|
20
|
+
PM_YM_FLRV: 'pm_ym_flrv', // Final floor value (after applying multiplier)
|
|
21
|
+
PM_YM_BID_S: 'pm_ym_bid_s' // Bid status (0: No bid, 1: Won, 2: Floored)
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
export const getProfileConfigs = () => getConfigJsonManager()?.getYMConfig();
|
|
25
|
+
|
|
26
|
+
let _configJsonManager = null;
|
|
27
|
+
export const getConfigJsonManager = () => _configJsonManager;
|
|
28
|
+
export const setConfigJsonManager = (configJsonManager) => { _configJsonManager = configJsonManager; }
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Initialize the floor provider
|
|
32
|
+
* @param {Object} pluginName - Plugin name
|
|
33
|
+
* @param {Object} configJsonManager - Configuration JSON manager object
|
|
34
|
+
* @returns {Promise<boolean>} - Promise resolving to initialization status
|
|
35
|
+
*/
|
|
36
|
+
export async function init(pluginName, configJsonManager) {
|
|
37
|
+
setConfigJsonManager(configJsonManager);
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Process bid request
|
|
43
|
+
* @param {Object} reqBidsConfigObj - Bid request config object
|
|
44
|
+
* @returns {Object} - Updated bid request config object
|
|
45
|
+
*/
|
|
46
|
+
export function processBidRequest(reqBidsConfigObj) {
|
|
47
|
+
return reqBidsConfigObj;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Get targeting data
|
|
52
|
+
* @param {Array} adUnitCodes - Ad unit codes
|
|
53
|
+
* @param {Object} config - Module configuration
|
|
54
|
+
* @param {Object} userConsent - User consent data
|
|
55
|
+
* @param {Object} auction - Auction object
|
|
56
|
+
* @returns {Object} - Targeting data
|
|
57
|
+
*/
|
|
58
|
+
export function getTargeting(adUnitCodes, config, userConsent, auction) {
|
|
59
|
+
// Access the profile configs stored globally
|
|
60
|
+
const profileConfigs = getProfileConfigs();
|
|
61
|
+
|
|
62
|
+
// Return empty object if profileConfigs is undefined or pmTargetingKeys.enabled is explicitly set to false
|
|
63
|
+
if (!profileConfigs || profileConfigs?.plugins?.dynamicFloors?.pmTargetingKeys?.enabled === false) {
|
|
64
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} pmTargetingKeys is disabled or profileConfigs is undefined`);
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Helper to check if RTD floor is applied to a bid
|
|
69
|
+
const isRtdFloorApplied = bid => bid.floorData?.floorProvider === "PM" && !bid.floorData.skipped;
|
|
70
|
+
|
|
71
|
+
// Check if any bid has RTD floor applied
|
|
72
|
+
const hasRtdFloorAppliedBid =
|
|
73
|
+
auction?.adUnits?.some(adUnit => adUnit.bids?.some(isRtdFloorApplied)) ||
|
|
74
|
+
auction?.bidsReceived?.some(isRtdFloorApplied);
|
|
75
|
+
|
|
76
|
+
// Only log when RTD floor is applied
|
|
77
|
+
if (hasRtdFloorAppliedBid) {
|
|
78
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, 'Setting targeting via getTargetingData:');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Process each ad unit code
|
|
82
|
+
const targeting = {};
|
|
83
|
+
|
|
84
|
+
adUnitCodes.forEach(code => {
|
|
85
|
+
targeting[code] = {};
|
|
86
|
+
|
|
87
|
+
// For non-RTD floor applied cases, only set pm_ym_flrs to 0
|
|
88
|
+
if (!hasRtdFloorAppliedBid) {
|
|
89
|
+
targeting[code][CONSTANTS.TARGETING_KEYS.PM_YM_FLRS] = 0;
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Find bids and determine status for RTD floor applied cases
|
|
94
|
+
const bidsForAdUnit = findBidsForAdUnit(auction, code);
|
|
95
|
+
const rejectedBidsForAdUnit = findRejectedBidsForAdUnit(auction, code);
|
|
96
|
+
const rejectedFloorBid = findRejectedFloorBid(rejectedBidsForAdUnit);
|
|
97
|
+
const winningBid = findWinningBid(code);
|
|
98
|
+
|
|
99
|
+
// Determine bid status and values
|
|
100
|
+
const { bidStatus, baseValue, multiplier } = determineBidStatusAndValues(
|
|
101
|
+
winningBid,
|
|
102
|
+
rejectedFloorBid,
|
|
103
|
+
bidsForAdUnit,
|
|
104
|
+
auction,
|
|
105
|
+
code
|
|
106
|
+
);
|
|
107
|
+
|
|
108
|
+
// Set all targeting keys
|
|
109
|
+
targeting[code][CONSTANTS.TARGETING_KEYS.PM_YM_FLRS] = 1;
|
|
110
|
+
targeting[code][CONSTANTS.TARGETING_KEYS.PM_YM_FLRV] = (baseValue * multiplier).toFixed(2);
|
|
111
|
+
targeting[code][CONSTANTS.TARGETING_KEYS.PM_YM_BID_S] = bidStatus;
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
return targeting;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Export the floor provider functions
|
|
118
|
+
export const UnifiedPricingRule = {
|
|
119
|
+
init,
|
|
120
|
+
processBidRequest,
|
|
121
|
+
getTargeting
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
// Find all bids for a specific ad unit
|
|
125
|
+
function findBidsForAdUnit(auction, code) {
|
|
126
|
+
return auction?.bidsReceived?.filter(bid => bid.adUnitCode === code) || [];
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Find rejected bids for a specific ad unit
|
|
130
|
+
function findRejectedBidsForAdUnit(auction, code) {
|
|
131
|
+
if (!auction?.bidsRejected) return [];
|
|
132
|
+
|
|
133
|
+
// If bidsRejected is an array
|
|
134
|
+
if (Array.isArray(auction.bidsRejected)) {
|
|
135
|
+
return auction.bidsRejected.filter(bid => bid.adUnitCode === code);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// If bidsRejected is an object mapping bidders to their rejected bids
|
|
139
|
+
if (typeof auction.bidsRejected === 'object') {
|
|
140
|
+
return Object.values(auction.bidsRejected)
|
|
141
|
+
.filter(Array.isArray)
|
|
142
|
+
.flatMap(bidderBids => bidderBids.filter(bid => bid.adUnitCode === code));
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return [];
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Find a rejected bid due to price floor
|
|
149
|
+
function findRejectedFloorBid(rejectedBids) {
|
|
150
|
+
return rejectedBids.find(bid => {
|
|
151
|
+
return bid.rejectionReason === REJECTION_REASON.FLOOR_NOT_MET &&
|
|
152
|
+
(bid.floorData?.floorValue && bid.cpm < bid.floorData.floorValue);
|
|
153
|
+
});
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Find the winning or highest bid for an ad unit
|
|
157
|
+
function findWinningBid(adUnitCode) {
|
|
158
|
+
try {
|
|
159
|
+
const pbjs = getGlobal();
|
|
160
|
+
if (!pbjs?.getHighestCpmBids) return null;
|
|
161
|
+
|
|
162
|
+
const highestCpmBids = pbjs.getHighestCpmBids(adUnitCode);
|
|
163
|
+
if (!highestCpmBids?.length) {
|
|
164
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `No highest CPM bids found for ad unit: ${adUnitCode}`);
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const highestCpmBid = highestCpmBids[0];
|
|
169
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `Found highest CPM bid using pbjs.getHighestCpmBids() for ad unit: ${adUnitCode}, CPM: ${highestCpmBid.cpm}`);
|
|
170
|
+
return highestCpmBid;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
logError(CONSTANTS.LOG_PRE_FIX, `Error finding highest CPM bid: ${error}`);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Find floor value from bidder requests
|
|
178
|
+
function findFloorValueFromBidderRequests(auction, code) {
|
|
179
|
+
if (!auction?.bidderRequests?.length) return 0;
|
|
180
|
+
|
|
181
|
+
// Find all bids in bidder requests for this ad unit
|
|
182
|
+
const bidsFromRequests = auction.bidderRequests
|
|
183
|
+
.flatMap(request => request.bids || [])
|
|
184
|
+
.filter(bid => bid.adUnitCode === code);
|
|
185
|
+
|
|
186
|
+
if (!bidsFromRequests.length) {
|
|
187
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `No bids found for ad unit: ${code}`);
|
|
188
|
+
return 0;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const bidWithGetFloor = bidsFromRequests.find(bid => bid.getFloor);
|
|
192
|
+
if (!bidWithGetFloor) {
|
|
193
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `No bid with getFloor method found for ad unit: ${code}`);
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Helper function to extract sizes with their media types from a source object
|
|
198
|
+
const extractSizes = (source) => {
|
|
199
|
+
if (!source) return null;
|
|
200
|
+
|
|
201
|
+
const result = [];
|
|
202
|
+
|
|
203
|
+
// Extract banner sizes
|
|
204
|
+
if (source.mediaTypes?.banner?.sizes) {
|
|
205
|
+
source.mediaTypes.banner.sizes.forEach(size => {
|
|
206
|
+
result.push({
|
|
207
|
+
size,
|
|
208
|
+
mediaType: 'banner'
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Extract video sizes
|
|
214
|
+
if (source.mediaTypes?.video?.playerSize) {
|
|
215
|
+
const playerSize = source.mediaTypes.video.playerSize;
|
|
216
|
+
// Handle both formats: [[w, h]] and [w, h]
|
|
217
|
+
const videoSizes = Array.isArray(playerSize[0]) ? playerSize : [playerSize];
|
|
218
|
+
|
|
219
|
+
videoSizes.forEach(size => {
|
|
220
|
+
result.push({
|
|
221
|
+
size,
|
|
222
|
+
mediaType: 'video'
|
|
223
|
+
});
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// Use general sizes as fallback if no specific media types found
|
|
228
|
+
if (result.length === 0 && source.sizes) {
|
|
229
|
+
source.sizes.forEach(size => {
|
|
230
|
+
result.push({
|
|
231
|
+
size,
|
|
232
|
+
mediaType: 'banner' // Default to banner for general sizes
|
|
233
|
+
});
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return result.length > 0 ? result : null;
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// Try to get sizes from different sources in order of preference
|
|
241
|
+
const adUnit = auction.adUnits?.find(unit => unit.code === code);
|
|
242
|
+
let sizes = extractSizes(adUnit) || extractSizes(bidWithGetFloor);
|
|
243
|
+
|
|
244
|
+
// Handle fallback to wildcard size if no sizes found
|
|
245
|
+
if (!sizes) {
|
|
246
|
+
sizes = [{ size: ['*', '*'], mediaType: 'banner' }];
|
|
247
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `No sizes found, using wildcard size for ad unit: ${code}`);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Try to get floor values for each size
|
|
251
|
+
let minFloor = -1;
|
|
252
|
+
|
|
253
|
+
for (const sizeObj of sizes) {
|
|
254
|
+
// Extract size and mediaType from the object
|
|
255
|
+
const { size, mediaType } = sizeObj;
|
|
256
|
+
|
|
257
|
+
// Call getFloor with the appropriate media type
|
|
258
|
+
const floorInfo = bidWithGetFloor.getFloor({
|
|
259
|
+
currency: 'USD', // Default currency
|
|
260
|
+
mediaType: mediaType, // Use the media type we extracted
|
|
261
|
+
size: size
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
if (floorInfo?.floor && !isNaN(parseFloat(floorInfo.floor))) {
|
|
265
|
+
const floorValue = parseFloat(floorInfo.floor);
|
|
266
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `Floor value for ${mediaType} size ${size}: ${floorValue}`);
|
|
267
|
+
|
|
268
|
+
// Update minimum floor value
|
|
269
|
+
minFloor = minFloor === -1 ? floorValue : Math.min(minFloor, floorValue);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
if (minFloor !== -1) {
|
|
274
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `Calculated minimum floor value ${minFloor} for ad unit: ${code}`);
|
|
275
|
+
return minFloor;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, `No floor data found for ad unit: ${code}`);
|
|
279
|
+
return 0;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Select multiplier based on priority order: floors.json → config.json → default
|
|
283
|
+
function selectMultiplier(multiplierKey, profileConfigs) {
|
|
284
|
+
// Define sources in priority order
|
|
285
|
+
const multiplierSources = [
|
|
286
|
+
{
|
|
287
|
+
name: 'config.json',
|
|
288
|
+
getValue: () => {
|
|
289
|
+
const configPath = profileConfigs?.plugins?.dynamicFloors?.pmTargetingKeys?.multiplier;
|
|
290
|
+
const lowerKey = multiplierKey.toLowerCase();
|
|
291
|
+
return configPath && lowerKey in configPath ? configPath[lowerKey] : null;
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
name: 'floor.json',
|
|
296
|
+
getValue: () => {
|
|
297
|
+
const configPath = profileConfigs?.plugins?.dynamicFloors?.data?.multiplier;
|
|
298
|
+
const lowerKey = multiplierKey.toLowerCase();
|
|
299
|
+
return configPath && lowerKey in configPath ? configPath[lowerKey] : null;
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
name: 'default',
|
|
304
|
+
getValue: () => CONSTANTS.MULTIPLIERS[multiplierKey]
|
|
305
|
+
}
|
|
306
|
+
];
|
|
307
|
+
|
|
308
|
+
// Find the first source with a non-null value
|
|
309
|
+
for (const source of multiplierSources) {
|
|
310
|
+
const value = source.getValue();
|
|
311
|
+
if (value != null) {
|
|
312
|
+
return { value, source: source.name };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// Fallback (shouldn't happen due to default source)
|
|
317
|
+
return { value: CONSTANTS.MULTIPLIERS[multiplierKey], source: 'default' };
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Identify winning bid scenario and return scenario data
|
|
321
|
+
function handleWinningBidScenario(winningBid, code) {
|
|
322
|
+
return {
|
|
323
|
+
scenario: 'winning',
|
|
324
|
+
bidStatus: CONSTANTS.BID_STATUS.WON,
|
|
325
|
+
baseValue: winningBid.cpm,
|
|
326
|
+
multiplierKey: 'WIN',
|
|
327
|
+
logMessage: `Bid won for ad unit: ${code}, CPM: ${winningBid.cpm}`
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// Identify rejected floor bid scenario and return scenario data
|
|
332
|
+
function handleRejectedFloorBidScenario(rejectedFloorBid, code) {
|
|
333
|
+
const baseValue = rejectedFloorBid.floorData?.floorValue || 0;
|
|
334
|
+
return {
|
|
335
|
+
scenario: 'rejected',
|
|
336
|
+
bidStatus: CONSTANTS.BID_STATUS.FLOORED,
|
|
337
|
+
baseValue,
|
|
338
|
+
multiplierKey: 'FLOORED',
|
|
339
|
+
logMessage: `Bid rejected due to price floor for ad unit: ${code}, Floor value: ${baseValue}, Bid CPM: ${rejectedFloorBid.cpm}`
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Identify no bid scenario and return scenario data
|
|
344
|
+
function handleNoBidScenario(auction, code) {
|
|
345
|
+
const baseValue = findFloorValueFromBidderRequests(auction, code);
|
|
346
|
+
return {
|
|
347
|
+
scenario: 'nobid',
|
|
348
|
+
bidStatus: CONSTANTS.BID_STATUS.NOBID,
|
|
349
|
+
baseValue,
|
|
350
|
+
multiplierKey: 'NOBID',
|
|
351
|
+
logMessage: `No bids for ad unit: ${code}, Floor value: ${baseValue}`
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Determine which scenario applies based on bid conditions
|
|
356
|
+
function determineScenario(winningBid, rejectedFloorBid, bidsForAdUnit, auction, code) {
|
|
357
|
+
return winningBid ? handleWinningBidScenario(winningBid, code)
|
|
358
|
+
: rejectedFloorBid ? handleRejectedFloorBidScenario(rejectedFloorBid, code)
|
|
359
|
+
: handleNoBidScenario(auction, code);
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// Main function that determines bid status and calculates values
|
|
363
|
+
function determineBidStatusAndValues(winningBid, rejectedFloorBid, bidsForAdUnit, auction, code) {
|
|
364
|
+
const profileConfigs = getProfileConfigs();
|
|
365
|
+
|
|
366
|
+
// Determine the scenario based on bid conditions
|
|
367
|
+
const { bidStatus, baseValue, multiplierKey, logMessage } =
|
|
368
|
+
determineScenario(winningBid, rejectedFloorBid, bidsForAdUnit, auction, code);
|
|
369
|
+
|
|
370
|
+
// Select the appropriate multiplier
|
|
371
|
+
const { value: multiplier, source } = selectMultiplier(multiplierKey, profileConfigs);
|
|
372
|
+
logInfo(CONSTANTS.LOG_PRE_FIX, logMessage + ` (Using ${source} multiplier: ${multiplier})`);
|
|
373
|
+
|
|
374
|
+
return { bidStatus, baseValue, multiplier };
|
|
375
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { getLowEntropySUA } from '../../src/fpd/sua.js';
|
|
2
|
+
|
|
3
|
+
const CONSTANTS = Object.freeze({
|
|
4
|
+
TIME_OF_DAY_VALUES: {
|
|
5
|
+
MORNING: 'morning',
|
|
6
|
+
AFTERNOON: 'afternoon',
|
|
7
|
+
EVENING: 'evening',
|
|
8
|
+
NIGHT: 'night'
|
|
9
|
+
},
|
|
10
|
+
UTM: 'utm_',
|
|
11
|
+
UTM_VALUES: {
|
|
12
|
+
TRUE: '1',
|
|
13
|
+
FALSE: '0'
|
|
14
|
+
},
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
const BROWSER_REGEX_MAP = [
|
|
18
|
+
{ regex: /\b(?:crios)\/([\w.]+)/i, id: 1 }, // Chrome for iOS
|
|
19
|
+
{ regex: /(edg|edge)(?:e|ios|a)?(?:\/([\w.]+))?/i, id: 2 }, // Edge
|
|
20
|
+
{ regex: /(opera|opr)(?:.+version\/|\/|\s+)([\w.]+)/i, id: 3 }, // Opera
|
|
21
|
+
{ regex: /(?:ms|\()(ie) ([\w.]+)|(?:trident\/[\w.]+)/i, id: 4 }, // Internet Explorer
|
|
22
|
+
{ regex: /fxios\/([-\w.]+)/i, id: 5 }, // Firefox for iOS
|
|
23
|
+
{ regex: /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w.]+);)/i, id: 6 }, // Facebook In-App Browser
|
|
24
|
+
{ regex: / wv\).+(chrome)\/([\w.]+)/i, id: 7 }, // Chrome WebView
|
|
25
|
+
{ regex: /droid.+ version\/([\w.]+)\b.+(?:mobile safari|safari)/i, id: 8 }, // Android Browser
|
|
26
|
+
{ regex: /(chrome|crios)(?:\/v?([\w.]+))?\b/i, id: 9 }, // Chrome
|
|
27
|
+
{ regex: /version\/([\w.,]+) .*mobile\/\w+ (safari)/i, id: 10 }, // Safari Mobile
|
|
28
|
+
{ regex: /version\/([\w.,]+) .*(mobile ?safari|safari)/i, id: 11 }, // Safari
|
|
29
|
+
{ regex: /(firefox)\/([\w.]+)/i, id: 12 } // Firefox
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
export const getBrowserType = () => {
|
|
33
|
+
const brandName = getLowEntropySUA()?.browsers
|
|
34
|
+
?.map(b => b.brand.toLowerCase())
|
|
35
|
+
.join(' ') || '';
|
|
36
|
+
const browserMatch = brandName ? BROWSER_REGEX_MAP.find(({ regex }) => regex.test(brandName)) : -1;
|
|
37
|
+
|
|
38
|
+
if (browserMatch?.id) return browserMatch.id.toString();
|
|
39
|
+
|
|
40
|
+
const userAgent = navigator?.userAgent;
|
|
41
|
+
let browserIndex = userAgent == null ? -1 : 0;
|
|
42
|
+
|
|
43
|
+
if (userAgent) {
|
|
44
|
+
browserIndex = BROWSER_REGEX_MAP.find(({ regex }) => regex.test(userAgent))?.id || 0;
|
|
45
|
+
}
|
|
46
|
+
return browserIndex.toString();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export const getCurrentTimeOfDay = () => {
|
|
50
|
+
const currentHour = new Date().getHours();
|
|
51
|
+
|
|
52
|
+
return currentHour < 5 ? CONSTANTS.TIME_OF_DAY_VALUES.NIGHT
|
|
53
|
+
: currentHour < 12 ? CONSTANTS.TIME_OF_DAY_VALUES.MORNING
|
|
54
|
+
: currentHour < 17 ? CONSTANTS.TIME_OF_DAY_VALUES.AFTERNOON
|
|
55
|
+
: currentHour < 19 ? CONSTANTS.TIME_OF_DAY_VALUES.EVENING
|
|
56
|
+
: CONSTANTS.TIME_OF_DAY_VALUES.NIGHT;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const getUtmValue = () => {
|
|
60
|
+
const url = new URL(window.location?.href);
|
|
61
|
+
const urlParams = new URLSearchParams(url?.search);
|
|
62
|
+
return urlParams && urlParams.toString().includes(CONSTANTS.UTM) ? CONSTANTS.UTM_VALUES.TRUE : CONSTANTS.UTM_VALUES.FALSE;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Determines whether an action should be throttled based on a given percentage.
|
|
67
|
+
*
|
|
68
|
+
* @param {number} skipRate - The percentage rate at which throttling will be applied (0-100).
|
|
69
|
+
* @param {number} maxRandomValue - The upper bound for generating a random number (default is 100).
|
|
70
|
+
* @returns {boolean} - Returns true if the action should be throttled, false otherwise.
|
|
71
|
+
*/
|
|
72
|
+
export const shouldThrottle = (skipRate, maxRandomValue = 100) => {
|
|
73
|
+
// Determine throttling based on the throttle rate and a random value
|
|
74
|
+
const rate = skipRate ?? maxRandomValue;
|
|
75
|
+
return Math.floor(Math.random() * maxRandomValue) < rate;
|
|
76
|
+
};
|
|
@@ -267,7 +267,7 @@ function handlerAuctionInit(event) {
|
|
|
267
267
|
ban_szs: bannerSizes.join(','),
|
|
268
268
|
bdrs: sortedBidderNames.join(','),
|
|
269
269
|
pgtyp: deepAccess(event.bidderRequests[0], 'ortb2.site.ext.data.pagetype', null),
|
|
270
|
-
plcmt: deepAccess(adUnits[0], 'ortb2Imp.ext.data.placement', null),
|
|
270
|
+
plcmt: deepAccess(adUnits[0], 'ortb2Imp.ext.data.adg_rtd.placement', null), // adg_rtd.placement is set by AdagioRtdProvider.
|
|
271
271
|
t_n: adgRtdSession.testName || null,
|
|
272
272
|
t_v: adgRtdSession.testVersion || null,
|
|
273
273
|
s_id: adgRtdSession.id || null,
|
|
@@ -289,6 +289,11 @@ function handlerAuctionInit(event) {
|
|
|
289
289
|
// for backward compatibility: if we didn't find organizationId & site but we have a bid from adagio we might still find it in params
|
|
290
290
|
qp.org_id = qp.org_id || adagioAdUnitBids[0].params.organizationId;
|
|
291
291
|
qp.site = qp.site || adagioAdUnitBids[0].params.site;
|
|
292
|
+
|
|
293
|
+
// `qp.plcmt` uses the value set by the AdagioRtdProvider. If not present, we fallback on the value set at the adUnit.params level.
|
|
294
|
+
if (!qp.plcmt) {
|
|
295
|
+
qp.plcmt = deepAccess(adagioAdUnitBids[0], 'params.placement', null);
|
|
296
|
+
}
|
|
292
297
|
}
|
|
293
298
|
}
|
|
294
299
|
|
|
@@ -399,11 +399,18 @@ function autoFillParams(bid) {
|
|
|
399
399
|
bid.params.site = adgGlobalConf.siteId.split(':')[1];
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
402
|
+
if (!bid.params.placement) {
|
|
403
|
+
let p = deepAccess(bid, 'ortb2Imp.ext.data.adg_rtd.placement', '');
|
|
404
|
+
if (!p) {
|
|
405
|
+
// Use ortb2Imp.ext.data.placement for backward compatibility.
|
|
406
|
+
p = deepAccess(bid, 'ortb2Imp.ext.data.placement', '');
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// `useAdUnitCodeAsPlacement` is an edge case. Useful when a Prebid Manager cannot handle properly params setting.
|
|
410
|
+
if (!p && bid.params.useAdUnitCodeAsPlacement === true) {
|
|
411
|
+
p = bid.adUnitCode;
|
|
412
|
+
}
|
|
413
|
+
bid.params.placement = p;
|
|
407
414
|
}
|
|
408
415
|
|
|
409
416
|
bid.params.adUnitElementId = deepAccess(bid, 'ortb2Imp.ext.data.divId', bid.params.adUnitElementId);
|
|
@@ -47,7 +47,7 @@ export const PLACEMENT_SOURCES = {
|
|
|
47
47
|
};
|
|
48
48
|
export const storage = getStorageManager({ moduleType: MODULE_TYPE_RTD, moduleName: SUBMODULE_NAME });
|
|
49
49
|
|
|
50
|
-
const { logError, logWarn } = prefixLog('AdagioRtdProvider:');
|
|
50
|
+
const { logError, logInfo, logWarn } = prefixLog('AdagioRtdProvider:');
|
|
51
51
|
|
|
52
52
|
// Guard to avoid storing the same bid data several times.
|
|
53
53
|
const guard = new Set();
|
|
@@ -238,6 +238,25 @@ export const _internal = {
|
|
|
238
238
|
return value;
|
|
239
239
|
}
|
|
240
240
|
});
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
// Compute the placement from the legacy RTD config params or ortb2Imp.ext.data.placement key.
|
|
244
|
+
computePlacementFromLegacy: function(rtdConfig, adUnit) {
|
|
245
|
+
const placementSource = deepAccess(rtdConfig, 'params.placementSource', '');
|
|
246
|
+
let placementFromSource = '';
|
|
247
|
+
|
|
248
|
+
switch (placementSource.toLowerCase()) {
|
|
249
|
+
case PLACEMENT_SOURCES.ADUNITCODE:
|
|
250
|
+
placementFromSource = adUnit.code;
|
|
251
|
+
break;
|
|
252
|
+
case PLACEMENT_SOURCES.GPID:
|
|
253
|
+
placementFromSource = deepAccess(adUnit, 'ortb2Imp.ext.gpid')
|
|
254
|
+
break;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const placementLegacy = deepAccess(adUnit, 'ortb2Imp.ext.data.placement', '');
|
|
258
|
+
|
|
259
|
+
return placementFromSource || placementLegacy;
|
|
241
260
|
}
|
|
242
261
|
};
|
|
243
262
|
|
|
@@ -317,7 +336,6 @@ function onBidRequest(bidderRequest, config, _userConsent) {
|
|
|
317
336
|
* @param {*} config
|
|
318
337
|
*/
|
|
319
338
|
function onGetBidRequestData(bidReqConfig, callback, config) {
|
|
320
|
-
const configParams = deepAccess(config, 'params', {});
|
|
321
339
|
const { site: ortb2Site } = bidReqConfig.ortb2Fragments.global;
|
|
322
340
|
const features = _internal.getFeatures().get();
|
|
323
341
|
const ext = {
|
|
@@ -345,30 +363,11 @@ function onGetBidRequestData(bidReqConfig, callback, config) {
|
|
|
345
363
|
const slotPosition = getSlotPosition(divId);
|
|
346
364
|
deepSetValue(ortb2Imp, `ext.data.adg_rtd.adunit_position`, slotPosition);
|
|
347
365
|
|
|
348
|
-
// It is expected that the publisher set a `adUnits[].ortb2Imp.ext.data.placement` value.
|
|
349
|
-
// Btw, We allow fallback sources to programmatically set this value.
|
|
350
|
-
// The source is defined in the `config.params.placementSource` and the possible values are `code` or `gpid`.
|
|
351
|
-
// (Please note that this `placement` is not related to the oRTB video property.)
|
|
352
|
-
if (!deepAccess(ortb2Imp, 'ext.data.placement')) {
|
|
353
|
-
const { placementSource = '' } = configParams;
|
|
354
|
-
|
|
355
|
-
switch (placementSource.toLowerCase()) {
|
|
356
|
-
case PLACEMENT_SOURCES.ADUNITCODE:
|
|
357
|
-
deepSetValue(ortb2Imp, 'ext.data.placement', adUnit.code);
|
|
358
|
-
break;
|
|
359
|
-
case PLACEMENT_SOURCES.GPID:
|
|
360
|
-
deepSetValue(ortb2Imp, 'ext.data.placement', deepAccess(ortb2Imp, 'ext.gpid'));
|
|
361
|
-
break;
|
|
362
|
-
default:
|
|
363
|
-
logWarn('`ortb2Imp.ext.data.placement` is missing and `params.definePlacement` is not set in the config.');
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// We expect that `pagetype`, `category`, `placement` are defined in FPD `ortb2.site.ext.data` and `adUnits[].ortb2Imp.ext.data` objects.
|
|
368
|
-
// Btw, we have to ensure compatibility with publishers that use the "legacy" adagio params at the adUnit.params level.
|
|
369
366
|
const adagioBid = adUnit.bids.find(bid => _internal.isAdagioBidder(bid.bidder));
|
|
370
367
|
if (adagioBid) {
|
|
371
368
|
// ortb2 level
|
|
369
|
+
// We expect that `pagetype`, `category` are defined in FPD `ortb2.site.ext.data` object.
|
|
370
|
+
// Btw, we still ensure compatibility with publishers that use the adagio params at the adUnit.params level.
|
|
372
371
|
let mustWarnOrtb2 = false;
|
|
373
372
|
if (!deepAccess(ortb2Site, 'ext.data.pagetype') && adagioBid.params.pagetype) {
|
|
374
373
|
deepSetValue(ortb2Site, 'ext.data.pagetype', adagioBid.params.pagetype);
|
|
@@ -378,21 +377,28 @@ function onGetBidRequestData(bidReqConfig, callback, config) {
|
|
|
378
377
|
deepSetValue(ortb2Site, 'ext.data.category', adagioBid.params.category);
|
|
379
378
|
mustWarnOrtb2 = true;
|
|
380
379
|
}
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
let mustWarnOrtb2Imp = false;
|
|
384
|
-
if (!deepAccess(ortb2Imp, 'ext.data.placement')) {
|
|
385
|
-
if (adagioBid.params.placement) {
|
|
386
|
-
deepSetValue(ortb2Imp, 'ext.data.placement', adagioBid.params.placement);
|
|
387
|
-
mustWarnOrtb2Imp = true;
|
|
388
|
-
}
|
|
380
|
+
if (mustWarnOrtb2) {
|
|
381
|
+
logInfo('`pagetype` and/or `category` have been set in the FPD `ortb2.site.ext.data` object from `adUnits[].bids.adagio.params`.');
|
|
389
382
|
}
|
|
390
383
|
|
|
391
|
-
|
|
392
|
-
|
|
384
|
+
// ortb2Imp level to handle legacy.
|
|
385
|
+
// The `placement` is finally set at the adUnit.params level (see https://github.com/prebid/Prebid.js/issues/12845)
|
|
386
|
+
// but we still need to set it at the ortb2Imp level for our internal use.
|
|
387
|
+
const placementParam = adagioBid.params.placement;
|
|
388
|
+
const adgRtdPlacement = deepAccess(ortb2Imp, 'ext.data.adg_rtd.placement', '');
|
|
389
|
+
|
|
390
|
+
if (placementParam) {
|
|
391
|
+
// Always overwrite the ortb2Imp value with the one from the adagio adUnit.params.placement if defined.
|
|
392
|
+
// This is the common case.
|
|
393
|
+
deepSetValue(ortb2Imp, 'ext.data.adg_rtd.placement', placementParam);
|
|
393
394
|
}
|
|
394
|
-
|
|
395
|
-
|
|
395
|
+
|
|
396
|
+
if (!placementParam && !adgRtdPlacement) {
|
|
397
|
+
const p = _internal.computePlacementFromLegacy(config, adUnit);
|
|
398
|
+
if (p) {
|
|
399
|
+
deepSetValue(ortb2Imp, 'ext.data.adg_rtd.placement', p);
|
|
400
|
+
logWarn('`ortb2Imp.ext.data.adg_rtd.placement` has been set from a legacy source. Please set `bids[].adagio.params.placement` or `ortb2Imp.ext.data.adg_rtd.placement` value.');
|
|
401
|
+
}
|
|
396
402
|
}
|
|
397
403
|
}
|
|
398
404
|
});
|