Skip to content

Commit

Permalink
Merge branch 'prebid:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
DimaIntentIQ authored Nov 27, 2024
2 parents adbc56d + 36f60c1 commit 5648e7d
Show file tree
Hide file tree
Showing 115 changed files with 7,910 additions and 1,749 deletions.
114 changes: 114 additions & 0 deletions integrationExamples/gpt/rewardedInterestIdSystem_example.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
<!DOCTYPE html>
<html lang="en">

<head>
<title>Rewarded Interest ID Example</title>
<script>
const FAILSAFE_TIMEOUT = 2000;
const adUnits = [
{
code: 'test-div',
mediaTypes: {
banner: {
sizes: [[300, 250], [300, 600], [728, 90]]
},
},
bids: [
{
bidder: 'rubicon',
params: {
accountId: '1001',
siteId: '113932',
zoneId: '535510'
}
}
]
}
];
var pbjs = pbjs || {};
pbjs.que = pbjs.que || [];
</script>
<script src="../../build/dev/prebid.js" async></script>

<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
googletag.cmd.push(function () {
googletag.pubads().disableInitialLoad();
});

pbjs.que.push(function () {
pbjs.setConfig({
debug: true,
userSync: {
userIds: [
{
name: 'rewardedInterestId',
},
],
syncDelay: 5000,
auctionDelay: 1000,
}
});
pbjs.addAdUnits(adUnits);
pbjs.requestBids({
bidsBackHandler: sendAdserverRequest
});
});

function sendAdserverRequest() {
if (pbjs.adserverRequestSent) return;
pbjs.adserverRequestSent = true;
googletag.cmd.push(function () {
pbjs.que.push(function () {
pbjs.setTargetingForGPTAsync();
googletag.pubads().refresh();
});
});
}

setTimeout(function () {
sendAdserverRequest();
}, FAILSAFE_TIMEOUT);
</script>

<script>
(function () {
var gads = document.createElement('script');
gads.async = true;
gads.type = 'text/javascript';
gads.src = 'https://securepubads.g.doubleclick.net/tag/js/gpt.js';
var node = document.getElementsByTagName('script')[0];
node.parentNode.insertBefore(gads, node);
})();
</script>

<script>
googletag.cmd.push(function () {
googletag.defineSlot('/112115922/FL_PB_MedRect', [[300, 250], [300, 600], [728, 90]], 'test-div').addService(googletag.pubads());
googletag.pubads().enableSingleRequest();
googletag.enableServices();
});
</script>
</head>

<body>
<script>
pbjs.que.push(function () {
pbjs.getUserIdsAsync().then(ids => {
document.getElementById('ids-div').innerHTML = JSON.stringify(ids, null, ' ');
document.getElementById('eids-div').innerHTML = JSON.stringify(pbjs.getUserIdsAsEids(), null, ' ');
});
});
</script>

<h2>Rewarded Interest ID Example</h2>

<h4>Generated IDs:</h4>
<pre id="ids-div" style="border:1px solid #333; padding:5px; overflow: auto"></pre>

<h4>Generated EIDs</h4>
<pre id="eids-div" style="border:1px solid #333; padding:5px; overflow: auto"></pre>
</body>

</html>
78 changes: 78 additions & 0 deletions libraries/braveUtils/buildAndInterpret.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import { isEmpty, parseUrl } from '../../src/utils.js';
import {config} from '../../src/config.js';
import { createNativeRequest, createBannerRequest, createVideoRequest } from './index.js';
import { convertOrtbRequestToProprietaryNative } from '../../src/native.js';

