Skip to content

Commit aa118c7

Browse files
authored
Adagio Bid Adapter: preparation for new Rtd module and Prebid.js 9 (#11485)
* Utils: add isSafeFrameWindow(), canAccessWindowTop() * AdagioBidAdapter: prepare to work with Adagio RTD Provider
1 parent 00144d5 commit aa118c7

File tree

4 files changed

+161
-76
lines changed

4 files changed

+161
-76
lines changed

modules/adagioBidAdapter.js

Lines changed: 84 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import {find} from '../src/polyfill.js';
22
import {
3+
canAccessWindowTop,
34
cleanObj,
45
deepAccess,
56
deepClone,
@@ -8,17 +9,18 @@ import {
89
getUniqueIdentifierStr,
910
getWindowSelf,
1011
getWindowTop,
11-
inIframe,
1212
isArray,
13+
isArrayOfNums,
1314
isFn,
15+
inIframe,
1416
isInteger,
1517
isNumber,
16-
isArrayOfNums,
18+
isSafeFrameWindow,
19+
isStr,
1720
logError,
1821
logInfo,
1922
logWarn,
2023
mergeDeep,
21-
isStr,
2224
} from '../src/utils.js';
2325
import {config} from '../src/config.js';
2426
import {registerBidder} from '../src/adapters/bidderFactory.js';
@@ -104,13 +106,15 @@ export const GlobalExchange = (function() {
104106
getOrSetGlobalFeatures: function () {
105107
if (!features) {
106108
features = {
109+
type: 'bidAdapter',
107110
page_dimensions: getPageDimensions().toString(),
108111
viewport_dimensions: getViewPortDimensions().toString(),
109112
user_timestamp: getTimestampUTC().toString(),
110113
dom_loading: getDomLoadingDuration().toString(),
111114
}
112115
}
113-
return features;
116+
117+
return { ...features };
114118
},
115119

116120
prepareExchangeData(storageValue) {
@@ -130,7 +134,7 @@ export const GlobalExchange = (function() {
130134
const data = {
131135
session: {
132136
new: newSession,
133-
rnd: random
137+
rnd: random,
134138
}
135139
}
136140

@@ -149,6 +153,9 @@ export const GlobalExchange = (function() {
149153
};
150154
})();
151155

156+
/**
157+
* @deprecated will be removed in Prebid.js 9.
158+
*/
152159
export function adagioScriptFromLocalStorageCb(ls) {
153160
try {
154161
if (!ls) {
@@ -179,6 +186,9 @@ export function adagioScriptFromLocalStorageCb(ls) {
179186
}
180187
}
181188

189+
/**
190+
* @deprecated will be removed in Prebid.js 9.
191+
*/
182192
export function getAdagioScript() {
183193
storage.getDataFromLocalStorage(ADAGIO_LOCALSTORAGE_KEY, (ls) => {
184194
internal.adagioScriptFromLocalStorageCb(ls);
@@ -204,31 +214,14 @@ export function getAdagioScript() {
204214
});
205215
}
206216

207-
function canAccessTopWindow() {
208-
try {
209-
if (getWindowTop().location.href) {
210-
return true;
211-
}
212-
} catch (error) {
213-
return false;
214-
}
215-
}
216-
217217
function getCurrentWindow() {
218218
return currentWindow || getWindowSelf();
219219
}
220220

221-
function isSafeFrameWindow() {
222-
const ws = getWindowSelf();
223-
return !!(ws.$sf && ws.$sf.ext);
224-
}
225-
226221
function initAdagio() {
227-
if (canAccessTopWindow()) {
228-
currentWindow = (canAccessTopWindow()) ? getWindowTop() : getWindowSelf();
229-
}
222+
currentWindow = (canAccessWindowTop()) ? getWindowTop() : getWindowSelf();
230223

231-
const w = internal.getCurrentWindow();
224+
const w = currentWindow;
232225

233226
w.ADAGIO = w.ADAGIO || {};
234227
w.ADAGIO.adUnits = w.ADAGIO.adUnits || {};
@@ -240,13 +233,16 @@ function initAdagio() {
240233

241234
storage.getDataFromLocalStorage('adagio', (storageData) => {
242235
try {
243-
GlobalExchange.prepareExchangeData(storageData);
236+
if (w.ADAGIO.hasRtd !== true) {
237+
logInfo(`${LOG_PREFIX} RTD module not found. Loading external script from adagioBidAdapter is deprecated and will be removed in Prebid.js 9.`);
238+
239+
GlobalExchange.prepareExchangeData(storageData);
240+
getAdagioScript();
241+
}
244242
} catch (e) {
245243
logError(LOG_PREFIX, e);
246244
}
247245
});
248-
249-
getAdagioScript();
250246
}
251247

252248
function enqueue(ob) {
@@ -359,6 +355,12 @@ function setPlayerName(bidRequest) {
359355
return playerName;
360356
}
361357

358+
function hasRtd() {
359+
const w = internal.getCurrentWindow();
360+
361+
return !!(w.ADAGIO && w.ADAGIO.hasRtd);
362+
};
363+
362364
export const internal = {
363365
enqueue,
364366
getPageviewId,
@@ -368,9 +370,10 @@ export const internal = {
368370
getRefererInfo,
369371
adagioScriptFromLocalStorageCb,
370372
getCurrentWindow,
371-
canAccessTopWindow,
373+
canAccessWindowTop,
372374
isRendererPreferredFromPublisher,
373-
isNewSession
375+
isNewSession,
376+
hasRtd
374377
};
375378

376379
function _getGdprConsent(bidderRequest) {
@@ -685,7 +688,7 @@ function autoFillParams(bid) {
685688
}
686689

687690
function getPageDimensions() {
688-
if (isSafeFrameWindow() || !canAccessTopWindow()) {
691+
if (isSafeFrameWindow() || !canAccessWindowTop()) {
689692
return '';
690693
}
691694

@@ -708,7 +711,7 @@ function getPageDimensions() {
708711
* @returns
709712
*/
710713
function getViewPortDimensions() {
711-
if (!isSafeFrameWindow() && !canAccessTopWindow()) {
714+
if (!isSafeFrameWindow() && !canAccessWindowTop()) {
712715
return '';
713716
}
714717

@@ -746,7 +749,7 @@ function getSlotPosition(adUnitElementId) {
746749
return '';
747750
}
748751

749-
if (!isSafeFrameWindow() && !canAccessTopWindow()) {
752+
if (!isSafeFrameWindow() && !canAccessWindowTop()) {
750753
return '';
751754
}
752755

@@ -769,7 +772,7 @@ function getSlotPosition(adUnitElementId) {
769772

770773
position.x = Math.round(sfGeom.t);
771774
position.y = Math.round(sfGeom.l);
772-
} else if (canAccessTopWindow()) {
775+
} else if (canAccessWindowTop()) {
773776
try {
774777
// window.top based computing
775778
const wt = getWindowTop();
@@ -823,22 +826,14 @@ function getTimestampUTC() {
823826
return Math.floor(new Date().getTime() / 1000) - new Date().getTimezoneOffset() * 60;
824827
}
825828

826-
function getPrintNumber(adUnitCode, bidderRequest) {
827-
if (!bidderRequest.bids || !bidderRequest.bids.length) {
828-
return 1;
829-
}
830-
const adagioBid = find(bidderRequest.bids, bid => bid.adUnitCode === adUnitCode);
831-
return adagioBid.bidderRequestsCount || 1;
832-
}
833-
834829
/**
835830
* domLoading feature is computed on window.top if reachable.
836831
*/
837832
function getDomLoadingDuration() {
838833
let domLoadingDuration = -1;
839834
let performance;
840835

841-
performance = (canAccessTopWindow()) ? getWindowTop().performance : getWindowSelf().performance;
836+
performance = (canAccessWindowTop()) ? getWindowTop().performance : getWindowSelf().performance;
842837

843838
if (performance && performance.timing && performance.timing.navigationStart > 0) {
844839
const val = performance.timing.domLoading - performance.timing.navigationStart;
@@ -958,6 +953,31 @@ const OUTSTREAM_RENDERER = {
958953
}
959954
};
960955

956+
/**
957+
*
958+
* @param {*} bidRequest
959+
* @returns
960+
*/
961+
const _getFeatures = (bidRequest) => {
962+
const f = { ...deepAccess(bidRequest, 'ortb2.ext.features', GlobalExchange.getOrSetGlobalFeatures()) } || {};
963+
964+
f.print_number = deepAccess(bidRequest, 'bidderRequestsCount', 1).toString();
965+
966+
if (f.type === 'bidAdapter') {
967+
f.adunit_position = getSlotPosition(bidRequest.params.adUnitElementId)
968+
} else {
969+
f.adunit_position = deepAccess(bidRequest, 'ortb2Imp.ext.data.adunit_position');
970+
}
971+
972+
Object.keys(f).forEach((prop) => {
973+
if (f[prop] === '') {
974+
delete f[prop];
975+
}
976+
});
977+
978+
return f;
979+
}
980+
961981
export const spec = {
962982
code: BIDDER_CODE,
963983
gvlid: GVLID,
@@ -986,6 +1006,7 @@ export const spec = {
9861006
const device = internal.getDevice();
9871007
const site = internal.getSite(bidderRequest);
9881008
const pageviewId = internal.getPageviewId();
1009+
const hasRtd = internal.hasRtd();
9891010
const gdprConsent = _getGdprConsent(bidderRequest) || {};
9901011
const uspConsent = _getUspConsent(bidderRequest) || {};
9911012
const coppa = _getCoppa();
@@ -998,6 +1019,9 @@ export const spec = {
9981019
// We don't validate the dsa object in adapter and let our server do it.
9991020
const dsa = deepAccess(bidderRequest, 'ortb2.regs.ext.dsa');
10001021

1022+
let rtdSamplingSession = deepAccess(bidderRequest, 'ortb2.ext.session');
1023+
const dataExchange = (rtdSamplingSession) ? { session: rtdSamplingSession } : GlobalExchange.getExchangeData();
1024+
10011025
const aucId = generateUUID()
10021026

10031027
const adUnits = validBidRequests.map(rawBidRequest => {
@@ -1006,13 +1030,6 @@ export const spec = {
10061030
// Fix https://github.com/prebid/Prebid.js/issues/9781
10071031
bidRequest.auctionId = aucId
10081032

1009-
const globalFeatures = GlobalExchange.getOrSetGlobalFeatures();
1010-
const features = {
1011-
...globalFeatures,
1012-
print_number: getPrintNumber(bidRequest.adUnitCode, bidderRequest).toString(),
1013-
adunit_position: getSlotPosition(bidRequest.params.adUnitElementId) // adUnitElementId à déplacer ???
1014-
};
1015-
10161033
// Force the Split Keyword to be a String
10171034
if (bidRequest.params.splitKeyword) {
10181035
if (isStr(bidRequest.params.splitKeyword) || isNumber(bidRequest.params.splitKeyword)) {
@@ -1056,23 +1073,20 @@ export const spec = {
10561073
}
10571074
}
10581075

1059-
Object.keys(features).forEach((prop) => {
1060-
if (features[prop] === '') {
1061-
delete features[prop];
1062-
}
1063-
});
1064-
1076+
const features = _getFeatures(bidRequest);
10651077
bidRequest.features = features;
10661078

1067-
internal.enqueue({
1068-
action: 'features',
1069-
ts: Date.now(),
1070-
data: {
1071-
features: bidRequest.features,
1072-
params: bidRequest.params,
1073-
adUnitCode: bidRequest.adUnitCode
1074-
}
1075-
});
1079+
if (!hasRtd) {
1080+
internal.enqueue({
1081+
action: 'features',
1082+
ts: Date.now(),
1083+
data: {
1084+
features,
1085+
params: { ...bidRequest.params },
1086+
adUnitCode: bidRequest.adUnitCode
1087+
}
1088+
});
1089+
}
10761090

10771091
// Handle priceFloors module
10781092
// We need to use `rawBidRequest` as param because:
@@ -1127,8 +1141,10 @@ export const spec = {
11271141
bidRequest.gpid = gpid;
11281142
}
11291143

1130-
// store the whole bidRequest (adUnit) object in the ADAGIO namespace.
1131-
storeRequestInAdagioNS(bidRequest);
1144+
if (!hasRtd) {
1145+
// store the whole bidRequest (adUnit) object in the ADAGIO namespace.
1146+
storeRequestInAdagioNS(bidRequest);
1147+
}
11321148

11331149
// Remove some params that are not needed on the server side.
11341150
delete bidRequest.params.siteId;
@@ -1176,12 +1192,13 @@ export const spec = {
11761192
url: ENDPOINT,
11771193
data: {
11781194
organizationId: organizationId,
1195+
hasRtd: hasRtd ? 1 : 0,
11791196
secure: secure,
11801197
device: device,
11811198
site: site,
11821199
pageviewId: pageviewId,
11831200
adUnits: groupedAdUnits[organizationId],
1184-
data: GlobalExchange.getExchangeData(),
1201+
data: dataExchange,
11851202
regs: {
11861203
gdpr: gdprConsent,
11871204
coppa: coppa,

src/utils.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export const internal = {
4141
createTrackPixelIframeHtml,
4242
getWindowSelf,
4343
getWindowTop,
44+
canAccessWindowTop,
4445
getWindowLocation,
4546
insertUserSyncIframe,
4647
insertElement,
@@ -180,6 +181,16 @@ export function getWindowLocation() {
180181
return window.location;
181182
}
182183

184+
export function canAccessWindowTop() {
185+
try {
186+
if (internal.getWindowTop().location.href) {
187+
return true;
188+
}
189+
} catch (e) {
190+
return false;
191+
}
192+
}
193+
183194
/**
184195
* Wrappers to console.(log | info | warn | error). Takes N arguments, the same as the native methods
185196
*/
@@ -620,6 +631,18 @@ export function inIframe() {
620631
}
621632
}
622633

634+
/**
635+
* https://iabtechlab.com/wp-content/uploads/2016/03/SafeFrames_v1.1_final.pdf
636+
*/
637+
export function isSafeFrameWindow() {
638+
if (!inIframe()) {
639+
return false;
640+
}
641+
642+
const ws = internal.getWindowSelf();
643+
return !!(ws.$sf && ws.$sf.ext);
644+
}
645+
623646
export function isSafariBrowser() {
624647
return /^((?!chrome|android|crios|fxios).)*safari/i.test(navigator.userAgent);
625648
}

0 commit comments

Comments
 (0)