prebid.js 5.16.0 → 5.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/.devcontainer/Dockerfile +11 -0
- package/.devcontainer/devcontainer.json +27 -0
- package/.devcontainer/postCreate.sh +6 -0
- package/browsers.json +1 -0
- package/integrationExamples/gpt/akamaidap_segments_example.html +132 -0
- package/modules/.submodules.json +1 -0
- package/modules/adfBidAdapter.js +21 -16
- package/modules/adgenerationBidAdapter.js +28 -4
- package/modules/adkernelBidAdapter.js +3 -1
- package/modules/admixerBidAdapter.js +11 -0
- package/modules/adnuntiusBidAdapter.js +1 -0
- package/modules/adtelligentBidAdapter.js +2 -1
- package/modules/airgridRtdProvider.js +1 -1
- package/modules/akamaiDapRtdProvider.js +474 -0
- package/modules/akamaiDapRtdProvider.md +47 -0
- package/modules/aolBidAdapter.js +2 -1
- package/modules/appnexusBidAdapter.js +5 -3
- package/modules/atsAnalyticsAdapter.js +89 -63
- package/modules/atsAnalyticsAdapter.md +1 -0
- package/modules/betweenBidAdapter.js +20 -3
- package/modules/bliinkBidAdapter.js +58 -32
- package/modules/bliinkBidAdapter.md +29 -6
- package/modules/browsiRtdProvider.js +106 -18
- package/modules/cleanioRtdProvider.js +192 -0
- package/modules/cleanioRtdProvider.md +59 -0
- package/modules/codefuelBidAdapter.js +183 -0
- package/modules/codefuelBidAdapter.md +111 -0
- package/modules/connectIdSystem.js +104 -0
- package/modules/connectIdSystem.md +33 -0
- package/modules/cwireBidAdapter.js +272 -0
- package/modules/cwireBidAdapter.md +43 -0
- package/modules/deepintentBidAdapter.js +106 -9
- package/modules/deepintentBidAdapter.md +36 -1
- package/modules/deltaprojectsBidAdapter.js +252 -0
- package/modules/deltaprojectsBidAdapter.md +32 -0
- package/modules/dgkeywordRtdProvider.js +0 -1
- package/modules/engageyaBidAdapter.js +157 -0
- package/modules/glimpseBidAdapter.js +160 -48
- package/modules/glimpseBidAdapter.md +11 -74
- package/modules/gridBidAdapter.js +1 -0
- package/modules/gridNMBidAdapter.js +7 -6
- package/modules/gumgumBidAdapter.js +16 -2
- package/modules/iasRtdProvider.js +83 -67
- package/modules/inskinBidAdapter.js +7 -3
- package/modules/ixBidAdapter.js +8 -1
- package/modules/jixieBidAdapter.js +8 -2
- package/modules/justpremiumBidAdapter.js +6 -1
- package/modules/kargoBidAdapter.js +14 -7
- package/modules/kargoBidAdapter.md +20 -0
- package/modules/limelightDigitalBidAdapter.js +22 -2
- package/modules/livewrappedAnalyticsAdapter.js +53 -3
- package/modules/mediakeysBidAdapter.js +405 -14
- package/modules/mediakeysBidAdapter.md +108 -0
- package/modules/multibid/index.js +3 -3
- package/modules/mytargetBidAdapter.js +112 -0
- package/modules/nativoBidAdapter.js +48 -29
- package/modules/nativoBidAdapter.md +0 -1
- package/modules/nextMillenniumBidAdapter.js +12 -3
- package/modules/nextrollBidAdapter.js +375 -0
- package/modules/nobidBidAdapter.js +2 -1
- package/modules/oguryBidAdapter.js +36 -7
- package/modules/openxBidAdapter.js +34 -22
- package/modules/operaadsBidAdapter.js +21 -1
- package/modules/otmBidAdapter.js +146 -0
- package/modules/otmBidAdapter.md +27 -26
- package/modules/outbrainBidAdapter.js +5 -0
- package/modules/pixfutureBidAdapter.js +24 -4
- package/modules/pixfutureBidAdapter.md +127 -0
- package/modules/playwireBidAdapter.md +61 -0
- package/modules/prebidServerBidAdapter/index.js +1 -1
- package/modules/proxistoreBidAdapter.js +4 -6
- package/modules/publinkIdSystem.js +17 -7
- package/modules/publinkIdSystem.md +7 -2
- package/modules/pubmaticBidAdapter.js +22 -6
- package/modules/pubmaticBidAdapter.md +1 -1
- package/modules/relaidoBidAdapter.js +8 -2
- package/modules/rtdModule/index.js +2 -2
- package/modules/sharethroughBidAdapter.js +12 -19
- package/modules/slimcutBidAdapter.js +121 -0
- package/modules/sonobiBidAdapter.js +7 -0
- package/modules/sortableBidAdapter.js +1 -0
- package/modules/spotxBidAdapter.js +15 -1
- package/modules/sspBCBidAdapter.js +207 -12
- package/modules/sspBCBidAdapter.md +1 -1
- package/modules/talkadsBidAdapter.js +129 -0
- package/modules/talkadsBidAdapter.md +60 -0
- package/modules/tappxBidAdapter.js +6 -5
- package/modules/teadsBidAdapter.js +3 -0
- package/modules/tripleliftBidAdapter.js +22 -5
- package/modules/trustxBidAdapter.js +17 -11
- package/modules/undertoneBidAdapter.js +9 -5
- package/modules/undertoneBidAdapter.md +5 -1
- package/modules/unicornBidAdapter.js +3 -3
- package/modules/userId/eids.js +18 -0
- package/modules/userId/eids.md +7 -0
- package/modules/userId/userId.md +12 -0
- package/modules/ventesBidAdapter.js +370 -0
- package/modules/ventesBidAdapter.md +94 -0
- package/modules/videobyteBidAdapter.js +13 -6
- package/modules/videobyteBidAdapter.md +49 -0
- package/modules/vidoomyBidAdapter.js +20 -12
- package/modules/visxBidAdapter.js +15 -22
- package/modules/yahoosspBidAdapter.js +637 -0
- package/modules/yahoosspBidAdapter.md +795 -0
- package/modules/yieldlabBidAdapter.js +48 -3
- package/modules/yieldlabBidAdapter.md +16 -1
- package/modules/yieldmoBidAdapter.js +20 -6
- package/modules/yieldmoSyntheticInventoryModule.js +46 -0
- package/modules/yieldmoSyntheticInventoryModule.md +68 -0
- package/package.json +1 -1
- package/src/adapterManager.js +5 -0
- package/src/adapters/bidderFactory.js +4 -3
- package/src/auction.js +11 -11
- package/src/constants.json +1 -0
- package/src/secureCreatives.js +6 -7
- package/src/targeting.js +11 -9
- package/test/.eslintrc.js +2 -1
- package/test/spec/modules/adfBidAdapter_spec.js +83 -29
- package/test/spec/modules/adgenerationBidAdapter_spec.js +121 -50
- package/test/spec/modules/adnuntiusBidAdapter_spec.js +68 -0
- package/test/spec/modules/adtelligentBidAdapter_spec.js +1 -0
- package/test/spec/modules/akamaiDapRtdProvider_spec.js +246 -0
- package/test/spec/modules/appnexusBidAdapter_spec.js +2 -1
- package/test/spec/modules/atsAnalyticsAdapter_spec.js +77 -9
- package/test/spec/modules/betweenBidAdapter_spec.js +41 -0
- package/test/spec/modules/bliinkBidAdapter_spec.js +87 -36
- package/test/spec/modules/browsiRtdProvider_spec.js +62 -7
- package/test/spec/modules/cleanioRtdProvider_spec.js +188 -0
- package/test/spec/modules/codefuelBidAdapter_spec.js +316 -0
- package/test/spec/modules/connectIdSystem_spec.js +189 -0
- package/test/spec/modules/cwireBidAdapter_spec.js +246 -0
- package/test/spec/modules/deepintentBidAdapter_spec.js +153 -3
- package/test/spec/modules/deltaprojectsBidAdapter_spec.js +399 -0
- package/test/spec/modules/engageyaBidAdapter_spec.js +286 -0
- package/test/spec/modules/glimpseBidAdapter_spec.js +302 -204
- package/test/spec/modules/gridNMBidAdapter_spec.js +40 -1
- package/test/spec/modules/gumgumBidAdapter_spec.js +23 -6
- package/test/spec/modules/iasRtdProvider_spec.js +71 -6
- package/test/spec/modules/ixBidAdapter_spec.js +13 -3
- package/test/spec/modules/jixieBidAdapter_spec.js +13 -11
- package/test/spec/modules/justpremiumBidAdapter_spec.js +9 -2
- package/test/spec/modules/limelightDigitalBidAdapter_spec.js +155 -1
- package/test/spec/modules/livewrappedAnalyticsAdapter_spec.js +67 -12
- package/test/spec/modules/mediakeysBidAdapter_spec.js +406 -51
- package/test/spec/modules/multibid_spec.js +31 -31
- package/test/spec/modules/mytargetBidAdapter_spec.js +199 -0
- package/test/spec/modules/nativoBidAdapter_spec.js +50 -3
- package/test/spec/modules/nextMillenniumBidAdapter_spec.js +13 -1
- package/test/spec/modules/nextrollBidAdapter_spec.js +290 -0
- package/test/spec/modules/nobidBidAdapter_spec.js +65 -1
- package/test/spec/modules/oguryBidAdapter_spec.js +125 -37
- package/test/spec/modules/openxBidAdapter_spec.js +85 -13
- package/test/spec/modules/operaadsBidAdapter_spec.js +38 -6
- package/test/spec/modules/otmBidAdapter_spec.js +67 -0
- package/test/spec/modules/outbrainBidAdapter_spec.js +18 -0
- package/test/spec/modules/publinkIdSystem_spec.js +34 -15
- package/test/spec/modules/pubmaticBidAdapter_spec.js +217 -1
- package/test/spec/modules/relaidoBidAdapter_spec.js +21 -20
- package/test/spec/modules/sharethroughBidAdapter_spec.js +156 -136
- package/test/spec/modules/slimcutBidAdapter_spec.js +200 -0
- package/test/spec/modules/sonobiBidAdapter_spec.js +34 -1
- package/test/spec/modules/sortableBidAdapter_spec.js +11 -0
- package/test/spec/modules/spotxBidAdapter_spec.js +36 -0
- package/test/spec/modules/sspBCBidAdapter_spec.js +210 -62
- package/test/spec/modules/talkadsBidAdapter_spec.js +231 -0
- package/test/spec/modules/teadsBidAdapter_spec.js +132 -0
- package/test/spec/modules/tripleliftBidAdapter_spec.js +128 -0
- package/test/spec/modules/trustxBidAdapter_spec.js +38 -5
- package/test/spec/modules/undertoneBidAdapter_spec.js +52 -0
- package/test/spec/modules/unicornBidAdapter_spec.js +4 -4
- package/test/spec/modules/ventesBidAdapter_spec.js +845 -0
- package/test/spec/modules/videobyteBidAdapter_spec.js +2 -2
- package/test/spec/modules/visxBidAdapter_spec.js +48 -4
- package/test/spec/modules/yahoosspBidAdapter_spec.js +1332 -0
- package/test/spec/modules/yieldlabBidAdapter_spec.js +65 -1
- package/test/spec/modules/yieldmoBidAdapter_spec.js +30 -9
- package/test/spec/modules/yieldmoSyntheticInventoryModule_spec.js +89 -0
- package/test/spec/unit/core/adapterManager_spec.js +32 -0
- package/test/spec/unit/core/bidderFactory_spec.js +61 -1
- package/test/spec/unit/pbjs_api_spec.js +37 -2
- package/test/spec/unit/secureCreatives_spec.js +54 -25
- package/modules/turktelekomBidAdapter.md +0 -49
|
@@ -15,21 +15,27 @@
|
|
|
15
15
|
* @property {?string} keyName
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
|
-
import { deepClone, logError, isGptPubadsDefined } from '../src/utils.js';
|
|
18
|
+
import { deepClone, logError, isGptPubadsDefined, isNumber, isFn, deepSetValue } from '../src/utils.js';
|
|
19
19
|
import {submodule} from '../src/hook.js';
|
|
20
20
|
import {ajaxBuilder} from '../src/ajax.js';
|
|
21
21
|
import {loadExternalScript} from '../src/adloader.js';
|
|
22
22
|
import {getStorageManager} from '../src/storageManager.js';
|
|
23
23
|
import find from 'core-js-pure/features/array/find.js';
|
|
24
|
+
import {getGlobal} from '../src/prebidGlobal.js';
|
|
25
|
+
import includes from 'core-js-pure/features/array/includes.js';
|
|
24
26
|
|
|
25
27
|
const storage = getStorageManager();
|
|
26
28
|
|
|
27
29
|
/** @type {ModuleParams} */
|
|
28
30
|
let _moduleParams = {};
|
|
29
31
|
/** @type {null|Object} */
|
|
30
|
-
let
|
|
32
|
+
let _browsiData = null;
|
|
31
33
|
/** @type {string} */
|
|
32
34
|
const DEF_KEYNAME = 'browsiViewability';
|
|
35
|
+
/** @type {null | function} */
|
|
36
|
+
let _dataReadyCallback = null;
|
|
37
|
+
/** @type {null|Object} */
|
|
38
|
+
let _ic = {};
|
|
33
39
|
|
|
34
40
|
/**
|
|
35
41
|
* add browsi script to page
|
|
@@ -78,29 +84,49 @@ export function collectData() {
|
|
|
78
84
|
getPredictionsFromServer(`//${_moduleParams.url}/prebid?${toUrlParams(predictorData)}`);
|
|
79
85
|
}
|
|
80
86
|
|
|
87
|
+
/**
|
|
88
|
+
* wait for data from server
|
|
89
|
+
* call callback when data is ready
|
|
90
|
+
* @param {function} callback
|
|
91
|
+
*/
|
|
92
|
+
function waitForData(callback) {
|
|
93
|
+
if (_browsiData) {
|
|
94
|
+
_dataReadyCallback = null;
|
|
95
|
+
callback(_browsiData);
|
|
96
|
+
} else {
|
|
97
|
+
_dataReadyCallback = callback;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
81
101
|
export function setData(data) {
|
|
82
|
-
|
|
102
|
+
_browsiData = data;
|
|
103
|
+
if (isFn(_dataReadyCallback)) {
|
|
104
|
+
_dataReadyCallback(_browsiData);
|
|
105
|
+
_dataReadyCallback = null;
|
|
106
|
+
}
|
|
83
107
|
}
|
|
84
108
|
|
|
85
|
-
function
|
|
109
|
+
function getRTD(auc) {
|
|
86
110
|
try {
|
|
87
|
-
const
|
|
88
|
-
return
|
|
89
|
-
|
|
111
|
+
const _bp = (_browsiData && _browsiData.p) || {};
|
|
112
|
+
return auc.reduce((rp, uc) => {
|
|
113
|
+
_ic[uc] = _ic[uc] || 0;
|
|
114
|
+
const _c = _ic[uc];
|
|
115
|
+
if (!uc) {
|
|
90
116
|
return rp
|
|
91
117
|
}
|
|
92
|
-
const adSlot = getSlotByCode(
|
|
93
|
-
const identifier = adSlot ? getMacroId(
|
|
94
|
-
const
|
|
95
|
-
rp[
|
|
96
|
-
if (!
|
|
118
|
+
const adSlot = getSlotByCode(uc);
|
|
119
|
+
const identifier = adSlot ? getMacroId(_browsiData['pmd'], adSlot) : uc;
|
|
120
|
+
const _pd = _bp[identifier];
|
|
121
|
+
rp[uc] = getKVObject(-1);
|
|
122
|
+
if (!_pd) {
|
|
97
123
|
return rp
|
|
98
124
|
}
|
|
99
|
-
if (
|
|
100
|
-
if (!isIdMatchingAdUnit(adSlot,
|
|
125
|
+
if (_pd.ps) {
|
|
126
|
+
if (!isIdMatchingAdUnit(adSlot, _pd.w)) {
|
|
101
127
|
return rp;
|
|
102
128
|
}
|
|
103
|
-
rp[
|
|
129
|
+
rp[uc] = getKVObject(getCurrentData(_pd.ps, _c));
|
|
104
130
|
}
|
|
105
131
|
return rp;
|
|
106
132
|
}, {});
|
|
@@ -109,6 +135,31 @@ function sendDataToModule(adUnitsCodes) {
|
|
|
109
135
|
}
|
|
110
136
|
}
|
|
111
137
|
|
|
138
|
+
/**
|
|
139
|
+
* get prediction
|
|
140
|
+
* return -1 if prediction not found
|
|
141
|
+
* @param {object} predictionObject
|
|
142
|
+
* @param {number} _c
|
|
143
|
+
* @return {number}
|
|
144
|
+
*/
|
|
145
|
+
export function getCurrentData(predictionObject, _c) {
|
|
146
|
+
if (!predictionObject || !isNumber(_c)) {
|
|
147
|
+
return -1;
|
|
148
|
+
}
|
|
149
|
+
if (isNumber(predictionObject[_c])) {
|
|
150
|
+
return predictionObject[_c];
|
|
151
|
+
}
|
|
152
|
+
if (Object.keys(predictionObject).length > 1) {
|
|
153
|
+
while (_c > 0) {
|
|
154
|
+
_c--;
|
|
155
|
+
if (isNumber(predictionObject[_c])) {
|
|
156
|
+
return predictionObject[_c];
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return -1;
|
|
161
|
+
}
|
|
162
|
+
|
|
112
163
|
/**
|
|
113
164
|
* get all slots on page
|
|
114
165
|
* @return {Object[]} slot GoogleTag slots
|
|
@@ -122,12 +173,16 @@ function getAllSlots() {
|
|
|
122
173
|
* @param {string?} keyName
|
|
123
174
|
* @return {Object} key:value
|
|
124
175
|
*/
|
|
125
|
-
function getKVObject(p
|
|
176
|
+
function getKVObject(p) {
|
|
126
177
|
const prValue = p < 0 ? 'NA' : (Math.floor(p * 10) / 10).toFixed(2);
|
|
127
178
|
let prObject = {};
|
|
128
|
-
prObject[(
|
|
179
|
+
prObject[getKey()] = prValue.toString();
|
|
129
180
|
return prObject;
|
|
130
181
|
}
|
|
182
|
+
|
|
183
|
+
function getKey() {
|
|
184
|
+
return ((_moduleParams['keyName'] || (_browsiData && _browsiData['kn']) || DEF_KEYNAME).toString())
|
|
185
|
+
}
|
|
131
186
|
/**
|
|
132
187
|
* check if placement id matches one of given ad units
|
|
133
188
|
* @param {Object} slot google slot
|
|
@@ -238,6 +293,28 @@ function toUrlParams(data) {
|
|
|
238
293
|
.join('&');
|
|
239
294
|
}
|
|
240
295
|
|
|
296
|
+
function setBidRequestsData(bidObj, callback) {
|
|
297
|
+
let adUnitCodes = bidObj.adUnitCodes;
|
|
298
|
+
let adUnits = bidObj.adUnits || getGlobal().adUnits || [];
|
|
299
|
+
if (adUnitCodes) {
|
|
300
|
+
adUnits = adUnits.filter(au => includes(adUnitCodes, au.code));
|
|
301
|
+
} else {
|
|
302
|
+
adUnitCodes = adUnits.map(au => au.code);
|
|
303
|
+
}
|
|
304
|
+
waitForData(() => {
|
|
305
|
+
const data = getRTD(adUnitCodes);
|
|
306
|
+
if (data) {
|
|
307
|
+
adUnits.forEach(adUnit => {
|
|
308
|
+
const adUnitCode = adUnit.code;
|
|
309
|
+
if (data[adUnitCode]) {
|
|
310
|
+
deepSetValue(adUnit, 'ortb2Imp.ext.data.browsi', {[getKey()]: data[adUnitCode][getKey()]});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
callback();
|
|
315
|
+
})
|
|
316
|
+
}
|
|
317
|
+
|
|
241
318
|
/** @type {RtdSubmodule} */
|
|
242
319
|
export const browsiSubmodule = {
|
|
243
320
|
/**
|
|
@@ -250,10 +327,21 @@ export const browsiSubmodule = {
|
|
|
250
327
|
* @function
|
|
251
328
|
* @param {string[]} adUnitsCodes
|
|
252
329
|
*/
|
|
253
|
-
getTargetingData:
|
|
330
|
+
getTargetingData: getTargetingData,
|
|
254
331
|
init: init,
|
|
332
|
+
getBidRequestData: setBidRequestsData
|
|
255
333
|
};
|
|
256
334
|
|
|
335
|
+
function getTargetingData(uc) {
|
|
336
|
+
const targetingData = getRTD(uc);
|
|
337
|
+
uc.forEach(auc => {
|
|
338
|
+
if (isNumber(_ic[auc])) {
|
|
339
|
+
_ic[auc] = _ic[auc] + 1;
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
return targetingData;
|
|
343
|
+
}
|
|
344
|
+
|
|
257
345
|
function init(moduleConfig) {
|
|
258
346
|
_moduleParams = moduleConfig.params;
|
|
259
347
|
if (_moduleParams && _moduleParams.siteKey && _moduleParams.pubKey && _moduleParams.url) {
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This module adds clean.io provider to the real time data module
|
|
3
|
+
* The {@link module:modules/realTimeData} module is required
|
|
4
|
+
* The module will wrap bid responses markup in clean.io agent script for protection
|
|
5
|
+
* @module modules/cleanioRtdProvider
|
|
6
|
+
* @requires module:modules/realTimeData
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { submodule } from '../src/hook.js';
|
|
10
|
+
import { logError, generateUUID, insertElement } from '../src/utils.js';
|
|
11
|
+
|
|
12
|
+
// ============================ MODULE STATE ===============================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @type {function(): void}
|
|
16
|
+
* Page-wide initialization step / strategy
|
|
17
|
+
*/
|
|
18
|
+
let onModuleInit = () => {};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* @type {function(Object): void}
|
|
22
|
+
* Bid response mutation step / strategy.
|
|
23
|
+
*/
|
|
24
|
+
let onBidResponse = () => {};
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* @type {number}
|
|
28
|
+
* 0 for unknown, 1 for preloaded, -1 for error.
|
|
29
|
+
*/
|
|
30
|
+
let preloadStatus = 0;
|
|
31
|
+
|
|
32
|
+
// ============================ MODULE LOGIC ===============================
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Page initialization step which just preloads the script, to be available whenever we start processing the bids.
|
|
36
|
+
* @param {string} scriptURL The script URL to preload
|
|
37
|
+
*/
|
|
38
|
+
function pageInitStepPreloadScript(scriptURL) {
|
|
39
|
+
const linkElement = document.createElement('link');
|
|
40
|
+
linkElement.rel = 'preload';
|
|
41
|
+
linkElement.as = 'script';
|
|
42
|
+
linkElement.href = scriptURL;
|
|
43
|
+
linkElement.onload = () => { preloadStatus = 1; };
|
|
44
|
+
linkElement.onerror = () => { preloadStatus = -1; };
|
|
45
|
+
insertElement(linkElement);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Page initialization step which adds the protector script to the whole page. With that, there is no need wrapping bids, and the coverage is better.
|
|
50
|
+
* @param {string} scriptURL The script URL to add to the page for protection
|
|
51
|
+
*/
|
|
52
|
+
function pageInitStepProtectPage(scriptURL) {
|
|
53
|
+
const scriptElement = document.createElement('script');
|
|
54
|
+
scriptElement.type = 'text/javascript';
|
|
55
|
+
scriptElement.src = scriptURL;
|
|
56
|
+
insertElement(scriptElement);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Bid processing step which alters the ad HTML to contain bid-specific information, which can be used to identify the creative later.
|
|
61
|
+
* @param {Object} bidResponse Bid response data
|
|
62
|
+
*/
|
|
63
|
+
function bidWrapStepAugmentHtml(bidResponse) {
|
|
64
|
+
bidResponse.ad = `<!-- pbad://creativeId=${bidResponse.creativeId || ''}&bidderCode=${bidResponse.bidderCode || ''}&cpm=${bidResponse.cpm || ''} -->\n${bidResponse.ad}`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Bid processing step which applies creative protection by wrapping the ad HTML.
|
|
69
|
+
* @param {string} scriptURL
|
|
70
|
+
* @param {number} requiredPreload
|
|
71
|
+
* @param {Object} bidResponse
|
|
72
|
+
*/
|
|
73
|
+
function bidWrapStepProtectByWrapping(scriptURL, requiredPreload, bidResponse) {
|
|
74
|
+
// Still prepend bid info, it's always helpful to have creative data in its payload
|
|
75
|
+
bidWrapStepAugmentHtml(bidResponse);
|
|
76
|
+
|
|
77
|
+
// If preloading failed, or if configuration requires us to finish preloading -
|
|
78
|
+
// we should not process this bid any further
|
|
79
|
+
if (preloadStatus < requiredPreload) {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const sid = generateUUID();
|
|
84
|
+
bidResponse.ad = `
|
|
85
|
+
<script type="text/javascript"
|
|
86
|
+
src="${scriptURL}"
|
|
87
|
+
data-api-integration-mode="prebid"
|
|
88
|
+
data-api-session-uuid="${sid}">
|
|
89
|
+
</script>
|
|
90
|
+
<script type="text/javascript">
|
|
91
|
+
var ad = "${encodeURIComponent(bidResponse.ad)}";
|
|
92
|
+
var agent = window["${sid}"];
|
|
93
|
+
if (agent && typeof agent.put === "function") {
|
|
94
|
+
agent.put(ad);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
document.open();
|
|
98
|
+
document.write(decodeURIComponent(ad));
|
|
99
|
+
document.close();
|
|
100
|
+
}
|
|
101
|
+
</script>
|
|
102
|
+
`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Custom error class to differentiate validation errors
|
|
107
|
+
*/
|
|
108
|
+
class ConfigError extends Error { }
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The function to be called upon module init. Depending on the passed config, initializes properly init/bid steps or throws ConfigError.
|
|
112
|
+
* @param {Object} config
|
|
113
|
+
*/
|
|
114
|
+
function readConfig(config) {
|
|
115
|
+
if (!config.params) {
|
|
116
|
+
throw new ConfigError('Missing config parameters for clean.io RTD module provider.');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (typeof config.params.cdnUrl !== 'string' || !/^https?:\/\//.test(config.params.cdnUrl)) {
|
|
120
|
+
throw new ConfigError('Parameter "cdnUrl" is a required string parameter, which should start with "http(s)://".');
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (typeof config.params.protectionMode !== 'string') {
|
|
124
|
+
throw new ConfigError('Parameter "protectionMode" is a required string parameter.');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
const scriptURL = config.params.cdnUrl;
|
|
128
|
+
|
|
129
|
+
switch (config.params.protectionMode) {
|
|
130
|
+
case 'full':
|
|
131
|
+
onModuleInit = () => pageInitStepProtectPage(scriptURL);
|
|
132
|
+
onBidResponse = (bidResponse) => bidWrapStepAugmentHtml(bidResponse);
|
|
133
|
+
break;
|
|
134
|
+
|
|
135
|
+
case 'bids':
|
|
136
|
+
onModuleInit = () => pageInitStepPreloadScript(scriptURL);
|
|
137
|
+
onBidResponse = (bidResponse) => bidWrapStepProtectByWrapping(scriptURL, 0, bidResponse);
|
|
138
|
+
break;
|
|
139
|
+
|
|
140
|
+
case 'bids-nowait':
|
|
141
|
+
onModuleInit = () => pageInitStepPreloadScript(scriptURL);
|
|
142
|
+
onBidResponse = (bidResponse) => bidWrapStepProtectByWrapping(scriptURL, 1, bidResponse);
|
|
143
|
+
break;
|
|
144
|
+
|
|
145
|
+
default:
|
|
146
|
+
throw new ConfigError('Parameter "protectionMode" must be one of "full" | "bids" | "bids-nowait".');
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// ============================ MODULE REGISTRATION ===============================
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* The function which performs submodule registration.
|
|
154
|
+
*/
|
|
155
|
+
function beforeInit() {
|
|
156
|
+
submodule('realTimeData', /** @type {RtdSubmodule} */ ({
|
|
157
|
+
name: 'clean.io',
|
|
158
|
+
|
|
159
|
+
init: (config, userConsent) => {
|
|
160
|
+
try {
|
|
161
|
+
readConfig(config);
|
|
162
|
+
onModuleInit();
|
|
163
|
+
return true;
|
|
164
|
+
} catch (err) {
|
|
165
|
+
if (err instanceof ConfigError) {
|
|
166
|
+
logError(err.message);
|
|
167
|
+
}
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
onBidResponseEvent: (bidResponse, config, userConsent) => {
|
|
173
|
+
onBidResponse(bidResponse);
|
|
174
|
+
}
|
|
175
|
+
}));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Exporting local (and otherwise encapsulated to this module) functions
|
|
180
|
+
* for testing purposes
|
|
181
|
+
*/
|
|
182
|
+
export const __TEST__ = {
|
|
183
|
+
pageInitStepPreloadScript,
|
|
184
|
+
pageInitStepProtectPage,
|
|
185
|
+
bidWrapStepAugmentHtml,
|
|
186
|
+
bidWrapStepProtectByWrapping,
|
|
187
|
+
ConfigError,
|
|
188
|
+
readConfig,
|
|
189
|
+
beforeInit,
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
beforeInit();
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
```
|
|
4
|
+
Module Name: clean.io Rtd provider
|
|
5
|
+
Module Type: Rtd Provider
|
|
6
|
+
Maintainer: nick@clean.io
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
The clean.io Realtime module provides effective anti-malvertising solution for publishers, including, but not limited to,
|
|
10
|
+
blocking unwanted 0- and 1-click redirects, deceptive ads or those with malicious landing pages, and various types of affiliate fraud.
|
|
11
|
+
|
|
12
|
+
Using this module requires prior agreement with [clean.io](https://clean.io) to obtain the necessary distribution key.
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
# Integration
|
|
16
|
+
|
|
17
|
+
clean.io Realtime module can be built just like any other prebid module:
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
gulp build --modules=cleanioRtdProvider,...
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
# Configuration
|
|
25
|
+
|
|
26
|
+
When built into prebid.js, this module can be configured through the following `pbjs.setConfig` call:
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
pbjs.setConfig({
|
|
30
|
+
realTimeData: {
|
|
31
|
+
dataProviders: [{
|
|
32
|
+
name: 'clean.io',
|
|
33
|
+
params: {
|
|
34
|
+
cdnUrl: 'https://abc1234567890.cloudfront.net/script.js', ///< Contact clean.io to get your own CDN URL
|
|
35
|
+
protectionMode: 'full', ///< Supported modes are 'full', 'bids' and 'bids-nowait', see below.
|
|
36
|
+
}
|
|
37
|
+
}]
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## Configuration parameters
|
|
44
|
+
|
|
45
|
+
{: .table .table-bordered .table-striped }
|
|
46
|
+
| Name | Type | Scope | Description |
|
|
47
|
+
| :------------ | :------------ | :------------ |:------------ |
|
|
48
|
+
| ``cdnUrl`` | ``string`` | Required | CDN URL of the script, which is to be used for protection. |
|
|
49
|
+
| ``protectionMode`` | ``'full' \| 'bids' \| 'bids-nowait'`` | Required | Integration mode. Please refer to the "Integration modes" section for details. |
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
## Integration modes
|
|
53
|
+
|
|
54
|
+
{: .table .table-bordered .table-striped }
|
|
55
|
+
| Integration Mode | Parameter Value | Description |
|
|
56
|
+
| :------------ | :------------ | :------------ |
|
|
57
|
+
| Full page protection | ``'full'`` | Preferred mode. The module will add the protector agent script directly to the page, and it will protect all placements. This mode will make the most out of various behavioral detection mechanisms, and will also prevent typical malicious behaviors. Please note that in this mode, depending on Prebid library naming, Chrome may mistakenly tag non-ad-related content as ads: https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/ad_tagging.md. |
|
|
58
|
+
| Bids-only protection | ``'bids'`` | The module will protect specific bid responses, more specifically, the HTML representing ad payload, by wrapping it into the agent script. Please note that in this mode, ads delivered directly, outside of Prebid integration, will not be protected, since the module can only access the ads coming through Prebid. |
|
|
59
|
+
| Bids-only protection with no delay on bid rendering | ``'bids-nowait'`` | Same as above, but in this mode, the script will also *not* wrap those bid responses, which arrived prior to successful preloading of agent script. |
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { deepAccess, isArray } from '../src/utils.js';
|
|
2
|
+
import { config } from '../src/config.js';
|
|
3
|
+
import {registerBidder} from '../src/adapters/bidderFactory.js';
|
|
4
|
+
import { BANNER } from '../src/mediaTypes.js';
|
|
5
|
+
const BIDDER_CODE = 'codefuel';
|
|
6
|
+
const CURRENCY = 'USD';
|
|
7
|
+
|
|
8
|
+
export const spec = {
|
|
9
|
+
code: BIDDER_CODE,
|
|
10
|
+
supportedMediaTypes: [ BANNER ],
|
|
11
|
+
aliases: ['ex'], // short code
|
|
12
|
+
/**
|
|
13
|
+
* Determines whether or not the given bid request is valid.
|
|
14
|
+
*
|
|
15
|
+
* @param {BidRequest} bid The bid params to validate.
|
|
16
|
+
* @return boolean True if this is a valid bid, and false otherwise.
|
|
17
|
+
*/
|
|
18
|
+
isBidRequestValid: function(bid) {
|
|
19
|
+
if (bid.nativeParams) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return !!(bid.params.placementId || (bid.params.member && bid.params.invCode));
|
|
23
|
+
},
|
|
24
|
+
/**
|
|
25
|
+
* Make a server request from the list of BidRequests.
|
|
26
|
+
*
|
|
27
|
+
* @param {validBidRequests[]} - an array of bids
|
|
28
|
+
* @return ServerRequest Info describing the request to the server.
|
|
29
|
+
*/
|
|
30
|
+
buildRequests: function(validBidRequests, bidderRequest) {
|
|
31
|
+
const page = bidderRequest.refererInfo.referer;
|
|
32
|
+
const domain = getDomainFromURL(page)
|
|
33
|
+
const ua = navigator.userAgent;
|
|
34
|
+
const devicetype = getDeviceType()
|
|
35
|
+
const publisher = setOnAny(validBidRequests, 'params.publisher');
|
|
36
|
+
const cur = CURRENCY;
|
|
37
|
+
// const endpointUrl = 'http://localhost:5000/prebid'
|
|
38
|
+
const endpointUrl = config.getConfig('codefuel.bidderUrl');
|
|
39
|
+
const timeout = bidderRequest.timeout;
|
|
40
|
+
|
|
41
|
+
validBidRequests.forEach(bid => bid.netRevenue = 'net');
|
|
42
|
+
|
|
43
|
+
const imps = validBidRequests.map((bid, idx) => {
|
|
44
|
+
const imp = {
|
|
45
|
+
id: idx + 1 + ''
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (bid.params.tagid) {
|
|
49
|
+
imp.tagid = bid.params.tagid
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
if (bid.sizes) {
|
|
53
|
+
imp.banner = {
|
|
54
|
+
format: transformSizes(bid.sizes)
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return imp;
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const request = {
|
|
62
|
+
id: bidderRequest.auctionId,
|
|
63
|
+
site: { page, domain, publisher },
|
|
64
|
+
device: { ua, devicetype },
|
|
65
|
+
source: { fd: 1 },
|
|
66
|
+
cur: [cur],
|
|
67
|
+
tmax: timeout,
|
|
68
|
+
imp: imps,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
return {
|
|
72
|
+
method: 'POST',
|
|
73
|
+
url: endpointUrl,
|
|
74
|
+
data: request,
|
|
75
|
+
bids: validBidRequests,
|
|
76
|
+
options: {
|
|
77
|
+
withCredentials: false
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
},
|
|
81
|
+
/**
|
|
82
|
+
* Unpack the response from the server into a list of bids.
|
|
83
|
+
*
|
|
84
|
+
* @param {ServerResponse} serverResponse A successful response from the server.
|
|
85
|
+
* @return {Bid[]} An array of bids which were nested inside the server.
|
|
86
|
+
*/
|
|
87
|
+
interpretResponse: (serverResponse, { bids }) => {
|
|
88
|
+
if (!serverResponse.body) {
|
|
89
|
+
return [];
|
|
90
|
+
}
|
|
91
|
+
const { seatbid, cur } = serverResponse.body;
|
|
92
|
+
|
|
93
|
+
const bidResponses = flatten(seatbid.map(seat => seat.bid)).reduce((result, bid) => {
|
|
94
|
+
result[bid.impid - 1] = bid;
|
|
95
|
+
return result;
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
return bids.map((bid, id) => {
|
|
99
|
+
const bidResponse = bidResponses[id];
|
|
100
|
+
if (bidResponse) {
|
|
101
|
+
const bidObject = {
|
|
102
|
+
requestId: bid.bidId,
|
|
103
|
+
cpm: bidResponse.price,
|
|
104
|
+
creativeId: bidResponse.crid,
|
|
105
|
+
ttl: 360,
|
|
106
|
+
netRevenue: true,
|
|
107
|
+
currency: cur,
|
|
108
|
+
mediaType: BANNER,
|
|
109
|
+
ad: bidResponse.adm,
|
|
110
|
+
width: bidResponse.w,
|
|
111
|
+
height: bidResponse.h,
|
|
112
|
+
meta: { advertiserDomains: bid.adomain ? bid.adomain : [] }
|
|
113
|
+
};
|
|
114
|
+
return bidObject;
|
|
115
|
+
}
|
|
116
|
+
}).filter(Boolean);
|
|
117
|
+
},
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Register the user sync pixels which should be dropped after the auction.
|
|
121
|
+
*
|
|
122
|
+
* @param {SyncOptions} syncOptions Which user syncs are allowed?
|
|
123
|
+
* @param {ServerResponse[]} serverResponses List of server's responses.
|
|
124
|
+
* @return {UserSync[]} The user syncs which should be dropped.
|
|
125
|
+
*/
|
|
126
|
+
getUserSyncs: function(syncOptions, serverResponses, gdprConsent, uspConsent) {
|
|
127
|
+
return [];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
}
|
|
131
|
+
registerBidder(spec);
|
|
132
|
+
|
|
133
|
+
function getDomainFromURL(url) {
|
|
134
|
+
let anchor = document.createElement('a');
|
|
135
|
+
anchor.href = url;
|
|
136
|
+
return anchor.hostname;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function getDeviceType() {
|
|
140
|
+
if ((/ipad|android 3.0|xoom|sch-i800|playbook|tablet|kindle/i.test(navigator.userAgent.toLowerCase()))) {
|
|
141
|
+
return 5; // 'tablet'
|
|
142
|
+
}
|
|
143
|
+
if ((/iphone|ipod|android|blackberry|opera|mini|windows\sce|palm|smartphone|iemobile/i.test(navigator.userAgent.toLowerCase()))) {
|
|
144
|
+
return 4; // 'mobile'
|
|
145
|
+
}
|
|
146
|
+
return 2; // 'desktop'
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function setOnAny(collection, key) {
|
|
150
|
+
for (let i = 0, result; i < collection.length; i++) {
|
|
151
|
+
result = deepAccess(collection[i], key);
|
|
152
|
+
if (result) {
|
|
153
|
+
return result;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function flatten(arr) {
|
|
159
|
+
return [].concat(...arr);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/* Turn bid request sizes into ut-compatible format */
|
|
163
|
+
function transformSizes(requestSizes) {
|
|
164
|
+
if (!isArray(requestSizes)) {
|
|
165
|
+
return [];
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (requestSizes.length === 2 && !isArray(requestSizes[0])) {
|
|
169
|
+
return [{
|
|
170
|
+
w: parseInt(requestSizes[0], 10),
|
|
171
|
+
h: parseInt(requestSizes[1], 10)
|
|
172
|
+
}];
|
|
173
|
+
} else if (isArray(requestSizes[0])) {
|
|
174
|
+
return requestSizes.map(item =>
|
|
175
|
+
({
|
|
176
|
+
w: parseInt(item[0], 10),
|
|
177
|
+
h: parseInt(item[1], 10)
|
|
178
|
+
})
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return [];
|
|
183
|
+
}
|