export const buildRequests = (validBidRequests, bidderRequest, endpointURL, defaultCur) => {
validBidRequests = convertOrtbRequestToProprietaryNative(validBidRequests);
if (!validBidRequests.length || !bidderRequest) return [];

const endpoint = endpointURL.replace('hash', validBidRequests[0].params.placementId);
const imp = validBidRequests.map((br) => {
const impObject = { id: br.bidId, secure: 1 };
if (br.mediaTypes.banner) impObject.banner = createBannerRequest(br);
else if (br.mediaTypes.video) impObject.video = createVideoRequest(br);
else if (br.mediaTypes.native) impObject.native = { id: br.transactionId, ver: '1.2', request: createNativeRequest(br) };
return impObject;
});

const page = bidderRequest.refererInfo.page || bidderRequest.refererInfo.topmostLocation;
const data = {
id: bidderRequest.bidderRequestId,
cur: [defaultCur],
device: { w: screen.width, h: screen.height, language: navigator.language?.split('-')[0], ua: navigator.userAgent },
site: { domain: parseUrl(page).hostname, page: page },
tmax: bidderRequest.timeout,
imp,
};

if (bidderRequest.refererInfo.ref) data.site.ref = bidderRequest.refererInfo.ref;
if (bidderRequest.gdprConsent) {
data.regs = { ext: { gdpr: bidderRequest.gdprConsent.gdprApplies ? 1 : 0 } };
data.user = { ext: { consent: bidderRequest.gdprConsent.consentString || '' } };
}
if (bidderRequest.uspConsent) data.regs.ext.us_privacy = bidderRequest.uspConsent;
if (config.getConfig('coppa')) data.regs.coppa = 1;
if (validBidRequests[0].schain) data.source = { ext: { schain: validBidRequests[0].schain } };

return { method: 'POST', url: endpoint, data };
};

export const interpretResponse = (serverResponse, defaultCur, parseNative) => {
if (!serverResponse || isEmpty(serverResponse.body)) return [];

let bids = [];
serverResponse.body.seatbid.forEach(response => {
response.bid.forEach(bid => {
const mediaType = bid.ext?.mediaType || 'banner';

const bidObj = {
requestId: bid.impid,
cpm: bid.price,
width: bid.w,
height: bid.h,
ttl: 1200,
currency: defaultCur,
netRevenue: true,
creativeId: bid.crid,
dealId: bid.dealid || null,
mediaType,
};

switch (mediaType) {
case 'video':
bidObj.vastUrl = bid.adm;
break;
case 'native':
bidObj.native = parseNative(bid.adm);
break;
default:
bidObj.ad = bid.adm;
}

bids.push(bidObj);
});
});

return bids;
};
95 changes: 95 additions & 0 deletions libraries/braveUtils/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
import { NATIVE_ASSETS, NATIVE_ASSETS_IDS } from './nativeAssets.js';

/**
* Builds a native request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The native request object
*/
export function createNativeRequest(br) {
let impObject = {
ver: '1.2',
assets: []
};

Object.keys(br.mediaTypes.native).forEach((key) => {
const props = NATIVE_ASSETS[key];
if (props) {
const asset = {
required: br.mediaTypes.native[key].required ? 1 : 0,
id: props.id,
[props.name]: {}
};

if (props.type) asset[props.name]['type'] = props.type;
if (br.mediaTypes.native[key].len) asset[props.name]['len'] = br.mediaTypes.native[key].len;
if (br.mediaTypes.native[key].sizes && br.mediaTypes.native[key].sizes[0]) {
asset[props.name]['w'] = br.mediaTypes.native[key].sizes[0];
asset[props.name]['h'] = br.mediaTypes.native[key].sizes[1];
}

impObject.assets.push(asset);
}
});

return impObject;
}

/**
* Builds a banner request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The banner request object
*/
export function createBannerRequest(br) {
let size = br.mediaTypes.banner.sizes?.[0] || [300, 250];
return { id: br.transactionId, w: size[0], h: size[1] };
}

/**
* Builds a video request object based on the bid request
* @param {object} br - The bid request
* @returns {object} The video request object
*/
export function createVideoRequest(br) {
let videoObj = { id: br.transactionId };
const supportedParams = ['mimes', 'minduration', 'maxduration', 'protocols', 'startdelay', 'skip', 'minbitrate', 'maxbitrate', 'api', 'linearity'];

supportedParams.forEach((param) => {
if (br.mediaTypes.video[param] !== undefined) {
videoObj[param] = br.mediaTypes.video[param];
}
});

const playerSize = br.mediaTypes.video.playerSize;
if (playerSize) {
videoObj.w = Array.isArray(playerSize[0]) ? playerSize[0][0] : playerSize[0];
videoObj.h = Array.isArray(playerSize[0]) ? playerSize[0][1] : playerSize[1];
} else {
videoObj.w = 640;
videoObj.h = 480;
}

return videoObj;
}

