prebid.js 7.18.0 → 7.20.0
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/33acrossBidAdapter.js +1 -1
- package/dist/33acrossIdSystem.js +1 -1
- package/dist/adWMGAnalyticsAdapter.js +1 -1
- package/dist/adagioAnalyticsAdapter.js +1 -1
- package/dist/adagioBidAdapter.js +1 -1
- package/dist/adbookpspBidAdapter.js +1 -1
- package/dist/adfBidAdapter.js +1 -1
- package/dist/adgenerationBidAdapter.js +1 -1
- package/dist/adkernelAdnAnalyticsAdapter.js +1 -1
- package/dist/adkernelBidAdapter.js +1 -1
- package/dist/adlooxAdServerVideo.js +1 -1
- package/dist/adlooxAnalyticsAdapter.js +1 -1
- package/dist/adlooxRtdProvider.js +1 -1
- package/dist/adomikAnalyticsAdapter.js +1 -1
- package/dist/adqueryIdSystem.js +1 -1
- package/dist/adrelevantisBidAdapter.js +1 -1
- package/dist/adtrgtmeBidAdapter.js +1 -1
- package/dist/adxcgAnalyticsAdapter.js +1 -1
- package/dist/adxcgBidAdapter.js +1 -1
- package/dist/adxpremiumAnalyticsAdapter.js +1 -1
- package/dist/ajaBidAdapter.js +1 -1
- package/dist/amxBidAdapter.js +1 -1
- package/dist/amxIdSystem.js +1 -1
- package/dist/aolBidAdapter.js +1 -1
- package/dist/appierAnalyticsAdapter.js +1 -1
- package/dist/appnexusBidAdapter.js +1 -1
- package/dist/asoBidAdapter.js +1 -1
- package/dist/atsAnalyticsAdapter.js +1 -1
- package/dist/axonixBidAdapter.js +1 -1
- package/dist/{andBeyondMediaBidAdapter.js → beyondmediaBidAdapter.js} +1 -1
- package/dist/bidViewability.js +1 -1
- package/dist/bidglassBidAdapter.js +1 -1
- package/dist/bidwatchAnalyticsAdapter.js +1 -1
- package/dist/big-richmediaBidAdapter.js +1 -1
- package/dist/bridgewellBidAdapter.js +1 -1
- package/dist/brightMountainMediaBidAdapter.js +1 -1
- package/dist/byDataAnalyticsAdapter.js +1 -1
- package/dist/carodaBidAdapter.js +1 -1
- package/dist/categoryTranslation.js +1 -1
- package/dist/cleanioRtdProvider.js +1 -1
- package/dist/colossussspBidAdapter.js +1 -1
- package/dist/concertAnalyticsAdapter.js +1 -1
- package/dist/concertBidAdapter.js +1 -1
- package/dist/connectIdSystem.js +1 -1
- package/dist/connectadBidAdapter.js +1 -1
- package/dist/consentManagement.js +1 -1
- package/dist/consentManagementUsp.js +1 -1
- package/dist/consumableBidAdapter.js +1 -1
- package/dist/conversantAnalyticsAdapter.js +1 -0
- package/dist/conversantBidAdapter.js +1 -1
- package/dist/craftBidAdapter.js +1 -1
- package/dist/criteoBidAdapter.js +1 -1
- package/dist/currency.js +1 -1
- package/dist/datablocksAnalyticsAdapter.js +1 -1
- package/dist/dchain.js +1 -1
- package/dist/debugging-standalone.js +1 -1
- package/dist/debugging.js +1 -1
- package/dist/dependencies.json +9 -0
- package/dist/dfpAdServerVideo.js +1 -1
- package/dist/dgkeywordRtdProvider.js +1 -1
- package/dist/dianomiBidAdapter.js +1 -1
- package/dist/dspxBidAdapter.js +1 -1
- package/dist/enrichmentFpdModule.js +1 -1
- package/dist/eplanningAnalyticsAdapter.js +1 -1
- package/dist/eplanningBidAdapter.js +1 -1
- package/dist/finativeBidAdapter.js +1 -1
- package/dist/fintezaAnalyticsAdapter.js +1 -1
- package/dist/fpd.js +1 -0
- package/dist/ftrackIdSystem.js +1 -1
- package/dist/gdprEnforcement.js +1 -1
- package/dist/glimpseBidAdapter.js +1 -1
- package/dist/gmosspBidAdapter.js +1 -1
- package/dist/goldbachBidAdapter.js +1 -1
- package/dist/googleAnalyticsAdapter.js +1 -1
- package/dist/gridBidAdapter.js +1 -1
- package/dist/gridNMBidAdapter.js +1 -1
- package/dist/gumgumBidAdapter.js +1 -1
- package/dist/h12mediaBidAdapter.js +1 -1
- package/dist/hadronAnalyticsAdapter.js +1 -1
- package/dist/id5AnalyticsAdapter.js +1 -1
- package/dist/id5IdSystem.js +1 -1
- package/dist/improvedigitalBidAdapter.js +1 -1
- package/dist/inmarBidAdapter.js +1 -1
- package/dist/insticatorBidAdapter.js +1 -1
- package/dist/invisiblyAnalyticsAdapter.js +1 -1
- package/dist/ixBidAdapter.js +1 -1
- package/dist/justpremiumBidAdapter.js +1 -1
- package/dist/kargoAnalyticsAdapter.js +1 -1
- package/dist/kinessoIdSystem.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/liveIntentAnalyticsAdapter.js +1 -1
- package/dist/liveIntentIdSystem.js +1 -1
- package/dist/livewrappedAnalyticsAdapter.js +1 -1
- package/dist/liveyieldAnalyticsAdapter.js +1 -1
- package/dist/logicadBidAdapter.js +1 -1
- package/dist/loglyliftBidAdapter.js +1 -1
- package/dist/lotamePanoramaIdSystem.js +1 -1
- package/dist/magniteAnalyticsAdapter.js +1 -0
- package/dist/malltvAnalyticsAdapter.js +1 -1
- package/dist/marsmediaAnalyticsAdapter.js +1 -1
- package/dist/marsmediaBidAdapter.js +1 -1
- package/dist/mass.js +1 -1
- package/dist/mediafuseBidAdapter.js +1 -1
- package/dist/mediakeysBidAdapter.js +1 -1
- package/dist/medianetAnalyticsAdapter.js +1 -1
- package/dist/mediasquareBidAdapter.js +1 -1
- package/dist/mgidBidAdapter.js +1 -1
- package/dist/minutemediaBidAdapter.js +1 -1
- package/dist/multibid.js +1 -1
- package/dist/nativoBidAdapter.js +1 -1
- package/dist/not-for-prod/prebid.js +198 -194
- package/dist/oguryBidAdapter.js +1 -1
- package/dist/onetagBidAdapter.js +1 -1
- package/dist/ooloAnalyticsAdapter.js +1 -1
- package/dist/openxAnalyticsAdapter.js +1 -1
- package/dist/optimonAnalyticsAdapter.js +1 -1
- package/dist/outbrainBidAdapter.js +1 -1
- package/dist/parrableIdSystem.js +1 -1
- package/dist/pianoDmpAnalyticsAdapter.js +1 -1
- package/dist/pixfutureBidAdapter.js +1 -1
- package/dist/prebid-core.js +2 -2
- package/dist/prebidServerBidAdapter.js +1 -1
- package/dist/prebidmanagerAnalyticsAdapter.js +1 -1
- package/dist/priceFloors.js +1 -1
- package/dist/publinkIdSystem.js +1 -1
- package/dist/pubmaticAnalyticsAdapter.js +1 -1
- package/dist/pubmaticBidAdapter.js +1 -1
- package/dist/pubperfAnalyticsAdapter.js +1 -1
- package/dist/pubstackAnalyticsAdapter.js +1 -1
- package/dist/pubwiseAnalyticsAdapter.js +1 -1
- package/dist/pubxaiAnalyticsAdapter.js +1 -1
- package/dist/pulsepointAnalyticsAdapter.js +1 -1
- package/dist/pxyzBidAdapter.js +1 -1
- package/dist/quantcastBidAdapter.js +1 -1
- package/dist/quantcastIdSystem.js +1 -1
- package/dist/readpeakBidAdapter.js +1 -1
- package/dist/realvuAnalyticsAdapter.js +1 -1
- package/dist/relaidoBidAdapter.js +1 -1
- package/dist/relevantAnalyticsAdapter.js +1 -1
- package/dist/rhythmoneBidAdapter.js +1 -1
- package/dist/riseBidAdapter.js +1 -1
- package/dist/rivrAnalyticsAdapter.js +1 -1
- package/dist/roxotAnalyticsAdapter.js +1 -1
- package/dist/rtdModule.js +1 -1
- package/dist/rubiconAnalyticsAdapter.js +1 -1
- package/dist/rubiconBidAdapter.js +1 -1
- package/dist/s2sTesting.js +1 -1
- package/dist/scaleableAnalyticsAdapter.js +1 -1
- package/dist/schain.js +1 -1
- package/dist/seedingAllianceBidAdapter.js +1 -1
- package/dist/seedtagBidAdapter.js +1 -1
- package/dist/sharedIdSystem.js +1 -1
- package/dist/sharethroughAnalyticsAdapter.js +1 -1
- package/dist/sharethroughBidAdapter.js +1 -1
- package/dist/shinezBidAdapter.js +1 -1
- package/dist/sigmoidAnalyticsAdapter.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/sonobiAnalyticsAdapter.js +1 -1
- package/dist/sonobiBidAdapter.js +1 -1
- package/dist/sovrnAnalyticsAdapter.js +1 -1
- package/dist/sovrnBidAdapter.js +1 -1
- package/dist/sspBCBidAdapter.js +1 -1
- package/dist/staqAnalyticsAdapter.js +1 -1
- package/dist/sublimeBidAdapter.js +1 -1
- package/dist/synacormediaBidAdapter.js +1 -1
- package/dist/taboolaBidAdapter.js +1 -1
- package/dist/tapadIdSystem.js +1 -1
- package/dist/targetVideoBidAdapter.js +1 -1
- package/dist/teadsBidAdapter.js +1 -1
- package/dist/teadsIdSystem.js +1 -0
- package/dist/terceptAnalyticsAdapter.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/underdogmediaBidAdapter.js +1 -1
- package/dist/undertoneBidAdapter.js +1 -1
- package/dist/userId.js +1 -1
- package/dist/vidazooBidAdapter.js +1 -1
- package/dist/videobyteBidAdapter.js +1 -1
- package/dist/visxBidAdapter.js +1 -1
- package/dist/vrtcalBidAdapter.js +1 -1
- package/dist/vuukleBidAdapter.js +1 -1
- package/dist/weboramaRtdProvider.js +1 -1
- package/dist/widespaceBidAdapter.js +1 -1
- package/dist/winrBidAdapter.js +1 -1
- package/dist/yahoosspBidAdapter.js +1 -1
- package/dist/yandexBidAdapter.js +1 -1
- package/dist/yieldmoBidAdapter.js +1 -1
- package/dist/yieldoneAnalyticsAdapter.js +1 -1
- package/dist/yuktamediaAnalyticsAdapter.js +1 -1
- package/dist/zeta_global_sspAnalyticsAdapter.js +1 -1
- package/libraries/fpd/sua.js +98 -0
- package/modules/.submodules.json +1 -0
- package/modules/adfBidAdapter.js +1 -1
- package/modules/adkernelAdnBidAdapter.js +1 -0
- package/modules/adkernelBidAdapter.js +2 -2
- package/modules/adqueryIdSystem.js +8 -8
- package/modules/adxcgBidAdapter.js +1 -1
- package/modules/amxBidAdapter.js +1 -1
- package/modules/aolBidAdapter.js +25 -2
- package/modules/appnexusBidAdapter.js +19 -2
- package/modules/{andBeyondMediaBidAdapter.js → beyondmediaBidAdapter.js} +0 -0
- package/modules/{andBeyondMediaBidAdapter.md → beyondmediaBidAdapter.md} +1 -1
- package/modules/categoryTranslation.js +4 -4
- package/modules/cleanioRtdProvider.js +3 -4
- package/modules/colossussspBidAdapter.js +2 -1
- package/modules/connectIdSystem.js +16 -1
- package/modules/conversantAnalyticsAdapter.js +560 -0
- package/modules/conversantAnalyticsAdapter.md +47 -0
- package/modules/criteoBidAdapter.js +1 -1
- package/modules/currency.js +11 -11
- package/modules/dchain.js +2 -2
- package/modules/debugging/bidInterceptor.js +2 -2
- package/modules/debugging/debugging.js +10 -2
- package/modules/debugging/legacy.js +2 -2
- package/modules/dgkeywordRtdProvider.js +21 -3
- package/modules/dianomiBidAdapter.js +1 -1
- package/modules/enrichmentFpdModule.js +33 -14
- package/modules/eplanningBidAdapter.js +48 -2
- package/modules/finativeBidAdapter.js +1 -1
- package/modules/gridBidAdapter.js +187 -117
- package/modules/improvedigitalBidAdapter.js +2 -2
- package/modules/ixBidAdapter.js +94 -23
- package/modules/liveIntentIdSystem.js +39 -5
- package/modules/lotamePanoramaIdSystem.js +10 -6
- package/modules/magniteAnalyticsAdapter.js +902 -0
- package/modules/magniteAnalyticsAdapter.md +18 -0
- package/modules/mass.js +2 -2
- package/modules/mediakeysBidAdapter.js +6 -1
- package/modules/mediakeysBidAdapter.md +50 -40
- package/modules/multibid/index.js +5 -5
- package/modules/nativoBidAdapter.js +1 -1
- package/modules/pixfutureBidAdapter.js +46 -15
- package/modules/prebidServerBidAdapter/index.js +54 -19
- package/modules/priceFloors.js +8 -22
- package/modules/readpeakBidAdapter.js +1 -1
- package/modules/rubiconAnalyticsAdapter.js +14 -9
- package/modules/rubiconBidAdapter.js +2 -3
- package/modules/seedingAllianceBidAdapter.js +1 -1
- package/modules/sharethroughBidAdapter.js +1 -1
- package/modules/taboolaBidAdapter.js +5 -5
- package/modules/talkadsBidAdapter.js +1 -0
- package/modules/teadsIdSystem.js +234 -0
- package/modules/teadsIdSystem.md +22 -0
- package/modules/truereachBidAdapter.js +1 -0
- package/modules/ttdBidAdapter.js +1 -1
- package/modules/userId/index.js +21 -14
- package/modules/vrtcalBidAdapter.js +7 -1
- package/modules/vuukleBidAdapter.js +34 -3
- package/modules/yahoosspBidAdapter.js +4 -2
- package/modules/yandexBidAdapter.js +31 -8
- package/package.json +2 -2
- package/src/adapterManager.js +2 -4
- package/src/adapters/bidderFactory.js +13 -11
- package/src/auction.js +140 -69
- package/src/constants.json +8 -0
- package/src/cpmBucketManager.js +22 -3
- package/src/native.js +1 -5
- package/src/prebid.js +5 -6
- package/src/targeting.js +31 -14
- package/test/fixtures/fixtures.js +2 -1
- package/test/spec/auctionmanager_spec.js +109 -21
- package/test/spec/cpmBucketManager_spec.js +239 -177
- package/test/spec/fpd/sua_spec.js +244 -0
- package/test/spec/modules/adfBidAdapter_spec.js +2 -3
- package/test/spec/modules/adqueryIdSystem_spec.js +0 -2
- package/test/spec/modules/adxcgBidAdapter_spec.js +2 -3
- package/test/spec/modules/amxBidAdapter_spec.js +3 -2
- package/test/spec/modules/aolBidAdapter_spec.js +42 -9
- package/test/spec/modules/appnexusBidAdapter_spec.js +24 -0
- package/test/spec/modules/{andBeyondMediaBidAdapter_spec.js → beyondmediaBidAdapter_spec.js} +1 -1
- package/test/spec/modules/colossussspBidAdapter_spec.js +4 -2
- package/test/spec/modules/connectIdSystem_spec.js +20 -0
- package/test/spec/modules/conversantAnalyticsAdapter_spec.js +963 -0
- package/test/spec/modules/currency_spec.js +14 -6
- package/test/spec/modules/debugging_mod_spec.js +9 -0
- package/test/spec/modules/dgkeywordRtdProvider_spec.js +83 -1
- package/test/spec/modules/dianomiBidAdapter_spec.js +2 -3
- package/test/spec/modules/enrichmentFpdModule_spec.js +50 -7
- package/test/spec/modules/eplanningBidAdapter_spec.js +285 -1
- package/test/spec/modules/fpdModule_spec.js +9 -0
- package/test/spec/modules/gridBidAdapter_spec.js +87 -31
- package/test/spec/modules/ixBidAdapter_spec.js +221 -2
- package/test/spec/modules/liveIntentIdMinimalSystem_spec.js +62 -8
- package/test/spec/modules/liveIntentIdSystem_spec.js +62 -8
- package/test/spec/modules/lotamePanoramaIdSystem_spec.js +0 -1
- package/test/spec/modules/magniteAnalyticsAdapter_spec.js +1942 -0
- package/test/spec/modules/mediakeysBidAdapter_spec.js +20 -3
- package/test/spec/modules/nativoBidAdapter_spec.js +13 -2
- package/test/spec/modules/prebidServerBidAdapter_spec.js +202 -15
- package/test/spec/modules/priceFloors_spec.js +5 -5
- package/test/spec/modules/rubiconAnalyticsAdapter_spec.js +2 -3
- package/test/spec/modules/seedtagBidAdapter_spec.js +15 -18
- package/test/spec/modules/sharethroughBidAdapter_spec.js +2 -1
- package/test/spec/modules/taboolaBidAdapter_spec.js +112 -13
- package/test/spec/modules/teadsIdSystem_spec.js +271 -0
- package/test/spec/modules/ttdBidAdapter_spec.js +3 -3
- package/test/spec/modules/userId_spec.js +39 -4
- package/test/spec/modules/vrtcalBidAdapter_spec.js +12 -1
- package/test/spec/modules/vuukleBidAdapter_spec.js +87 -0
- package/test/spec/modules/yahoosspBidAdapter_spec.js +48 -1
- package/test/spec/modules/yandexBidAdapter_spec.js +8 -5
- package/test/spec/native_spec.js +5 -0
- package/test/spec/unit/core/bidderFactory_spec.js +66 -11
- package/test/spec/unit/core/targeting_spec.js +28 -9
- package/test/spec/unit/pbjs_api_spec.js +48 -2
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
import { generateUUID, mergeDeep, deepAccess, parseUrl, logError, pick, isEmpty, logWarn, debugTurnedOn, parseQS, getWindowLocation, isAdUnitCodeMatchingSlot, isNumber, deepSetValue, deepClone, logInfo, isGptPubadsDefined } from '../src/utils.js';
|
|
2
|
+
import adapter from '../libraries/analyticsAdapter/AnalyticsAdapter.js';
|
|
3
|
+
import adapterManager from '../src/adapterManager.js';
|
|
4
|
+
import CONSTANTS from '../src/constants.json';
|
|
5
|
+
import { ajax } from '../src/ajax.js';
|
|
6
|
+
import { config } from '../src/config.js';
|
|
7
|
+
import { getGlobal } from '../src/prebidGlobal.js';
|
|
8
|
+
import { getStorageManager } from '../src/storageManager.js';
|
|
9
|
+
|
|
10
|
+
const RUBICON_GVL_ID = 52;
|
|
11
|
+
export const storage = getStorageManager({ gvlid: RUBICON_GVL_ID, moduleName: 'magnite' });
|
|
12
|
+
const COOKIE_NAME = 'mgniSession';
|
|
13
|
+
const LAST_SEEN_EXPIRE_TIME = 1800000; // 30 mins
|
|
14
|
+
const END_EXPIRE_TIME = 21600000; // 6 hours
|
|
15
|
+
const MODULE_NAME = 'Magnite Analytics';
|
|
16
|
+
const BID_REJECTED_IPF = 'rejected-ipf';
|
|
17
|
+
|
|
18
|
+
// List of known rubicon aliases
|
|
19
|
+
// This gets updated on auction init to account for any custom aliases present
|
|
20
|
+
let rubiconAliases = ['rubicon'];
|
|
21
|
+
|
|
22
|
+
const pbsErrorMap = {
|
|
23
|
+
1: 'timeout-error',
|
|
24
|
+
2: 'input-error',
|
|
25
|
+
3: 'connect-error',
|
|
26
|
+
4: 'request-error',
|
|
27
|
+
999: 'generic-error'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let prebidGlobal = getGlobal();
|
|
31
|
+
const {
|
|
32
|
+
EVENTS: {
|
|
33
|
+
AUCTION_INIT,
|
|
34
|
+
AUCTION_END,
|
|
35
|
+
BID_REQUESTED,
|
|
36
|
+
BID_RESPONSE,
|
|
37
|
+
BIDDER_DONE,
|
|
38
|
+
BID_TIMEOUT,
|
|
39
|
+
BID_WON,
|
|
40
|
+
BILLABLE_EVENT
|
|
41
|
+
},
|
|
42
|
+
STATUS: {
|
|
43
|
+
GOOD,
|
|
44
|
+
NO_BID
|
|
45
|
+
},
|
|
46
|
+
BID_STATUS: {
|
|
47
|
+
BID_REJECTED
|
|
48
|
+
}
|
|
49
|
+
} = CONSTANTS;
|
|
50
|
+
|
|
51
|
+
// The saved state of rubicon specific setConfig controls
|
|
52
|
+
export let rubiConf;
|
|
53
|
+
// Saving state of all our data we want
|
|
54
|
+
let cache;
|
|
55
|
+
const resetConfs = () => {
|
|
56
|
+
cache = {
|
|
57
|
+
auctions: {},
|
|
58
|
+
auctionOrder: [],
|
|
59
|
+
timeouts: {},
|
|
60
|
+
billing: {},
|
|
61
|
+
pendingEvents: {},
|
|
62
|
+
eventPending: false,
|
|
63
|
+
elementIdMap: {},
|
|
64
|
+
sessionData: {}
|
|
65
|
+
}
|
|
66
|
+
rubiConf = {
|
|
67
|
+
pvid: generateUUID().slice(0, 8),
|
|
68
|
+
analyticsEventDelay: 500,
|
|
69
|
+
analyticsBatchTimeout: 5000,
|
|
70
|
+
analyticsProcessDelay: 1,
|
|
71
|
+
dmBilling: {
|
|
72
|
+
enabled: false,
|
|
73
|
+
vendors: [],
|
|
74
|
+
waitForAuction: true
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
resetConfs();
|
|
79
|
+
|
|
80
|
+
config.getConfig('rubicon', config => {
|
|
81
|
+
mergeDeep(rubiConf, config.rubicon);
|
|
82
|
+
if (deepAccess(config, 'rubicon.updatePageView') === true) {
|
|
83
|
+
rubiConf.pvid = generateUUID().slice(0, 8)
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// pbs confs
|
|
88
|
+
let serverConfig;
|
|
89
|
+
config.getConfig('s2sConfig', ({ s2sConfig }) => {
|
|
90
|
+
serverConfig = s2sConfig;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const DEFAULT_INTEGRATION = 'pbjs';
|
|
94
|
+
|
|
95
|
+
const adUnitIsOnlyInstream = adUnit => {
|
|
96
|
+
return adUnit.mediaTypes && Object.keys(adUnit.mediaTypes).length === 1 && deepAccess(adUnit, 'mediaTypes.video.context') === 'instream';
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const sendPendingEvents = () => {
|
|
100
|
+
cache.pendingEvents.trigger = `batched-${Object.keys(cache.pendingEvents).sort().join('-')}`;
|
|
101
|
+
sendEvent(cache.pendingEvents);
|
|
102
|
+
cache.pendingEvents = {};
|
|
103
|
+
cache.eventPending = false;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const addEventToQueue = (event, auctionId, eventName) => {
|
|
107
|
+
// If it's auction has not left yet, add it there
|
|
108
|
+
if (cache.auctions[auctionId] && !cache.auctions[auctionId].sent) {
|
|
109
|
+
cache.auctions[auctionId].pendingEvents = mergeDeep(cache.auctions[auctionId].pendingEvents, event);
|
|
110
|
+
} else if (rubiConf.analyticsEventDelay > 0) {
|
|
111
|
+
// else if we are trying to batch stuff up, add it to pending events to be fired
|
|
112
|
+
cache.pendingEvents = mergeDeep(cache.pendingEvents, event);
|
|
113
|
+
|
|
114
|
+
// If no event is pending yet, start a timer for them to be sent and attempted to be gathered together
|
|
115
|
+
if (!cache.eventPending) {
|
|
116
|
+
setTimeout(sendPendingEvents, rubiConf.analyticsEventDelay);
|
|
117
|
+
cache.eventPending = true;
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
// else - send it solo
|
|
121
|
+
event.trigger = `solo-${eventName}`;
|
|
122
|
+
sendEvent(event);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const sendEvent = payload => {
|
|
127
|
+
const event = {
|
|
128
|
+
...getTopLevelDetails(),
|
|
129
|
+
...payload
|
|
130
|
+
}
|
|
131
|
+
ajax(
|
|
132
|
+
endpoint,
|
|
133
|
+
null,
|
|
134
|
+
JSON.stringify(event),
|
|
135
|
+
{
|
|
136
|
+
contentType: 'application/json'
|
|
137
|
+
}
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const sendAuctionEvent = (auctionId, trigger) => {
|
|
142
|
+
let auctionCache = cache.auctions[auctionId];
|
|
143
|
+
const auctionEvent = formatAuction(auctionCache.auction);
|
|
144
|
+
|
|
145
|
+
auctionCache.sent = true;
|
|
146
|
+
sendEvent({
|
|
147
|
+
auctions: [auctionEvent],
|
|
148
|
+
...(auctionCache.pendingEvents || {}), // if any pending events were attached
|
|
149
|
+
trigger
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const formatAuction = auction => {
|
|
154
|
+
const auctionEvent = deepClone(auction);
|
|
155
|
+
|
|
156
|
+
auctionEvent.samplingFactor = 1;
|
|
157
|
+
|
|
158
|
+
// We stored adUnits and bids as objects for quick lookups, now they are mapped into arrays for PBA
|
|
159
|
+
auctionEvent.adUnits = Object.entries(auctionEvent.adUnits).map(([tid, adUnit]) => {
|
|
160
|
+
adUnit.bids = Object.entries(adUnit.bids).map(([bidId, bid]) => {
|
|
161
|
+
// determine adUnit.status from its bid statuses. Use priority below to determine, higher index is better
|
|
162
|
+
let statusPriority = ['error', 'no-bid', 'success'];
|
|
163
|
+
if (statusPriority.indexOf(bid.status) > statusPriority.indexOf(adUnit.status)) {
|
|
164
|
+
adUnit.status = bid.status;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// If PBS told us to overwrite the bid ID, do so
|
|
168
|
+
if (bid.pbsBidId) {
|
|
169
|
+
bid.oldBidId = bid.bidId;
|
|
170
|
+
bid.bidId = bid.pbsBidId;
|
|
171
|
+
delete bid.pbsBidId;
|
|
172
|
+
}
|
|
173
|
+
return bid;
|
|
174
|
+
});
|
|
175
|
+
return adUnit;
|
|
176
|
+
});
|
|
177
|
+
return auctionEvent;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const isBillingEventValid = event => {
|
|
181
|
+
// vendor is whitelisted
|
|
182
|
+
const isWhitelistedVendor = rubiConf.dmBilling.vendors.includes(event.vendor);
|
|
183
|
+
// event is not duplicated
|
|
184
|
+
const isNotDuplicate = typeof deepAccess(cache.billing, `${event.vendor}.${event.billingId}`) !== 'boolean';
|
|
185
|
+
// billingId is defined and a string
|
|
186
|
+
return typeof event.billingId === 'string' && isWhitelistedVendor && isNotDuplicate;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const formatBillingEvent = event => {
|
|
190
|
+
let billingEvent = deepClone(event);
|
|
191
|
+
// Pass along type if is string and not empty else general
|
|
192
|
+
billingEvent.type = (typeof event.type === 'string' && event.type) || 'general';
|
|
193
|
+
billingEvent.accountId = accountId;
|
|
194
|
+
// mark as sent
|
|
195
|
+
deepSetValue(cache.billing, `${event.vendor}.${event.billingId}`, true);
|
|
196
|
+
return billingEvent;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const getBidPrice = bid => {
|
|
200
|
+
// get the cpm from bidResponse
|
|
201
|
+
let cpm;
|
|
202
|
+
let currency;
|
|
203
|
+
if (bid.status === BID_REJECTED && typeof deepAccess(bid, 'floorData.cpmAfterAdjustments') === 'number') {
|
|
204
|
+
// if bid was rejected and bid.floorData.cpmAfterAdjustments use it
|
|
205
|
+
cpm = bid.floorData.cpmAfterAdjustments;
|
|
206
|
+
currency = bid.floorData.floorCurrency;
|
|
207
|
+
} else if (typeof bid.currency === 'string' && bid.currency.toUpperCase() === 'USD') {
|
|
208
|
+
// bid is in USD use it
|
|
209
|
+
return Number(bid.cpm);
|
|
210
|
+
} else {
|
|
211
|
+
// else grab cpm
|
|
212
|
+
cpm = bid.cpm;
|
|
213
|
+
currency = bid.currency;
|
|
214
|
+
}
|
|
215
|
+
// if after this it is still going and is USD then return it.
|
|
216
|
+
if (currency === 'USD') {
|
|
217
|
+
return Number(cpm);
|
|
218
|
+
}
|
|
219
|
+
// otherwise we convert and return
|
|
220
|
+
try {
|
|
221
|
+
return Number(prebidGlobal.convertCurrency(cpm, currency, 'USD'));
|
|
222
|
+
} catch (err) {
|
|
223
|
+
logWarn(`${MODULE_NAME}: Could not determine the bidPriceUSD of the bid `, bid);
|
|
224
|
+
bid.conversionError = true;
|
|
225
|
+
bid.ogCurrency = currency;
|
|
226
|
+
bid.ogPrice = cpm;
|
|
227
|
+
return 0;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
export const parseBidResponse = (bid, previousBidResponse) => {
|
|
232
|
+
// The current bidResponse for this matching requestId/bidRequestId
|
|
233
|
+
let responsePrice = getBidPrice(bid)
|
|
234
|
+
// we need to compare it with the previous one (if there was one) log highest only
|
|
235
|
+
// THIS WILL CHANGE WITH ALLOWING MULTIBID BETTER
|
|
236
|
+
if (previousBidResponse && previousBidResponse.bidPriceUSD > responsePrice) {
|
|
237
|
+
return previousBidResponse;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return pick(bid, [
|
|
241
|
+
'bidPriceUSD', () => responsePrice,
|
|
242
|
+
'dealId', dealId => dealId || undefined,
|
|
243
|
+
'mediaType',
|
|
244
|
+
'dimensions', () => {
|
|
245
|
+
const width = bid.width || bid.playerWidth;
|
|
246
|
+
const height = bid.height || bid.playerHeight;
|
|
247
|
+
return (width && height) ? { width, height } : undefined;
|
|
248
|
+
},
|
|
249
|
+
'floorValue', () => deepAccess(bid, 'floorData.floorValue'),
|
|
250
|
+
'floorRuleValue', () => deepAccess(bid, 'floorData.floorRuleValue'),
|
|
251
|
+
'floorRule', () => debugTurnedOn() ? deepAccess(bid, 'floorData.floorRule') : undefined,
|
|
252
|
+
'adomains', () => {
|
|
253
|
+
const adomains = deepAccess(bid, 'meta.advertiserDomains');
|
|
254
|
+
const validAdomains = Array.isArray(adomains) && adomains.filter(domain => typeof domain === 'string');
|
|
255
|
+
return validAdomains && validAdomains.length > 0 ? validAdomains.slice(0, 10) : undefined
|
|
256
|
+
},
|
|
257
|
+
'conversionError', conversionError => conversionError === true || undefined, // only pass if exactly true
|
|
258
|
+
'ogCurrency',
|
|
259
|
+
'ogPrice'
|
|
260
|
+
]);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
const addFloorData = floorData => {
|
|
264
|
+
if (floorData.location === 'noData') {
|
|
265
|
+
return pick(floorData, [
|
|
266
|
+
'location',
|
|
267
|
+
'fetchStatus',
|
|
268
|
+
'floorProvider as provider'
|
|
269
|
+
]);
|
|
270
|
+
} else {
|
|
271
|
+
return pick(floorData, [
|
|
272
|
+
'location',
|
|
273
|
+
'modelVersion as modelName',
|
|
274
|
+
'modelWeight',
|
|
275
|
+
'modelTimestamp',
|
|
276
|
+
'skipped',
|
|
277
|
+
'enforcement', () => deepAccess(floorData, 'enforcements.enforceJS'),
|
|
278
|
+
'dealsEnforced', () => deepAccess(floorData, 'enforcements.floorDeals'),
|
|
279
|
+
'skipRate',
|
|
280
|
+
'fetchStatus',
|
|
281
|
+
'floorMin',
|
|
282
|
+
'floorProvider as provider'
|
|
283
|
+
]);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
let pageReferer;
|
|
288
|
+
|
|
289
|
+
const getTopLevelDetails = () => {
|
|
290
|
+
let payload = {
|
|
291
|
+
channel: 'web',
|
|
292
|
+
integration: rubiConf.int_type || DEFAULT_INTEGRATION,
|
|
293
|
+
referrerUri: pageReferer,
|
|
294
|
+
version: '$prebid.version$',
|
|
295
|
+
referrerHostname: magniteAdapter.referrerHostname || getHostNameFromReferer(pageReferer),
|
|
296
|
+
timestamps: {
|
|
297
|
+
timeSincePageLoad: performance.now(),
|
|
298
|
+
eventTime: Date.now(),
|
|
299
|
+
prebidLoaded: magniteAdapter.MODULE_INITIALIZED_TIME
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// Add DM wrapper details
|
|
304
|
+
if (rubiConf.wrapperName) {
|
|
305
|
+
payload.wrapper = {
|
|
306
|
+
name: rubiConf.wrapperName,
|
|
307
|
+
family: rubiConf.wrapperFamily,
|
|
308
|
+
rule: rubiConf.rule_name
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (cache.sessionData) {
|
|
313
|
+
// gather session info
|
|
314
|
+
payload.session = pick(cache.sessionData, [
|
|
315
|
+
'id',
|
|
316
|
+
'pvid',
|
|
317
|
+
'start',
|
|
318
|
+
'expires'
|
|
319
|
+
]);
|
|
320
|
+
// Any FPKVS set?
|
|
321
|
+
if (!isEmpty(cache.sessionData.fpkvs)) {
|
|
322
|
+
payload.fpkvs = Object.keys(cache.sessionData.fpkvs).map(key => {
|
|
323
|
+
return { key, value: cache.sessionData.fpkvs[key] };
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
return payload;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
export const getHostNameFromReferer = referer => {
|
|
331
|
+
try {
|
|
332
|
+
magniteAdapter.referrerHostname = parseUrl(referer, { noDecodeWholeURL: true }).hostname;
|
|
333
|
+
} catch (e) {
|
|
334
|
+
logError(`${MODULE_NAME}: Unable to parse hostname from supplied url: `, referer, e);
|
|
335
|
+
magniteAdapter.referrerHostname = '';
|
|
336
|
+
}
|
|
337
|
+
return magniteAdapter.referrerHostname
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
const getRpaCookie = () => {
|
|
341
|
+
let encodedCookie = storage.getDataFromLocalStorage(COOKIE_NAME);
|
|
342
|
+
if (encodedCookie) {
|
|
343
|
+
try {
|
|
344
|
+
return JSON.parse(window.atob(encodedCookie));
|
|
345
|
+
} catch (e) {
|
|
346
|
+
logError(`${MODULE_NAME}: Unable to decode ${COOKIE_NAME} value: `, e);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
return {};
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
const setRpaCookie = (decodedCookie) => {
|
|
353
|
+
try {
|
|
354
|
+
storage.setDataInLocalStorage(COOKIE_NAME, window.btoa(JSON.stringify(decodedCookie)));
|
|
355
|
+
} catch (e) {
|
|
356
|
+
logError(`${MODULE_NAME}: Unable to encode ${COOKIE_NAME} value: `, e);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
const updateRpaCookie = () => {
|
|
361
|
+
const currentTime = Date.now();
|
|
362
|
+
let decodedRpaCookie = getRpaCookie();
|
|
363
|
+
if (
|
|
364
|
+
!Object.keys(decodedRpaCookie).length ||
|
|
365
|
+
(currentTime - decodedRpaCookie.lastSeen) > LAST_SEEN_EXPIRE_TIME ||
|
|
366
|
+
decodedRpaCookie.expires < currentTime
|
|
367
|
+
) {
|
|
368
|
+
decodedRpaCookie = {
|
|
369
|
+
id: generateUUID(),
|
|
370
|
+
start: currentTime,
|
|
371
|
+
expires: currentTime + END_EXPIRE_TIME, // six hours later,
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
// possible that decodedRpaCookie is undefined, and if it is, we probably are blocked by storage or some other exception
|
|
375
|
+
if (Object.keys(decodedRpaCookie).length) {
|
|
376
|
+
decodedRpaCookie.lastSeen = currentTime;
|
|
377
|
+
decodedRpaCookie.fpkvs = { ...decodedRpaCookie.fpkvs, ...getFpkvs() };
|
|
378
|
+
decodedRpaCookie.pvid = rubiConf.pvid;
|
|
379
|
+
setRpaCookie(decodedRpaCookie)
|
|
380
|
+
}
|
|
381
|
+
return decodedRpaCookie;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/*
|
|
385
|
+
Filters and converts URL Params into an object and returns only KVs that match the 'utm_KEY' format
|
|
386
|
+
*/
|
|
387
|
+
const getUtmParams = () => {
|
|
388
|
+
let search;
|
|
389
|
+
|
|
390
|
+
try {
|
|
391
|
+
search = parseQS(getWindowLocation().search);
|
|
392
|
+
} catch (e) {
|
|
393
|
+
search = {};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
return Object.keys(search).reduce((accum, param) => {
|
|
397
|
+
if (param.match(/utm_/)) {
|
|
398
|
+
accum[param.replace(/utm_/, '')] = search[param];
|
|
399
|
+
}
|
|
400
|
+
return accum;
|
|
401
|
+
}, {});
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const getFpkvs = () => {
|
|
405
|
+
rubiConf.fpkvs = Object.assign((rubiConf.fpkvs || {}), getUtmParams());
|
|
406
|
+
|
|
407
|
+
// convert all values to strings
|
|
408
|
+
Object.keys(rubiConf.fpkvs).forEach(key => {
|
|
409
|
+
rubiConf.fpkvs[key] = rubiConf.fpkvs[key] + '';
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
return rubiConf.fpkvs;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/*
|
|
416
|
+
Checks the alias registry for any entries of the rubicon bid adapter.
|
|
417
|
+
adds to the rubiconAliases list if found
|
|
418
|
+
*/
|
|
419
|
+
const setRubiconAliases = (aliasRegistry) => {
|
|
420
|
+
const otherAliases = Object.keys(aliasRegistry).filter(alias => aliasRegistry[alias] === 'rubicon');
|
|
421
|
+
rubiconAliases.push(...otherAliases);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const sizeToDimensions = size => {
|
|
425
|
+
return {
|
|
426
|
+
width: size.w || size[0],
|
|
427
|
+
height: size.h || size[1]
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const findMatchingAdUnitFromAuctions = (matchesFunction, returnFirstMatch) => {
|
|
432
|
+
// finding matching adUnit / auction
|
|
433
|
+
let matches = {};
|
|
434
|
+
|
|
435
|
+
// loop through auctions in order and adunits
|
|
436
|
+
for (const auctionId of cache.auctionOrder) {
|
|
437
|
+
const auction = cache.auctions[auctionId].auction;
|
|
438
|
+
for (const transactionId in auction.adUnits) {
|
|
439
|
+
const adUnit = auction.adUnits[transactionId];
|
|
440
|
+
|
|
441
|
+
// check if this matches
|
|
442
|
+
let doesMatch;
|
|
443
|
+
try {
|
|
444
|
+
doesMatch = matchesFunction(adUnit, auction);
|
|
445
|
+
} catch (error) {
|
|
446
|
+
logWarn(`${MODULE_NAME}: Error running matches function: ${returnFirstMatch}`, error);
|
|
447
|
+
doesMatch = false;
|
|
448
|
+
}
|
|
449
|
+
if (doesMatch) {
|
|
450
|
+
matches = { adUnit, auction };
|
|
451
|
+
|
|
452
|
+
// we either return first match or we want last one matching so go to end
|
|
453
|
+
if (returnFirstMatch) return matches;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
return matches;
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
const getRenderingIds = bidWonData => {
|
|
461
|
+
// if bid caching off -> return the bidWon auction id
|
|
462
|
+
if (!config.getConfig('useBidCache')) {
|
|
463
|
+
return {
|
|
464
|
+
renderTransactionId: bidWonData.transactionId,
|
|
465
|
+
renderAuctionId: bidWonData.auctionId
|
|
466
|
+
};
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
// a rendering auction id is the LATEST auction / adunit which contains GAM ID's
|
|
470
|
+
const matchingFunction = (adUnit, auction) => {
|
|
471
|
+
// does adUnit match our bidWon and gam id's are present
|
|
472
|
+
const gamHasRendered = deepAccess(cache, `auctions.${auction.auctionId}.gamRenders.${adUnit.transactionId}`);
|
|
473
|
+
return adUnit.adUnitCode === bidWonData.adUnitCode && gamHasRendered;
|
|
474
|
+
}
|
|
475
|
+
let { adUnit, auction } = findMatchingAdUnitFromAuctions(matchingFunction, false);
|
|
476
|
+
// If no match was found, we will use the actual bid won auction id
|
|
477
|
+
return {
|
|
478
|
+
renderTransactionId: (adUnit && adUnit.transactionId) || bidWonData.transactionId,
|
|
479
|
+
renderAuctionId: (auction && auction.auctionId) || bidWonData.auctionId
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const formatBidWon = bidWonData => {
|
|
484
|
+
// get transaction and auction id of where this "rendered"
|
|
485
|
+
const { renderTransactionId, renderAuctionId } = getRenderingIds(bidWonData);
|
|
486
|
+
|
|
487
|
+
const isCachedBid = renderTransactionId !== bidWonData.transactionId;
|
|
488
|
+
logInfo(`${MODULE_NAME}: Bid Won : `, {
|
|
489
|
+
isCachedBid,
|
|
490
|
+
renderAuctionId,
|
|
491
|
+
renderTransactionId,
|
|
492
|
+
sourceAuctionId: bidWonData.auctionId,
|
|
493
|
+
sourceTransactionId: bidWonData.transactionId,
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
// get the bid from the source auction id
|
|
497
|
+
let bid = deepAccess(cache, `auctions.${bidWonData.auctionId}.auction.adUnits.${bidWonData.transactionId}.bids.${bidWonData.requestId}`);
|
|
498
|
+
let adUnit = deepAccess(cache, `auctions.${bidWonData.auctionId}.auction.adUnits.${bidWonData.transactionId}`);
|
|
499
|
+
let bidWon = {
|
|
500
|
+
...bid,
|
|
501
|
+
sourceAuctionId: bidWonData.auctionId,
|
|
502
|
+
renderAuctionId,
|
|
503
|
+
transactionId: bidWonData.transactionId,
|
|
504
|
+
sourceTransactionId: bidWonData.transactionId,
|
|
505
|
+
bidId: bid.pbsBidId || bidWonData.bidId || bidWonData.requestId, // if PBS had us overwrite bidId, use that as signal
|
|
506
|
+
renderTransactionId,
|
|
507
|
+
accountId,
|
|
508
|
+
siteId: adUnit.siteId,
|
|
509
|
+
zoneId: adUnit.zoneId,
|
|
510
|
+
mediaTypes: adUnit.mediaTypes,
|
|
511
|
+
adUnitCode: adUnit.adUnitCode,
|
|
512
|
+
isCachedBid: isCachedBid || undefined // only send if it is true (save some space)
|
|
513
|
+
}
|
|
514
|
+
delete bidWon.pbsBidId; // if pbsBidId is there delete it (no need to pass it)
|
|
515
|
+
return bidWon;
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
const formatGamEvent = (slotEvent, adUnit, auction) => {
|
|
519
|
+
const gamEvent = pick(slotEvent, [
|
|
520
|
+
// these come in as `null` from Gpt, which when stringified does not get removed
|
|
521
|
+
// so set explicitly to undefined when not a number
|
|
522
|
+
'advertiserId', advertiserId => isNumber(advertiserId) ? advertiserId : undefined,
|
|
523
|
+
'creativeId', creativeId => isNumber(slotEvent.sourceAgnosticCreativeId) ? slotEvent.sourceAgnosticCreativeId : isNumber(creativeId) ? creativeId : undefined,
|
|
524
|
+
'lineItemId', lineItemId => isNumber(slotEvent.sourceAgnosticLineItemId) ? slotEvent.sourceAgnosticLineItemId : isNumber(lineItemId) ? lineItemId : undefined,
|
|
525
|
+
'adSlot', () => slotEvent.slot.getAdUnitPath(),
|
|
526
|
+
'isSlotEmpty', () => slotEvent.isEmpty || undefined
|
|
527
|
+
]);
|
|
528
|
+
gamEvent.auctionId = auction.auctionId;
|
|
529
|
+
gamEvent.transactionId = adUnit.transactionId;
|
|
530
|
+
return gamEvent;
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
const subscribeToGamSlots = () => {
|
|
534
|
+
window.googletag.pubads().addEventListener('slotRenderEnded', event => {
|
|
535
|
+
const isMatchingAdSlot = isAdUnitCodeMatchingSlot(event.slot);
|
|
536
|
+
|
|
537
|
+
// We want to find the FIRST auction - adUnit that matches and does not have gam data yet
|
|
538
|
+
const matchingFunction = (adUnit, auction) => {
|
|
539
|
+
// first it has to match the slot
|
|
540
|
+
// if the code is present in the elementIdMap then we use the matched id as code here
|
|
541
|
+
const elementIds = cache.elementIdMap[adUnit.adUnitCode] || [adUnit.adUnitCode];
|
|
542
|
+
const matchesSlot = elementIds.some(isMatchingAdSlot);
|
|
543
|
+
|
|
544
|
+
// next it has to have NOT already been counted as gam rendered
|
|
545
|
+
const gamHasRendered = deepAccess(cache, `auctions.${auction.auctionId}.gamRenders.${adUnit.transactionId}`);
|
|
546
|
+
return matchesSlot && !gamHasRendered;
|
|
547
|
+
}
|
|
548
|
+
let { adUnit, auction } = findMatchingAdUnitFromAuctions(matchingFunction, true);
|
|
549
|
+
|
|
550
|
+
const slotName = `${event.slot.getAdUnitPath()} - ${event.slot.getSlotElementId()}`;
|
|
551
|
+
|
|
552
|
+
if (!adUnit || !auction) {
|
|
553
|
+
logInfo(`${MODULE_NAME}: Could not find matching adUnit for Gam Render: `, {
|
|
554
|
+
slotName
|
|
555
|
+
});
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const auctionId = auction.auctionId;
|
|
559
|
+
|
|
560
|
+
logInfo(`${MODULE_NAME}: Gam Render: `, {
|
|
561
|
+
slotName,
|
|
562
|
+
transactionId: adUnit.transactionId,
|
|
563
|
+
auctionId: auctionId,
|
|
564
|
+
adUnit: adUnit,
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
// if we have an adunit, then we need to make a gam event
|
|
568
|
+
const gamEvent = formatGamEvent(event, adUnit, auction);
|
|
569
|
+
|
|
570
|
+
// marking that this prebid adunit has had its matching gam render found
|
|
571
|
+
deepSetValue(cache, `auctions.${auctionId}.gamRenders.${adUnit.transactionId}`, true);
|
|
572
|
+
|
|
573
|
+
addEventToQueue({ gamRenders: [gamEvent] }, auctionId, 'gam');
|
|
574
|
+
|
|
575
|
+
// If this auction now has all gam slots rendered, fire the payload
|
|
576
|
+
if (!cache.auctions[auctionId].sent && Object.keys(cache.auctions[auctionId].gamRenders).every(tid => cache.auctions[auctionId].gamRenders[tid])) {
|
|
577
|
+
// clear the auction end timeout
|
|
578
|
+
clearTimeout(cache.timeouts[auctionId]);
|
|
579
|
+
delete cache.timeouts[auctionId];
|
|
580
|
+
|
|
581
|
+
// wait for bid wons a bit or send right away
|
|
582
|
+
if (rubiConf.analyticsEventDelay > 0) {
|
|
583
|
+
setTimeout(() => {
|
|
584
|
+
sendAuctionEvent(auctionId, 'gam-delayed');
|
|
585
|
+
}, rubiConf.analyticsEventDelay);
|
|
586
|
+
} else {
|
|
587
|
+
sendAuctionEvent(auctionId, 'gam');
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
let accountId;
|
|
594
|
+
let endpoint;
|
|
595
|
+
|
|
596
|
+
let magniteAdapter = adapter({ analyticsType: 'endpoint' });
|
|
597
|
+
|
|
598
|
+
magniteAdapter.originEnableAnalytics = magniteAdapter.enableAnalytics;
|
|
599
|
+
function enableMgniAnalytics(config = {}) {
|
|
600
|
+
let error = false;
|
|
601
|
+
// endpoint
|
|
602
|
+
endpoint = deepAccess(config, 'options.endpoint');
|
|
603
|
+
if (!endpoint) {
|
|
604
|
+
logError(`${MODULE_NAME}: required endpoint missing`);
|
|
605
|
+
error = true;
|
|
606
|
+
}
|
|
607
|
+
// accountId
|
|
608
|
+
accountId = Number(deepAccess(config, 'options.accountId'));
|
|
609
|
+
if (!accountId) {
|
|
610
|
+
logError(`${MODULE_NAME}: required accountId missing`);
|
|
611
|
+
error = true;
|
|
612
|
+
}
|
|
613
|
+
if (!error) {
|
|
614
|
+
magniteAdapter.originEnableAnalytics(config);
|
|
615
|
+
}
|
|
616
|
+
// listen to gam slot renders!
|
|
617
|
+
if (isGptPubadsDefined()) {
|
|
618
|
+
subscribeToGamSlots();
|
|
619
|
+
} else {
|
|
620
|
+
window.googletag = window.googletag || {};
|
|
621
|
+
window.googletag.cmd = window.googletag.cmd || [];
|
|
622
|
+
window.googletag.cmd.push(() => subscribeToGamSlots());
|
|
623
|
+
}
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
const handleBidWon = args => {
|
|
627
|
+
const bidWon = formatBidWon(args);
|
|
628
|
+
addEventToQueue({ bidsWon: [bidWon] }, bidWon.renderAuctionId, 'bidWon');
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
magniteAdapter.enableAnalytics = enableMgniAnalytics;
|
|
632
|
+
|
|
633
|
+
magniteAdapter.originDisableAnalytics = magniteAdapter.disableAnalytics;
|
|
634
|
+
magniteAdapter.disableAnalytics = function () {
|
|
635
|
+
// trick analytics module to register our enable back as main one
|
|
636
|
+
magniteAdapter._oldEnable = enableMgniAnalytics;
|
|
637
|
+
endpoint = undefined;
|
|
638
|
+
accountId = undefined;
|
|
639
|
+
resetConfs();
|
|
640
|
+
magniteAdapter.originDisableAnalytics();
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
magniteAdapter.MODULE_INITIALIZED_TIME = Date.now();
|
|
644
|
+
magniteAdapter.referrerHostname = '';
|
|
645
|
+
|
|
646
|
+
magniteAdapter.track = ({ eventType, args }) => {
|
|
647
|
+
switch (eventType) {
|
|
648
|
+
case AUCTION_INIT:
|
|
649
|
+
// Update session
|
|
650
|
+
cache.sessionData = storage.localStorageIsEnabled() && updateRpaCookie();
|
|
651
|
+
// set the rubicon aliases
|
|
652
|
+
setRubiconAliases(adapterManager.aliasRegistry);
|
|
653
|
+
|
|
654
|
+
// latest page "referer"
|
|
655
|
+
pageReferer = deepAccess(args, 'bidderRequests.0.refererInfo.page');
|
|
656
|
+
|
|
657
|
+
// set auction level data
|
|
658
|
+
let auctionData = pick(args, [
|
|
659
|
+
'auctionId',
|
|
660
|
+
'timestamp as auctionStart',
|
|
661
|
+
'timeout as clientTimeoutMillis',
|
|
662
|
+
]);
|
|
663
|
+
auctionData.accountId = accountId;
|
|
664
|
+
|
|
665
|
+
// Order bidders were called
|
|
666
|
+
auctionData.bidderOrder = args.bidderRequests.map(bidderRequest => bidderRequest.bidderCode);
|
|
667
|
+
|
|
668
|
+
// Price Floors information
|
|
669
|
+
const floorData = deepAccess(args, 'bidderRequests.0.bids.0.floorData');
|
|
670
|
+
if (floorData) {
|
|
671
|
+
auctionData.floors = addFloorData(floorData);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// GDPR info
|
|
675
|
+
const gdprData = deepAccess(args, 'bidderRequests.0.gdprConsent');
|
|
676
|
+
if (gdprData) {
|
|
677
|
+
auctionData.gdpr = pick(gdprData, [
|
|
678
|
+
'gdprApplies as applies',
|
|
679
|
+
'consentString',
|
|
680
|
+
'apiVersion as version'
|
|
681
|
+
]);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
// User ID Data included in auction
|
|
685
|
+
const userIds = Object.keys(deepAccess(args, 'bidderRequests.0.bids.0.userId', {})).map(id => {
|
|
686
|
+
return { provider: id, hasId: true }
|
|
687
|
+
});
|
|
688
|
+
if (userIds.length) {
|
|
689
|
+
auctionData.user = { ids: userIds };
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
if (serverConfig) {
|
|
693
|
+
auctionData.serverTimeoutMillis = serverConfig.timeout;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
// lets us keep a map of adunit and wether it had a gam or bid won render yet, used to track when to send events
|
|
697
|
+
let gamRenders = {};
|
|
698
|
+
// adunits saved as map of transactionIds
|
|
699
|
+
auctionData.adUnits = args.adUnits.reduce((adMap, adUnit) => {
|
|
700
|
+
let ad = pick(adUnit, [
|
|
701
|
+
'code as adUnitCode',
|
|
702
|
+
'transactionId',
|
|
703
|
+
'mediaTypes', mediaTypes => Object.keys(mediaTypes),
|
|
704
|
+
'sizes as dimensions', sizes => sizes.map(sizeToDimensions),
|
|
705
|
+
]);
|
|
706
|
+
ad.pbAdSlot = deepAccess(adUnit, 'ortb2Imp.ext.data.pbadslot');
|
|
707
|
+
ad.pattern = deepAccess(adUnit, 'ortb2Imp.ext.data.aupname');
|
|
708
|
+
ad.gpid = deepAccess(adUnit, 'ortb2Imp.ext.gpid');
|
|
709
|
+
ad.bids = {};
|
|
710
|
+
adMap[adUnit.transactionId] = ad;
|
|
711
|
+
gamRenders[adUnit.transactionId] = false;
|
|
712
|
+
|
|
713
|
+
// Handle case elementId's (div Id's) are set on adUnit - PPI
|
|
714
|
+
const elementIds = deepAccess(adUnit, 'ortb2Imp.ext.data.elementid');
|
|
715
|
+
if (elementIds) {
|
|
716
|
+
cache.elementIdMap[adUnit.code] = cache.elementIdMap[adUnit.code] || [];
|
|
717
|
+
// set it to array if set to string to be careful (should be array of strings)
|
|
718
|
+
const newIds = typeof elementIds === 'string' ? [elementIds] : elementIds;
|
|
719
|
+
newIds.forEach(id => {
|
|
720
|
+
if (!cache.elementIdMap[adUnit.code].includes(id)) {
|
|
721
|
+
cache.elementIdMap[adUnit.code].push(id);
|
|
722
|
+
}
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
return adMap;
|
|
726
|
+
}, {});
|
|
727
|
+
|
|
728
|
+
// holding our pba data to send
|
|
729
|
+
cache.auctions[args.auctionId] = {
|
|
730
|
+
auction: auctionData,
|
|
731
|
+
gamRenders,
|
|
732
|
+
pendingEvents: {}
|
|
733
|
+
}
|
|
734
|
+
break;
|
|
735
|
+
case BID_REQUESTED:
|
|
736
|
+
args.bids.forEach(bid => {
|
|
737
|
+
const adUnit = deepAccess(cache, `auctions.${args.auctionId}.auction.adUnits.${bid.transactionId}`);
|
|
738
|
+
adUnit.bids[bid.bidId] = pick(bid, [
|
|
739
|
+
'bidder',
|
|
740
|
+
'bidId',
|
|
741
|
+
'source', () => bid.src === 's2s' ? 'server' : 'client',
|
|
742
|
+
'status', () => 'no-bid'
|
|
743
|
+
]);
|
|
744
|
+
// set acct site zone id on adunit
|
|
745
|
+
if ((!adUnit.siteId || !adUnit.zoneId) && rubiconAliases.indexOf(bid.bidder) !== -1) {
|
|
746
|
+
if (deepAccess(bid, 'params.accountId') == accountId) {
|
|
747
|
+
adUnit.accountId = parseInt(accountId);
|
|
748
|
+
adUnit.siteId = parseInt(deepAccess(bid, 'params.siteId'));
|
|
749
|
+
adUnit.zoneId = parseInt(deepAccess(bid, 'params.zoneId'));
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
break;
|
|
754
|
+
case BID_RESPONSE:
|
|
755
|
+
const auctionEntry = deepAccess(cache, `auctions.${args.auctionId}.auction`);
|
|
756
|
+
const adUnit = deepAccess(auctionEntry, `adUnits.${args.transactionId}`);
|
|
757
|
+
let bid = adUnit.bids[args.requestId];
|
|
758
|
+
|
|
759
|
+
// if this came from multibid, there might now be matching bid, so check
|
|
760
|
+
// THIS logic will change when we support multibid per bid request
|
|
761
|
+
if (!bid && args.originalRequestId) {
|
|
762
|
+
let ogBid = adUnit.bids[args.originalRequestId];
|
|
763
|
+
// create new bid
|
|
764
|
+
adUnit.bids[args.requestId] = {
|
|
765
|
+
...ogBid,
|
|
766
|
+
bidId: args.requestId,
|
|
767
|
+
bidderDetail: args.targetingBidder
|
|
768
|
+
};
|
|
769
|
+
bid = adUnit.bids[args.requestId];
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// if we have not set enforcements yet set it (This is hidden from bidders until now so we have to get from here)
|
|
773
|
+
if (typeof deepAccess(auctionEntry, 'floors.enforcement') !== 'boolean' && deepAccess(args, 'floorData.enforcements')) {
|
|
774
|
+
auctionEntry.floors.enforcement = args.floorData.enforcements.enforceJS;
|
|
775
|
+
auctionEntry.floors.dealsEnforced = args.floorData.enforcements.floorDeals;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
// Log error if no matching bid!
|
|
779
|
+
if (!bid) {
|
|
780
|
+
logError(`${MODULE_NAME}: Could not find associated bid request for bid response with requestId: `, args.requestId);
|
|
781
|
+
break;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
// set bid status
|
|
785
|
+
switch (args.getStatusCode()) {
|
|
786
|
+
case GOOD:
|
|
787
|
+
bid.status = 'success';
|
|
788
|
+
delete bid.error; // it's possible for this to be set by a previous timeout
|
|
789
|
+
break;
|
|
790
|
+
case NO_BID:
|
|
791
|
+
bid.status = args.status === BID_REJECTED ? BID_REJECTED_IPF : 'no-bid';
|
|
792
|
+
delete bid.error;
|
|
793
|
+
break;
|
|
794
|
+
default:
|
|
795
|
+
bid.status = 'error';
|
|
796
|
+
bid.error = {
|
|
797
|
+
code: 'request-error'
|
|
798
|
+
};
|
|
799
|
+
}
|
|
800
|
+
bid.clientLatencyMillis = args.timeToRespond || Date.now() - cache.auctions[args.auctionId].auction.auctionStart;
|
|
801
|
+
bid.bidResponse = parseBidResponse(args, bid.bidResponse);
|
|
802
|
+
|
|
803
|
+
// if pbs gave us back a bidId, we need to use it and update our bidId to PBA
|
|
804
|
+
const pbsBidId = (args.pbsBidId == 0 ? generateUUID() : args.pbsBidId) || (args.seatBidId == 0 ? generateUUID() : args.seatBidId);
|
|
805
|
+
if (pbsBidId) {
|
|
806
|
+
bid.pbsBidId = pbsBidId;
|
|
807
|
+
}
|
|
808
|
+
break;
|
|
809
|
+
case BIDDER_DONE:
|
|
810
|
+
const serverError = deepAccess(args, 'serverErrors.0');
|
|
811
|
+
const serverResponseTimeMs = args.serverResponseTimeMs;
|
|
812
|
+
args.bids.forEach(bid => {
|
|
813
|
+
let cachedBid = deepAccess(cache, `auctions.${bid.auctionId}.auction.adUnits.${bid.transactionId}.bids.${bid.bidId}`);
|
|
814
|
+
if (typeof bid.serverResponseTimeMs !== 'undefined') {
|
|
815
|
+
cachedBid.serverLatencyMillis = bid.serverResponseTimeMs;
|
|
816
|
+
} else if (serverResponseTimeMs && bid.source === 's2s') {
|
|
817
|
+
cachedBid.serverLatencyMillis = serverResponseTimeMs;
|
|
818
|
+
}
|
|
819
|
+
// if PBS said we had an error, and this bid has not been processed by BID_RESPONSE YET
|
|
820
|
+
if (serverError && (!cachedBid.status || ['no-bid', 'error'].indexOf(cachedBid.status) !== -1)) {
|
|
821
|
+
cachedBid.status = 'error';
|
|
822
|
+
cachedBid.error = {
|
|
823
|
+
code: pbsErrorMap[serverError.code] || pbsErrorMap[999],
|
|
824
|
+
description: serverError.message
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
// set client latency if not done yet
|
|
829
|
+
if (!cachedBid.clientLatencyMillis) {
|
|
830
|
+
cachedBid.clientLatencyMillis = Date.now() - cache.auctions[args.auctionId].auction.auctionStart;
|
|
831
|
+
}
|
|
832
|
+
});
|
|
833
|
+
break;
|
|
834
|
+
case BID_WON:
|
|
835
|
+
// Allowing us to delay bidWon handling so it happens at right time
|
|
836
|
+
// we expect it to happen after gpt slotRenderEnded, but have seen it happen before when testing
|
|
837
|
+
// this will ensure it happens after if set
|
|
838
|
+
if (rubiConf.analyticsProcessDelay > 0) {
|
|
839
|
+
setTimeout(() => {
|
|
840
|
+
handleBidWon(args);
|
|
841
|
+
}, rubiConf.analyticsProcessDelay);
|
|
842
|
+
} else {
|
|
843
|
+
handleBidWon(args);
|
|
844
|
+
}
|
|
845
|
+
break;
|
|
846
|
+
case AUCTION_END:
|
|
847
|
+
let auctionCache = cache.auctions[args.auctionId];
|
|
848
|
+
// if for some reason the auction did not do its normal thing, this could be undefied so bail
|
|
849
|
+
if (!auctionCache) {
|
|
850
|
+
break;
|
|
851
|
+
}
|
|
852
|
+
// Set this auction as being done
|
|
853
|
+
auctionCache.auction.auctionEnd = args.auctionEnd;
|
|
854
|
+
|
|
855
|
+
// keeping order of auctions and if the payload has been sent or not
|
|
856
|
+
cache.auctionOrder.push(args.auctionId);
|
|
857
|
+
|
|
858
|
+
const isOnlyInstreamAuction = args.adUnits && args.adUnits.every(adUnit => adUnitIsOnlyInstream(adUnit));
|
|
859
|
+
|
|
860
|
+
// if we are not waiting OR it is instream only auction
|
|
861
|
+
if (isOnlyInstreamAuction || rubiConf.analyticsBatchTimeout === 0) {
|
|
862
|
+
sendAuctionEvent(args.auctionId, 'solo-auction');
|
|
863
|
+
} else {
|
|
864
|
+
// start timer to send batched payload just in case we don't hear any BID_WON events
|
|
865
|
+
cache.timeouts[args.auctionId] = setTimeout(() => {
|
|
866
|
+
sendAuctionEvent(args.auctionId, 'auctionEnd');
|
|
867
|
+
}, rubiConf.analyticsBatchTimeout);
|
|
868
|
+
}
|
|
869
|
+
break;
|
|
870
|
+
case BID_TIMEOUT:
|
|
871
|
+
args.forEach(badBid => {
|
|
872
|
+
let bid = deepAccess(cache, `auctions.${badBid.auctionId}.auction.adUnits.${badBid.transactionId}.bids.${badBid.bidId}`, {});
|
|
873
|
+
// might be set already by bidder-done, so do not overwrite
|
|
874
|
+
if (bid.status !== 'error') {
|
|
875
|
+
bid.status = 'error';
|
|
876
|
+
bid.error = {
|
|
877
|
+
code: 'timeout-error',
|
|
878
|
+
description: 'prebid.js timeout' // will help us diff if timeout was set by PBS or PBJS
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
});
|
|
882
|
+
break;
|
|
883
|
+
case BILLABLE_EVENT:
|
|
884
|
+
if (rubiConf.dmBilling.enabled && isBillingEventValid(args)) {
|
|
885
|
+
// add to the map indicating it has not been sent yet
|
|
886
|
+
deepSetValue(cache.billing, `${args.vendor}.${args.billingId}`, false);
|
|
887
|
+
const billingEvent = formatBillingEvent(args);
|
|
888
|
+
addEventToQueue({ billableEvents: [billingEvent] }, args.auctionId, 'billing');
|
|
889
|
+
} else {
|
|
890
|
+
logInfo(`${MODULE_NAME}: Billing event ignored`, args);
|
|
891
|
+
}
|
|
892
|
+
break;
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
|
|
896
|
+
adapterManager.registerAnalyticsAdapter({
|
|
897
|
+
adapter: magniteAdapter,
|
|
898
|
+
code: 'magnite',
|
|
899
|
+
gvlid: RUBICON_GVL_ID
|
|
900
|
+
});
|
|
901
|
+
|
|
902
|
+
export default magniteAdapter;
|