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
mustafakemal16 authored Jun 5, 2024
2 parents 8e25ed9 + 47e6561 commit 3ce1754
Show file tree
Hide file tree
Showing 44 changed files with 1,381 additions and 291 deletions.
8 changes: 4 additions & 4 deletions libraries/ortbConverter/lib/composer.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@ const SORTED = new WeakMap();

/**
*
* @param {Object[string, Component]} components to compose
* @param {Object[string, function|boolean]} overrides a map from component name, to a function that should override that component.
* @param {Object.<string, Component>} components - An object where keys are component names and values are components to compose.
* @param {Object.<string, (function|boolean)>} overrides - A map from component names to functions that should override those components.
* Override functions are replacements, except that they get the original function they are overriding as their first argument. If the override
* is `false`, the component is disabled.
*
* @return a function that will run all components in order of priority, with functions from `overrides` taking
* precedence over components that match names
* @return {function} - A function that will run all components in order of priority, with functions from `overrides` taking
* precedence over components that match names.
*/
export function compose(components, overrides = {}) {
if (!SORTED.has(components)) {
Expand Down
2 changes: 1 addition & 1 deletion libraries/video/constants/ortb.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/**
* @typedef {Object} OrtbParams
* @property {OrtbVideoParamst} video
* @property {OrtbVideoParams} video
* @property {OrtbContentParams} content
*/

Expand Down
64 changes: 43 additions & 21 deletions modules/33acrossIdSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { submodule } from '../src/hook.js';
import { uspDataHandler, coppaDataHandler, gppDataHandler } from '../src/adapterManager.js';
import { getStorageManager, STORAGE_TYPE_COOKIES, STORAGE_TYPE_LOCALSTORAGE } from '../src/storageManager.js';
import { MODULE_TYPE_UID } from '../src/activities/modules.js';
import { domainOverrideToRootDomain } from '../libraries/domainOverrideToRootDomain/index.js';

/**
* @typedef {import('../modules/userId/index.js').Submodule} Submodule
Expand All @@ -28,6 +29,10 @@ const STORAGE_FPID_KEY = '33acrossIdFp';

export const storage = getStorageManager({ moduleType: MODULE_TYPE_UID, moduleName: MODULE_NAME });

export const domainUtils = {
domainOverride: domainOverrideToRootDomain(storage, MODULE_NAME)
};

function calculateResponseObj(response) {
if (!response.succeeded) {
if (response.error == 'Cookied User') {
Expand All @@ -50,7 +55,7 @@ function calculateResponseObj(response) {
};
}

function calculateQueryStringParams(pid, gdprConsentData, storageConfig) {
function calculateQueryStringParams(pid, gdprConsentData, enabledStorageTypes) {
const uspString = uspDataHandler.getConsentData();
const coppaValue = coppaDataHandler.getCoppa();
const gppConsent = gppDataHandler.getConsentData();
Expand Down Expand Up @@ -78,7 +83,7 @@ function calculateQueryStringParams(pid, gdprConsentData, storageConfig) {
params.gdpr_consent = gdprConsentData.consentString;
}

const fp = getStoredValue(STORAGE_FPID_KEY, storageConfig);
const fp = getStoredValue(STORAGE_FPID_KEY, enabledStorageTypes);
if (fp) {
params.fp = encodeURIComponent(fp);
}
Expand All @@ -90,32 +95,42 @@ function deleteFromStorage(key) {
if (storage.cookiesAreEnabled()) {
const expiredDate = new Date(0).toUTCString();

storage.setCookie(key, '', expiredDate, 'Lax');
storage.setCookie(key, '', expiredDate, 'Lax', domainUtils.domainOverride());
}

storage.removeDataFromLocalStorage(key);
}

function storeValue(key, value, storageConfig = {}) {
if (storageConfig.type === STORAGE_TYPE_COOKIES && storage.cookiesAreEnabled()) {
const expirationInMs = 60 * 60 * 24 * 1000 * storageConfig.expires;
const expirationTime = new Date(Date.now() + expirationInMs);
function storeValue(key, value, { enabledStorageTypes, expires }) {
enabledStorageTypes.forEach(storageType => {
if (storageType === STORAGE_TYPE_COOKIES) {
const expirationInMs = 60 * 60 * 24 * 1000 * expires;
const expirationTime = new Date(Date.now() + expirationInMs);

storage.setCookie(key, value, expirationTime.toUTCString(), 'Lax');
} else if (storageConfig.type === STORAGE_TYPE_LOCALSTORAGE) {
storage.setDataInLocalStorage(key, value);
}
storage.setCookie(key, value, expirationTime.toUTCString(), 'Lax', domainUtils.domainOverride());
} else if (storageType === STORAGE_TYPE_LOCALSTORAGE) {
storage.setDataInLocalStorage(key, value);
}
});
}

function getStoredValue(key, storageConfig = {}) {
if (storageConfig.type === STORAGE_TYPE_COOKIES && storage.cookiesAreEnabled()) {
return storage.getCookie(key);
} else if (storageConfig.type === STORAGE_TYPE_LOCALSTORAGE) {
return storage.getDataFromLocalStorage(key);
}
function getStoredValue(key, enabledStorageTypes) {
let storedValue;

enabledStorageTypes.find(storageType => {
if (storageType === STORAGE_TYPE_COOKIES) {
storedValue = storage.getCookie(key);
} else if (storageType === STORAGE_TYPE_LOCALSTORAGE) {
storedValue = storage.getDataFromLocalStorage(key);
}

return !!storedValue;
});

return storedValue;
}

function handleFpId(fpId, storageConfig = {}) {
function handleFpId(fpId, storageConfig) {
fpId
? storeValue(STORAGE_FPID_KEY, fpId, storageConfig)
: deleteFromStorage(STORAGE_FPID_KEY);
Expand Down Expand Up @@ -151,7 +166,7 @@ export const thirthyThreeAcrossIdSubmodule = {
* @param {SubmoduleConfig} [config]
* @returns {IdResponse|undefined}
*/
getId({ params = { }, storage: storageConfig }, gdprConsentData) {
getId({ params = { }, enabledStorageTypes = [], storage: storageConfig }, gdprConsentData) {
if (typeof params.pid !== 'string') {
logError(`${MODULE_NAME}: Submodule requires a partner ID to be defined`);

Expand Down Expand Up @@ -183,7 +198,10 @@ export const thirthyThreeAcrossIdSubmodule = {
}

if (storeFpid) {
handleFpId(responseObj.fp, storageConfig);
handleFpId(responseObj.fp, {
enabledStorageTypes,
expires: storageConfig.expires
});
}

cb(responseObj.envelope);
Expand All @@ -193,10 +211,14 @@ export const thirthyThreeAcrossIdSubmodule = {

cb();
}
}, calculateQueryStringParams(pid, gdprConsentData, storageConfig), { method: 'GET', withCredentials: true });
}, calculateQueryStringParams(pid, gdprConsentData, enabledStorageTypes), {
method: 'GET',
withCredentials: true
});
}
};
},
domainOverride: domainUtils.domainOverride,
eids: {
'33acrossId': {
source: '33across.com',
Expand Down
4 changes: 2 additions & 2 deletions modules/33acrossIdSystem.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pbjs.setConfig({
name: "33acrossId",
storage: {
name: "33acrossId",
type: "html5",
type: "cookie&html5",
expires: 30,
refreshInSeconds: 8*3600
},
Expand All @@ -40,7 +40,7 @@ The following settings are available for the `storage` property in the `userSync
| Param name | Scope | Type | Description | Example |
| --- | --- | --- | --- | --- |
| name | Required | String| Name of the cookie or HTML5 local storage where the user ID will be stored | `"33acrossId"` |
| type | Required | String | `"html5"` (preferred) or `"cookie"` | `"html5"` |
| type | Required | String | `"cookie&html5"` (preferred) or `"cookie"` or `"html5"` | `"cookie&html5"` |
| expires | Strongly Recommended | Number | How long (in days) the user ID information will be stored. 33Across recommends `30`. | `30` |
| refreshInSeconds | Strongly Recommended | Number | The interval (in seconds) for refreshing the user ID. 33Across recommends no more than 8 hours between refreshes. | `8*3600` |

Expand Down
9 changes: 4 additions & 5 deletions modules/adpod.js
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,6 @@ export function callPrebidCacheAfterAuction(bids, callback) {
/**
* Compare function to be used in sorting long-form bids. This will compare bids on price per second.
* @param {Object} bid
* @param {Object} bid
*/
export function sortByPricePerSecond(a, b) {
if (a.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / a.video.durationBucket < b.adserverTargeting[TARGETING_KEYS.PRICE_BUCKET] / b.video.durationBucket) {
Expand All @@ -465,10 +464,10 @@ export function sortByPricePerSecond(a, b) {

/**
* This function returns targeting keyvalue pairs for long-form adserver modules. Freewheel and GAM are currently supporting Prebid long-form
* @param {Object} options
* @param {Array[string]} codes
* @param {function} callback
* @returns targeting kvs for adUnitCodes
* @param {Object} options - Options for targeting.
* @param {Array<string>} options.codes - Array of ad unit codes.
* @param {function} options.callback - Callback function to handle the targeting key-value pairs.
* @returns {Object} Targeting key-value pairs for ad unit codes.
*/
export function getTargeting({ codes, callback } = {}) {
if (!callback) {
Expand Down
10 changes: 7 additions & 3 deletions modules/consentManagement.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@ const cmpCallMap = {

/**
* This function reads the consent string from the config to obtain the consent information of the user.
* @param {function({})} onSuccess acts as a success callback when the value is read from config; pass along consentObject from CMP
* @param {Object} options - An object containing the callbacks.
* @param {function(Object): void} options.onSuccess - Acts as a success callback when the value is read from config; pass along consentObject from CMP.
* @param {function(string, ...Object?): void} [options.onError] - Acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging). Optional.
*/
function lookupStaticConsentData({onSuccess, onError}) {
processCmpData(staticConsentData, {onSuccess, onError})
Expand All @@ -45,8 +47,10 @@ function lookupStaticConsentData({onSuccess, onError}) {
* This function handles interacting with an IAB compliant CMP to obtain the consent information of the user.
* Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function
* based on the appropriate result.
* @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP
* @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging)
* @param {Object} options - An object containing the callbacks.
* @param {function(Object): void} options.onSuccess - Acts as a success callback when CMP returns a value; pass along consentObject from CMP.
* @param {function(string, ...Object?): void} options.onError - Acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging).
* @param {function(Object): void} options.onEvent - Acts as an event callback for processing TCF data events from CMP.
*/
function lookupIabConsent({onSuccess, onError, onEvent}) {
function cmpResponseCallback(tcfData, success) {
Expand Down
7 changes: 4 additions & 3 deletions modules/consentManagementGpp.js
Original file line number Diff line number Diff line change
Expand Up @@ -304,8 +304,10 @@ class GPP11Client extends GPPClient {
* This function handles interacting with an IAB compliant CMP to obtain the consent information of the user.
* Given the async nature of the CMP's API, we pass in acting success/error callback functions to exit this function
* based on the appropriate result.
* @param {function({})} onSuccess acts as a success callback when CMP returns a value; pass along consentObjectfrom CMP
* @param {function(string, ...{}?)} cmpError acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging)
* @param {Object} options - An object containing the callbacks.
* @param {function(Object): void} options.onSuccess - Acts as a success callback when CMP returns a value; pass along consentObject from CMP.
* @param {function(string, ...Object?): void} options.onError - Acts as an error callback while interacting with CMP; pass along an error message (string) and any extra error arguments (purely for logging).
* @param {function(): Object} [mkCmp=cmpClient] - A function to create the CMP client. Defaults to `cmpClient`.
*/
export function lookupIabConsent({onSuccess, onError}, mkCmp = cmpClient) {
pipeCallbacks(() => GPPClient.init(mkCmp).then(([client, gppDataPm]) => gppDataPm), {onSuccess, onError});
Expand Down Expand Up @@ -434,7 +436,6 @@ function processCmpData(consentData) {
/**
* Stores CMP data locally in module to make information available in adaptermanager.js for later in the auction
* @param {{}} gppData the result of calling a CMP's `getGPPData` (or equivalent)
* @param {{}} sectionData map from GPP section name to the result of calling a CMP's `getSection` (or equivalent)
*/
export function storeConsentData(gppData = {}) {
consentData = {
Expand Down
10 changes: 6 additions & 4 deletions modules/consentManagementUsp.js
Original file line number Diff line number Diff line change
Expand Up @@ -163,10 +163,12 @@ export const requestBidsHook = timedAuctionHook('usp', function requestBidsHook(
/**
* This function checks the consent data provided by USPAPI to ensure it's in an expected state.
* If it's bad, we exit the module depending on config settings.
* If it's good, then we store the value and exits the module.
* @param {object} consentObject required; object returned by USPAPI that contains user's consent choices
* @param {function(string)} onSuccess callback accepting the resolved consent USP consent string
* @param {function(string, ...{}?)} onError callback accepting error message and any extra error arguments (used purely for logging)
* If it's good, then we store the value and exit the module.
*
* @param {Object} consentObject - The object returned by USPAPI that contains the user's consent choices.
* @param {Object} callbacks - An object containing the callback functions.
* @param {function(string): void} callbacks.onSuccess - Callback accepting the resolved USP consent string.
* @param {function(string, ...Object?): void} callbacks.onError - Callback accepting an error message and any extra error arguments (used purely for logging).
*/
function processUspData(consentObject, {onSuccess, onError}) {
const valid = !!(consentObject && consentObject.usPrivacy);
Expand Down
1 change: 1 addition & 0 deletions modules/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export let responseReady = defer();

/**
* Configuration function for currency
* @param {object} config
* @param {string} [config.adServerCurrency = 'USD']
* ISO 4217 3-letter currency code that represents the target currency. (e.g. 'EUR'). If this value is present,
* the currency conversion feature is activated.
Expand Down
70 changes: 67 additions & 3 deletions modules/dailymotionBidAdapter.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,37 @@ function getVideoMetadata(bidRequest, bidderRequest) {
: Object.keys(parsedContentData.iabcat2),
id: videoParams.id || deepAccess(contentObj, 'id', ''),
lang: videoParams.lang || deepAccess(contentObj, 'language', ''),
livestream: typeof videoParams.livestream === 'number'
? !!videoParams.livestream
: !!deepAccess(contentObj, 'livestream', 0),
private: videoParams.private || false,
tags: videoParams.tags || deepAccess(contentObj, 'keywords', ''),
title: videoParams.title || deepAccess(contentObj, 'title', ''),
url: videoParams.url || deepAccess(contentObj, 'url', ''),
topics: videoParams.topics || '',
xid: videoParams.xid || '',
livestream: typeof videoParams.livestream === 'number'
? !!videoParams.livestream
: !!deepAccess(contentObj, 'livestream', 0),
isCreatedForKids: typeof videoParams.isCreatedForKids === 'boolean'
? videoParams.isCreatedForKids
: null,
context: {
siteOrAppCat: deepAccess(contentObj, 'cat', ''),
videoViewsInSession: (
typeof videoParams.videoViewsInSession === 'number' &&
videoParams.videoViewsInSession >= 0
)
? videoParams.videoViewsInSession
: null,
autoplay: typeof videoParams.autoplay === 'boolean'
? videoParams.autoplay
: null,
playerVolume: (
typeof videoParams.playerVolume === 'number' &&
videoParams.playerVolume >= 0 &&
videoParams.playerVolume <= 10
)
? videoParams.playerVolume
: null,
},
};

return videoMetadata;
Expand Down Expand Up @@ -111,6 +134,7 @@ export const spec = {
method: 'POST',
url: 'https://pb.dmxleo.com',
data: {
pbv: '$prebid.version$',
bidder_request: {
gdprConsent: {
apiVersion: deepAccess(bidderRequest, 'gdprConsent.apiVersion', 1),
Expand Down Expand Up @@ -139,6 +163,13 @@ export const spec = {
appBundle: deepAccess(bidderRequest, 'ortb2.app.bundle', ''),
appStoreUrl: deepAccess(bidderRequest, 'ortb2.app.storeurl', ''),
} : {}),
...(deepAccess(bidderRequest, 'ortb2.device') ? {
device: {
lmt: deepAccess(bidderRequest, 'ortb2.device.lmt', null),
ifa: deepAccess(bidderRequest, 'ortb2.device.ifa', ''),
atts: deepAccess(bidderRequest, 'ortb2.device.ext.atts', 0),
},
} : {}),
request: {
adUnitCode: deepAccess(bid, 'adUnitCode', ''),
auctionId: deepAccess(bid, 'auctionId', ''),
Expand All @@ -149,6 +180,8 @@ export const spec = {
mimes: bid.mediaTypes?.[VIDEO]?.mimes || [],
minduration: bid.mediaTypes?.[VIDEO]?.minduration || 0,
maxduration: bid.mediaTypes?.[VIDEO]?.maxduration || 0,
playbackmethod: bid.mediaTypes?.[VIDEO]?.playbackmethod || [],
plcmt: bid.mediaTypes?.[VIDEO]?.plcmt || 1, // Fallback to instream considering logic of `isBidRequestValid`
protocols: bid.mediaTypes?.[VIDEO]?.protocols || [],
skip: bid.mediaTypes?.[VIDEO]?.skip || 0,
skipafter: bid.mediaTypes?.[VIDEO]?.skipafter || 0,
Expand Down Expand Up @@ -177,6 +210,37 @@ export const spec = {
* @return {Bid[]} An array of bids which were nested inside the server.
*/
interpretResponse: serverResponse => serverResponse?.body ? [serverResponse.body] : [],

/**
* Retrieves user synchronization URLs based on provided options and consents.
*
* @param {object} syncOptions - Options for synchronization.
* @param {object[]} serverResponses - Array of server responses.
* @returns {object[]} - Array of synchronization URLs.
*/
getUserSyncs: (syncOptions, serverResponses) => {
if (!!serverResponses?.length && (syncOptions.iframeEnabled || syncOptions.pixelEnabled)) {
const iframeSyncs = [];
const pixelSyncs = [];

serverResponses.forEach((response) => {
(response.user_syncs || []).forEach((syncUrl) => {
if (syncUrl.type === 'image') {
pixelSyncs.push({ url: syncUrl.url, type: 'image' });
}

if (syncUrl.type === 'iframe') {
iframeSyncs.push({ url: syncUrl.url, type: 'iframe' });
}
});
});

if (syncOptions.iframeEnabled) return iframeSyncs;
return pixelSyncs;
}

return [];
},
};

registerBidder(spec);
Loading

0 comments on commit 3ce1754

Please sign in to comment.