/**
* Parses the native ad response
* @param {object} adm - The native ad response
* @returns {object} Parsed native ad object
*/
export function parseNative(adm) {
let bid = {
clickUrl: adm.native.link?.url,
impressionTrackers: adm.native.imptrackers || [],
clickTrackers: adm.native.link?.clicktrackers || [],
jstracker: adm.native.jstracker || []
};
adm.native.assets.forEach((asset) => {
const kind = NATIVE_ASSETS_IDS[asset.id];
const content = kind && asset[NATIVE_ASSETS[kind].name];
if (content) {
bid[kind] = content.text || content.value || { url: content.url, width: content.w, height: content.h };
}
});

return bid;
}
23 changes: 23 additions & 0 deletions libraries/braveUtils/nativeAssets.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* IDs and asset types for native ad assets.
*/
export const NATIVE_ASSETS_IDS = {
1: 'title',
2: 'icon',
3: 'image',
4: 'body',
5: 'sponsoredBy',
6: 'cta'
};

/**
* Native assets definition for mapping purposes.
*/
export const NATIVE_ASSETS = {
title: { id: 1, name: 'title' },
icon: { id: 2, type: 1, name: 'img' },
image: { id: 3, type: 3, name: 'img' },
body: { id: 4, type: 2, name: 'data' },
sponsoredBy: { id: 5, type: 1, name: 'data' },
cta: { id: 6, type: 12, name: 'data' }
};
2 changes: 1 addition & 1 deletion libraries/intentIqConstants/intentIqConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ export const OPT_OUT = 'O';
export const BLACK_LIST = 'L';
export const CLIENT_HINTS_KEY = '_iiq_ch';
export const EMPTY = 'EMPTY'
export const VERSION = 0.21
export const VERSION = 0.22
64 changes: 64 additions & 0 deletions libraries/intentIqUtils/getRefferer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { getWindowTop, logError, getWindowLocation, getWindowSelf } from '../../src/utils.js';

/**
* Determines if the script is running inside an iframe and retrieves the URL.
* @return {string} The encoded vrref value representing the relevant URL.
*/
export function getReferrer() {
try {
if (getWindowSelf() === getWindowTop()) {
return encodeURIComponent(getWindowLocation().href);
} else {
return encodeURIComponent(getWindowTop().location.href);
}
} catch (error) {
logError(`Error accessing location: ${error}`);
return '';
}
}

/**
* Appends `vrref` and `fui` parameters to the provided URL.
* If the referrer URL is available, it appends `vrref` with the relevant referrer value based on the domain.
* Otherwise, it appends `fui=1`. If a domain name is provided, it may also append `vrref` with the domain.
* @param {string} url - The URL to append parameters to.
* @param {string} domainName - The domain name used to determine the relevant referrer.
* @return {string} The modified URL with appended `vrref` or `fui` parameters.
*/
export function appendVrrefAndFui(url, domainName) {
const fullUrl = getReferrer();
if (fullUrl) {
return (url += '&vrref=' + getRelevantRefferer(domainName, fullUrl));
}
url += '&fui=1'; // Full Url Issue
url += '&vrref=' + encodeURIComponent(domainName || '');
return url;
}

/**
* Get the relevant referrer based on full URL and domain
* @param {string} domainName The domain name to compare
* @param {string} fullUrl The full URL to analyze
* @return {string} The relevant referrer
*/
export function getRelevantRefferer(domainName, fullUrl) {
if (domainName && isDomainIncluded(fullUrl, domainName)) {
return fullUrl;
}
return domainName ? encodeURIComponent(domainName) : fullUrl;
}

/**
* Checks if the provided domain name is included in the full URL.
* @param {string} fullUrl - The full URL to check.
* @param {string} domainName - The domain name to search for within the URL.
* @return {boolean} `True` if the domain name is found in the URL, `false` otherwise.
*/
export function isDomainIncluded(fullUrl, domainName) {
try {
return fullUrl.includes(domainName);
} catch (error) {
logError(`Invalid URL provided: ${error}`);
return false;
}
}
Loading

0 comments on commit 5648e7d

Please sign in to comment.