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
|
@@ -7,11 +7,7 @@ import {
|
|
|
7
7
|
ORTB_UFPD_PATHS
|
|
8
8
|
} from '../../src/activities/redactor.js';
|
|
9
9
|
import {objectGuard, writeProtectRule} from './objectGuard.js';
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* @typedef {import('./objectGuard.js').ObjectGuard} ObjectGuard
|
|
14
|
-
*/
|
|
10
|
+
import {logError} from '../../src/utils.js';
|
|
15
11
|
|
|
16
12
|
function ortb2EnrichRules(isAllowed = isActivityAllowed) {
|
|
17
13
|
return [
|
|
@@ -32,20 +28,10 @@ export function ortb2GuardFactory(isAllowed = isActivityAllowed) {
|
|
|
32
28
|
return objectGuard(ortb2TransmitRules(isAllowed).concat(ortb2EnrichRules(isAllowed)));
|
|
33
29
|
}
|
|
34
30
|
|
|
35
|
-
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
* @typedef {Function} ortb2Guard
|
|
39
|
-
* @param {{}} ortb2 ORTB object to guard
|
|
40
|
-
* @param {{}} params activity params to use for activity checks
|
|
41
|
-
* @returns {ObjectGuard}
|
|
42
|
-
*/
|
|
43
|
-
|
|
44
31
|
/*
|
|
45
32
|
* Get a guard for an ORTB object. Read access is restricted in the same way it'd be redacted (see activites/redactor.js);
|
|
46
33
|
* and writes are checked against the enrich* activites.
|
|
47
34
|
*
|
|
48
|
-
* @type ortb2Guard
|
|
49
35
|
*/
|
|
50
36
|
export const ortb2Guard = ortb2GuardFactory();
|
|
51
37
|
|
|
@@ -53,40 +39,44 @@ export function ortb2FragmentsGuardFactory(guardOrtb2 = ortb2Guard) {
|
|
|
53
39
|
return function guardOrtb2Fragments(fragments, params) {
|
|
54
40
|
fragments.global = fragments.global || {};
|
|
55
41
|
fragments.bidder = fragments.bidder || {};
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
42
|
+
const guard = {
|
|
43
|
+
global: guardOrtb2(fragments.global, params),
|
|
44
|
+
bidder: new Proxy(fragments.bidder, {
|
|
45
|
+
get(target, prop, receiver) {
|
|
46
|
+
let bidderData = Reflect.get(target, prop, receiver);
|
|
47
|
+
if (bidderData != null) {
|
|
48
|
+
bidderData = guardOrtb2(bidderData, params)
|
|
49
|
+
}
|
|
50
|
+
return bidderData;
|
|
51
|
+
},
|
|
52
|
+
set(target, prop, newValue, receiver) {
|
|
53
|
+
if (newValue == null || typeof newValue !== 'object') {
|
|
54
|
+
logError(`ortb2Fragments.bidder[bidderCode] must be an object`);
|
|
55
|
+
}
|
|
56
|
+
let bidderData = Reflect.get(target, prop, receiver);
|
|
57
|
+
if (bidderData == null) {
|
|
58
|
+
bidderData = target[prop] = {};
|
|
59
|
+
}
|
|
60
|
+
bidderData = guardOrtb2(bidderData, params);
|
|
61
|
+
Object.entries(newValue).forEach(([prop, value]) => {
|
|
62
|
+
bidderData[prop] = value;
|
|
63
|
+
})
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
})
|
|
68
67
|
};
|
|
69
68
|
|
|
70
|
-
return
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const guard = guardOrtb2(repl, params);
|
|
78
|
-
mergeDeep(guard.obj, ortb2);
|
|
79
|
-
guard.verify();
|
|
80
|
-
fragments.bidder[bidder] = repl;
|
|
81
|
-
})
|
|
82
|
-
verifiers.forEach(fn => fn());
|
|
83
|
-
}
|
|
84
|
-
}
|
|
69
|
+
return Object.defineProperties(
|
|
70
|
+
{},
|
|
71
|
+
Object.fromEntries(
|
|
72
|
+
// disallow overwriting of the top level `global` / `bidder`
|
|
73
|
+
Object.entries(guard).map(([prop, obj]) => [prop, {get: () => obj}])
|
|
74
|
+
)
|
|
75
|
+
)
|
|
85
76
|
}
|
|
86
77
|
}
|
|
87
78
|
|
|
88
79
|
/**
|
|
89
80
|
* Get a guard for an ortb2Fragments object.
|
|
90
|
-
* @type {function(*, *): ObjectGuard}
|
|
91
81
|
*/
|
|
92
82
|
export const guardOrtb2Fragments = ortb2FragmentsGuardFactory();
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { logInfo } from '../../../src/utils.js';
|
|
2
|
+
import { getGlobal } from '../../../src/prebidGlobal.js';
|
|
3
|
+
import { bidderTimeoutFunctions } from '../../bidderTimeoutUtils/bidderTimeoutUtils.js';
|
|
4
|
+
import { shouldThrottle } from '../pubmaticUtils.js';
|
|
5
|
+
|
|
6
|
+
let _dynamicTimeoutConfig = null;
|
|
7
|
+
export const getDynamicTimeoutConfig = () => _dynamicTimeoutConfig;
|
|
8
|
+
export const setDynamicTimeoutConfig = (config) => { _dynamicTimeoutConfig = config; }
|
|
9
|
+
|
|
10
|
+
export const CONSTANTS = Object.freeze({
|
|
11
|
+
LOG_PRE_FIX: 'PubMatic-Dynamic-Timeout: ',
|
|
12
|
+
INCLUDES_VIDEOS: 'includesVideo',
|
|
13
|
+
NUM_AD_UNITS: 'numAdUnits',
|
|
14
|
+
DEVICE_TYPE: 'deviceType',
|
|
15
|
+
CONNECTION_SPEED: 'connectionSpeed',
|
|
16
|
+
DEFAULT_SKIP_RATE: 50,
|
|
17
|
+
DEFAULT_THRESHOLD_TIMEOUT: 500
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
export const RULES_PERCENTAGE = {
|
|
21
|
+
[CONSTANTS.INCLUDES_VIDEOS]: {
|
|
22
|
+
"true": 20, // 20% of bidderTimeout
|
|
23
|
+
"false": 5 // 5% of bidderTimeout
|
|
24
|
+
},
|
|
25
|
+
[CONSTANTS.NUM_AD_UNITS]: {
|
|
26
|
+
"1-5": 10, // 10% of bidderTimeout
|
|
27
|
+
"6-10": 20, // 20% of bidderTimeout
|
|
28
|
+
"11-15": 30 // 30% of bidderTimeout
|
|
29
|
+
},
|
|
30
|
+
[CONSTANTS.DEVICE_TYPE]: {
|
|
31
|
+
"2": 5, // 5% of bidderTimeout
|
|
32
|
+
"4": 10, // 10% of bidderTimeout
|
|
33
|
+
"5": 20 // 20% of bidderTimeout
|
|
34
|
+
},
|
|
35
|
+
[CONSTANTS.CONNECTION_SPEED]: {
|
|
36
|
+
"slow": 20, // 20% of bidderTimeout
|
|
37
|
+
"medium": 10, // 10% of bidderTimeout
|
|
38
|
+
"fast": 5, // 5% of bidderTimeout
|
|
39
|
+
"unknown": 1 // 1% of bidderTimeout
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Initialize the dynamic timeout plugin
|
|
45
|
+
* @param {Object} pluginName - Plugin name
|
|
46
|
+
* @param {Object} configJsonManager - Configuration JSON manager object
|
|
47
|
+
* @returns {Promise<boolean>} - Promise resolving to initialization status
|
|
48
|
+
*/
|
|
49
|
+
export async function init(pluginName, configJsonManager) {
|
|
50
|
+
const config = configJsonManager.getConfigByName(pluginName);
|
|
51
|
+
if (!config) {
|
|
52
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Dynamic Timeout configuration not found`);
|
|
53
|
+
return false;
|
|
54
|
+
}
|
|
55
|
+
// Set the Dynamic Timeout config
|
|
56
|
+
setDynamicTimeoutConfig(config);
|
|
57
|
+
|
|
58
|
+
if (!getDynamicTimeoutConfig()?.enabled) {
|
|
59
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Dynamic Timeout configuration is disabled`);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Process bid request by applying dynamic timeout adjustments
|
|
67
|
+
* @param {Object} reqBidsConfigObj - Bid request config object
|
|
68
|
+
* @returns {Object} - Updated bid request config object with adjusted timeout
|
|
69
|
+
*/
|
|
70
|
+
export function processBidRequest(reqBidsConfigObj) {
|
|
71
|
+
// Cache config to avoid multiple calls
|
|
72
|
+
const timeoutConfig = getDynamicTimeoutConfig();
|
|
73
|
+
|
|
74
|
+
// Check if request should be throttled based on skipRate
|
|
75
|
+
const skipRate = (timeoutConfig?.config?.skipRate !== undefined && timeoutConfig?.config?.skipRate !== null) ? timeoutConfig?.config?.skipRate : CONSTANTS.DEFAULT_SKIP_RATE;
|
|
76
|
+
if (shouldThrottle(skipRate)) {
|
|
77
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Dynamic timeout is skipped (skipRate: ${skipRate}%)`);
|
|
78
|
+
return reqBidsConfigObj;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Dynamic timeout is applying...`);
|
|
82
|
+
|
|
83
|
+
// Get ad units and bidder timeout
|
|
84
|
+
const adUnits = reqBidsConfigObj.adUnits || getGlobal().adUnits;
|
|
85
|
+
const bidderTimeout = getBidderTimeout(reqBidsConfigObj);
|
|
86
|
+
|
|
87
|
+
// Calculate and apply additional timeout
|
|
88
|
+
const rules = getRules(bidderTimeout);
|
|
89
|
+
const additionalTimeout = bidderTimeoutFunctions.calculateTimeoutModifier(adUnits, rules);
|
|
90
|
+
|
|
91
|
+
reqBidsConfigObj.timeout = getFinalTimeout(bidderTimeout, additionalTimeout);
|
|
92
|
+
|
|
93
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Timeout adjusted from ${bidderTimeout}ms to ${reqBidsConfigObj.timeout}ms (added ${additionalTimeout}ms)`);
|
|
94
|
+
return reqBidsConfigObj;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Get targeting data
|
|
99
|
+
* @param {Array} adUnitCodes - Ad unit codes
|
|
100
|
+
* @param {Object} config - Module configuration
|
|
101
|
+
* @param {Object} userConsent - User consent data
|
|
102
|
+
* @param {Object} auction - Auction object
|
|
103
|
+
* @returns {Object} - Targeting data
|
|
104
|
+
*/
|
|
105
|
+
export function getTargeting(adUnitCodes, config, userConsent, auction) {
|
|
106
|
+
// Implementation for targeting data, if not applied then do nothing
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Export the dynamic timeout functions
|
|
110
|
+
export const DynamicTimeout = {
|
|
111
|
+
init,
|
|
112
|
+
processBidRequest,
|
|
113
|
+
getTargeting
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Helper Functions
|
|
117
|
+
|
|
118
|
+
export const getFinalTimeout = (bidderTimeout, additionalTimeout) => {
|
|
119
|
+
// Calculate the final timeout by adding bidder timeout and additional timeout
|
|
120
|
+
const calculatedTimeout = parseInt(bidderTimeout) + parseInt(additionalTimeout);
|
|
121
|
+
const thresholdTimeout = getDynamicTimeoutConfig()?.config?.thresholdTimeout || CONSTANTS.DEFAULT_THRESHOLD_TIMEOUT;
|
|
122
|
+
|
|
123
|
+
// Handle cases where the calculated timeout might be negative or below threshold
|
|
124
|
+
if (calculatedTimeout < thresholdTimeout) {
|
|
125
|
+
// Log warning for negative or very low timeouts
|
|
126
|
+
if (calculatedTimeout < 0) {
|
|
127
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Warning: Negative timeout calculated (${calculatedTimeout}ms), using threshold (${thresholdTimeout}ms)`);
|
|
128
|
+
} else if (calculatedTimeout < thresholdTimeout) {
|
|
129
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Calculated timeout (${calculatedTimeout}ms) below threshold, using threshold (${thresholdTimeout}ms)`);
|
|
130
|
+
}
|
|
131
|
+
return thresholdTimeout;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return calculatedTimeout;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export const getBidderTimeout = (reqBidsConfigObj) => {
|
|
138
|
+
return getDynamicTimeoutConfig()?.config?.bidderTimeout
|
|
139
|
+
? getDynamicTimeoutConfig()?.config?.bidderTimeout
|
|
140
|
+
: reqBidsConfigObj?.timeout || getGlobal()?.getConfig('bidderTimeout');
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Get rules based on percentage values and bidderTimeout
|
|
145
|
+
* @param {number} bidderTimeout - Bidder timeout in milliseconds
|
|
146
|
+
* @returns {Object} - Rules with calculated millisecond values
|
|
147
|
+
*/
|
|
148
|
+
export const getRules = (bidderTimeout) => {
|
|
149
|
+
const timeoutConfig = getDynamicTimeoutConfig();
|
|
150
|
+
|
|
151
|
+
// In milliseconds - If timeout rules provided by publishers are available then return it
|
|
152
|
+
if (timeoutConfig?.config?.timeoutRules && Object.keys(timeoutConfig.config.timeoutRules).length > 0) {
|
|
153
|
+
return timeoutConfig.config.timeoutRules;
|
|
154
|
+
}
|
|
155
|
+
// In milliseconds - Check for rules in priority order, If ML model rules are available then return it
|
|
156
|
+
if (timeoutConfig?.data && Object.keys(timeoutConfig.data).length > 0) {
|
|
157
|
+
return timeoutConfig.data;
|
|
158
|
+
}
|
|
159
|
+
// In Percentage - If no rules are available then create rules from the default defined - values are in percentages
|
|
160
|
+
return createDynamicRules(RULES_PERCENTAGE, bidderTimeout);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Creates dynamic rules based on percentage values and bidder timeout
|
|
165
|
+
* @param {Object} percentageRules - Rules with percentage values
|
|
166
|
+
* @param {number} bidderTimeout - Bidder timeout in milliseconds
|
|
167
|
+
* @return {Object} - Rules with calculated millisecond values
|
|
168
|
+
*/
|
|
169
|
+
export const createDynamicRules = (percentageRules, bidderTimeout) => {
|
|
170
|
+
// Return empty object if required parameters are missing or invalid
|
|
171
|
+
if (!percentageRules || typeof percentageRules !== 'object') {
|
|
172
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Invalid percentage rules provided to createDynamicRules`);
|
|
173
|
+
return {};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Handle negative or zero bidderTimeout gracefully
|
|
177
|
+
if (!bidderTimeout || typeof bidderTimeout !== 'number' || bidderTimeout <= 0) {
|
|
178
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Invalid bidderTimeout (${bidderTimeout}ms) provided to createDynamicRules`);
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
// Create a new rules object with millisecond values
|
|
183
|
+
return Object.entries(percentageRules).reduce((dynamicRules, [category, rules]) => {
|
|
184
|
+
// Skip if rules is not an object
|
|
185
|
+
if (!rules || typeof rules !== 'object') {
|
|
186
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Skipping invalid rule category: ${category}`);
|
|
187
|
+
return dynamicRules;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Initialize category in the dynamic rules
|
|
191
|
+
dynamicRules[category] = {};
|
|
192
|
+
|
|
193
|
+
// Convert each percentage value to milliseconds
|
|
194
|
+
Object.entries(rules).forEach(([key, percentValue]) => {
|
|
195
|
+
// Ensure percentage value is a number and not zero
|
|
196
|
+
if (typeof percentValue === 'number' && percentValue !== 0) {
|
|
197
|
+
const calculatedTimeout = Math.floor(bidderTimeout * (percentValue / 100));
|
|
198
|
+
dynamicRules[category][key] = calculatedTimeout;
|
|
199
|
+
|
|
200
|
+
// Log warning for negative calculated timeouts
|
|
201
|
+
if (calculatedTimeout < 0) {
|
|
202
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Warning: Negative timeout calculated for ${category}.${key}: ${calculatedTimeout}ms`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
return dynamicRules;
|
|
208
|
+
}, {});
|
|
209
|
+
};
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
// plugins/floorProvider.js
|
|
2
|
+
import { logInfo, logError, isFn, logMessage, isEmpty } from '../../../src/utils.js';
|
|
3
|
+
import { getDeviceType as fetchDeviceType, getOS } from '../../userAgentUtils/index.js';
|
|
4
|
+
import { getBrowserType, getCurrentTimeOfDay, getUtmValue } from '../pubmaticUtils.js';
|
|
5
|
+
import { config as conf } from '../../../src/config.js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* This RTD module has a dependency on the priceFloors module.
|
|
9
|
+
* We utilize the continueAuction function from the priceFloors module to incorporate price floors data into the current auction.
|
|
10
|
+
*/
|
|
11
|
+
import { continueAuction } from '../../../modules/priceFloors.js'; // eslint-disable-line prebid/validate-imports
|
|
12
|
+
|
|
13
|
+
let _floorConfig = null;
|
|
14
|
+
export const getFloorConfig = () => _floorConfig;
|
|
15
|
+
export const setFloorsConfig = (config) => { _floorConfig = config; }
|
|
16
|
+
|
|
17
|
+
let _configJsonManager = null;
|
|
18
|
+
export const getConfigJsonManager = () => _configJsonManager;
|
|
19
|
+
export const setConfigJsonManager = (configJsonManager) => { _configJsonManager = configJsonManager; }
|
|
20
|
+
|
|
21
|
+
export const CONSTANTS = Object.freeze({
|
|
22
|
+
LOG_PRE_FIX: 'PubMatic-Floor-Provider: '
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Initialize the floor provider
|
|
27
|
+
* @param {Object} pluginName - Plugin name
|
|
28
|
+
* @param {Object} configJsonManager - Configuration JSON manager object
|
|
29
|
+
* @returns {Promise<boolean>} - Promise resolving to initialization status
|
|
30
|
+
*/
|
|
31
|
+
export async function init(pluginName, configJsonManager) {
|
|
32
|
+
// Process floor-specific configuration
|
|
33
|
+
const config = configJsonManager.getConfigByName(pluginName);
|
|
34
|
+
if (!config) {
|
|
35
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Floor configuration not found`);
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
setFloorsConfig(config);
|
|
39
|
+
|
|
40
|
+
if (!getFloorConfig()?.enabled) {
|
|
41
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Floor configuration is disabled`);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!isFn(continueAuction)) {
|
|
46
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} continueAuction is not a function. Please ensure to add priceFloors module.`);
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
setConfigJsonManager(configJsonManager);
|
|
51
|
+
try {
|
|
52
|
+
conf.setConfig(prepareFloorsConfig());
|
|
53
|
+
logMessage(`${CONSTANTS.LOG_PRE_FIX} dynamicFloors config set successfully`);
|
|
54
|
+
} catch (error) {
|
|
55
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error setting dynamicFloors config: ${error}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Floor configuration loaded`);
|
|
59
|
+
|
|
60
|
+
return true;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Process bid request
|
|
65
|
+
* @param {Object} reqBidsConfigObj - Bid request config object
|
|
66
|
+
* @returns {Object} - Updated bid request config object
|
|
67
|
+
*/
|
|
68
|
+
export function processBidRequest(reqBidsConfigObj) {
|
|
69
|
+
try {
|
|
70
|
+
const hookConfig = {
|
|
71
|
+
reqBidsConfigObj,
|
|
72
|
+
context: null, // Removed 'this' as it's not applicable in function-based implementation
|
|
73
|
+
nextFn: () => true,
|
|
74
|
+
haveExited: false,
|
|
75
|
+
timer: null
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Apply floor configuration
|
|
79
|
+
continueAuction(hookConfig);
|
|
80
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Applied floor configuration to auction`);
|
|
81
|
+
|
|
82
|
+
return reqBidsConfigObj;
|
|
83
|
+
} catch (error) {
|
|
84
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error applying floor configuration: ${error}`);
|
|
85
|
+
return reqBidsConfigObj;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Get targeting data
|
|
91
|
+
* @param {Array} adUnitCodes - Ad unit codes
|
|
92
|
+
* @param {Object} config - Module configuration
|
|
93
|
+
* @param {Object} userConsent - User consent data
|
|
94
|
+
* @param {Object} auction - Auction object
|
|
95
|
+
* @returns {Object} - Targeting data
|
|
96
|
+
*/
|
|
97
|
+
export function getTargeting(adUnitCodes, config, userConsent, auction) {
|
|
98
|
+
// Implementation for targeting data, if not applied then do nothing
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Export the floor provider functions
|
|
102
|
+
export const FloorProvider = {
|
|
103
|
+
init,
|
|
104
|
+
processBidRequest,
|
|
105
|
+
getTargeting
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// Helper Functions
|
|
109
|
+
|
|
110
|
+
export const defaultValueTemplate = {
|
|
111
|
+
currency: 'USD',
|
|
112
|
+
skipRate: 0,
|
|
113
|
+
schema: {
|
|
114
|
+
fields: ['mediaType', 'size']
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Getter Functions
|
|
119
|
+
export const getTimeOfDay = () => getCurrentTimeOfDay();
|
|
120
|
+
export const getBrowser = () => getBrowserType();
|
|
121
|
+
export const getOs = () => getOS().toString();
|
|
122
|
+
export const getDeviceType = () => fetchDeviceType().toString();
|
|
123
|
+
export const getCountry = () => getConfigJsonManager().country;
|
|
124
|
+
export const getBidder = (request) => request?.bidder;
|
|
125
|
+
export const getUtm = () => getUtmValue();
|
|
126
|
+
|
|
127
|
+
export const prepareFloorsConfig = () => {
|
|
128
|
+
if (!getFloorConfig()?.enabled || !getFloorConfig()?.config) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Floor configs from adunit / setconfig
|
|
133
|
+
const defaultFloorConfig = conf.getConfig('floors') ?? {};
|
|
134
|
+
if (defaultFloorConfig?.endpoint) {
|
|
135
|
+
delete defaultFloorConfig.endpoint;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
let ymUiConfig = { ...getFloorConfig().config };
|
|
139
|
+
|
|
140
|
+
// default values provided by publisher on YM UI
|
|
141
|
+
const defaultValues = ymUiConfig.defaultValues ?? {};
|
|
142
|
+
// If floorsData is not present or is an empty object, use default values
|
|
143
|
+
const ymFloorsData = isEmpty(getFloorConfig().data)
|
|
144
|
+
? { ...defaultValueTemplate, values: { ...defaultValues } }
|
|
145
|
+
: getFloorConfig().data;
|
|
146
|
+
|
|
147
|
+
delete ymUiConfig.defaultValues;
|
|
148
|
+
// If skiprate is provided in configs, overwrite the value in ymFloorsData
|
|
149
|
+
(ymUiConfig.skipRate !== undefined) && (ymFloorsData.skipRate = ymUiConfig.skipRate);
|
|
150
|
+
|
|
151
|
+
// merge default configs from page, configs
|
|
152
|
+
return {
|
|
153
|
+
floors: {
|
|
154
|
+
...defaultFloorConfig,
|
|
155
|
+
...ymUiConfig,
|
|
156
|
+
data: ymFloorsData,
|
|
157
|
+
additionalSchemaFields: {
|
|
158
|
+
deviceType: getDeviceType,
|
|
159
|
+
timeOfDay: getTimeOfDay,
|
|
160
|
+
browser: getBrowser,
|
|
161
|
+
os: getOs,
|
|
162
|
+
utm: getUtm,
|
|
163
|
+
country: getCountry,
|
|
164
|
+
bidder: getBidder,
|
|
165
|
+
},
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { logInfo, logWarn, logError } from "../../../src/utils.js";
|
|
2
|
+
|
|
3
|
+
// pluginManager.js
|
|
4
|
+
export const plugins = new Map();
|
|
5
|
+
export const CONSTANTS = Object.freeze({
|
|
6
|
+
LOG_PRE_FIX: 'PubMatic-Plugin-Manager: '
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Initialize the plugin manager with constants
|
|
11
|
+
* @returns {Object} - Plugin manager functions
|
|
12
|
+
*/
|
|
13
|
+
export const PluginManager = () => ({
|
|
14
|
+
register,
|
|
15
|
+
initialize,
|
|
16
|
+
executeHook
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Register a plugin with the plugin manager
|
|
21
|
+
* @param {string} name - Plugin name
|
|
22
|
+
* @param {Object} plugin - Plugin object
|
|
23
|
+
* @returns {Object} - Plugin manager functions
|
|
24
|
+
*/
|
|
25
|
+
const register = (name, plugin) => {
|
|
26
|
+
if (plugins.has(name)) {
|
|
27
|
+
logWarn(`${CONSTANTS.LOG_PRE_FIX} Plugin ${name} already registered`);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
plugins.set(name, plugin);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Unregister a plugin from the plugin manager
|
|
35
|
+
* @param {string} name - Plugin name
|
|
36
|
+
* @returns {Object} - Plugin manager functions
|
|
37
|
+
*/
|
|
38
|
+
const unregister = (name) => {
|
|
39
|
+
if (plugins.has(name)) {
|
|
40
|
+
logInfo(`${CONSTANTS.LOG_PRE_FIX} Unregistering plugin ${name}`);
|
|
41
|
+
plugins.delete(name);
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Initialize all registered plugins with their specific config
|
|
47
|
+
* @param {Object} configJsonManager - Configuration JSON manager object
|
|
48
|
+
* @returns {Promise} - Promise resolving when all plugins are initialized
|
|
49
|
+
*/
|
|
50
|
+
const initialize = async (configJsonManager) => {
|
|
51
|
+
const initPromises = [];
|
|
52
|
+
|
|
53
|
+
// Initialize each plugin with its specific config
|
|
54
|
+
for (const [name, plugin] of plugins.entries()) {
|
|
55
|
+
if (plugin.init) {
|
|
56
|
+
const initialized = await plugin.init(name, configJsonManager);
|
|
57
|
+
if (!initialized) {
|
|
58
|
+
unregister(name);
|
|
59
|
+
}
|
|
60
|
+
initPromises.push(initialized);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return Promise.all(initPromises);
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Execute a hook on all registered plugins synchronously
|
|
69
|
+
* @param {string} hookName - Name of the hook to execute
|
|
70
|
+
* @param {...any} args - Arguments to pass to the hook
|
|
71
|
+
* @returns {Object} - Object containing merged results from all plugins
|
|
72
|
+
*/
|
|
73
|
+
const executeHook = (hookName, ...args) => {
|
|
74
|
+
// Cache results to avoid repeated processing
|
|
75
|
+
const results = {};
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
// Get all plugins that have the specified hook method
|
|
79
|
+
const pluginsWithHook = Array.from(plugins.entries())
|
|
80
|
+
.filter(([_, plugin]) => typeof plugin[hookName] === 'function');
|
|
81
|
+
|
|
82
|
+
// Process each plugin synchronously
|
|
83
|
+
for (const [name, plugin] of pluginsWithHook) {
|
|
84
|
+
try {
|
|
85
|
+
// Call the plugin's hook method synchronously
|
|
86
|
+
const result = plugin[hookName](...args);
|
|
87
|
+
|
|
88
|
+
// Skip null/undefined results
|
|
89
|
+
if (result === null || result === undefined) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// If result is an object, merge it
|
|
94
|
+
if (typeof result === 'object') {
|
|
95
|
+
Object.assign(results, result);
|
|
96
|
+
}
|
|
97
|
+
} catch (error) {
|
|
98
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error executing hook ${hookName} in plugin ${name}: ${error.message}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
} catch (error) {
|
|
102
|
+
logError(`${CONSTANTS.LOG_PRE_FIX} Error in executeHookSync: ${error.message}`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return results;
|
|
106
|
+
};
|